Kitsune2: Ricerca più veloce di 251x, percorso di aggiornamento 33x, e gossip iniziato 15x prima
In una mattina di esperimenti sul livello di rete di Holochain: come i nodi trovano i peer, recuperano i dati mancanti e riprendono il gossip, e cosa 6 piccoli patch hanno cambiato lungo il percorso.
Developed by Robert E. Beckner III (Merlin) | rbeckner.com
Sono stato sveglio intorno alle 4:30 a.m. ultimamente, appena prima dell'alba, e lo sto godendo. Il 19 settembre ho usato quella mattina per avviare un laboratorio su Kitsune2, il livello di rete peer-to-peer sotto Holochain, e sono andato a cercare dove stesse spendendo tempo.Alle 12:20 p.m., il laboratorio aveva prodotto 6 patch. Ricerca di endpoint: 251× più veloce a 10,000 identità mantenute. Il percorso di aggiornamento peer che li chiama: 33× più veloce. Inizio del gossip dopo un fetch completato: 3,002 ms a 202 ms. Traffico di richieste burst: 96.9% meno messaggi. 3 dei cambiamenti riparati lavoravano che aspettavano inutilmente, o aspettavano qualcosa che non accadrà mai.Ho codificato per più di 25 anni e costruito con AI da GPT-3. Lo uso per isolare qualcosa che mi interessa o che non capisco ancora, lavorarci sopra e testare ciò che pensiamo di aver imparato. Mi piace quella parte: trasformare una domanda in un esperimento e vedere cosa rimane. Questa mattina, con agenti di coding AI, ho applicato quell'approccio alla macchina che permette ai nodi Holochain di tenersi aggiornati l'un l'altro.Le applicazioni Holochain condividono dati tra computer partecipanti, o nodes. Ogni partecipante mantiene la propria cronologia firmata e aiuta a validare e memorizzare una porzione dei dati condivisi dell'applicazione. Quegli store condivisi sono la distributed hash table, o DHT. Le copie vivono con diversi peer, quindi i dati possono rimanere disponibili quando il loro autore si disconnette. Holochain's DHT guide spiega come quelle responsabilità siano distribuite.Kitsune2 gestisce la comunicazione peer-to-peer sottostante. Immagina un nodo che si mette al passo: impara dove possono essere raggiunti i peer, confronta ciò che possiede con ciò che hanno, e richiede i pezzi che gli mancano. Gossip è lo scambio attraverso il quale i peer scoprono quelle differenze; fetch recupera le operazioni mancanti, le unità di dati che Kitsune2 trasferisce. Il nodo ricevente le consegna allo store delle operazioni dell’host. Holochain gestisce la loro validazione e integrazione.Diagram source
graph TD
A[Impara le identità e gli endpoint dei peer] --> B[Confronta i dati tramite gossip]
B --> C[Identifica le operazioni mancanti]
C --> D[Recupera le operazioni dai peer]
D --> E[Consegnare le operazioni ricevute allo store dell’host]
E --> F[Segnala che i fetch in sospeso sono completati]
F e1@--> B
e1@{ animation: fast }
Copy sourceLe patch si trovano lungo quella sequenza. Alcune riducono il lavoro che un nodo deve fare; altre lo lasciano andare avanti quando il lavoro è già terminato. Le figure sopra misurano quei passaggi particolari su nodi di test locali.
Cosa hanno effettivamente spostato ciascuna delle modifiche 6#
Abbiamo fissato il punto di partenza al commit upstream 06555ee, sorgente di sviluppo 0.6.0-dev.1. Ogni confronto utilizza quella base più la sequenza di patch registrata. Le etichette qui sotto collegano i risultati alle nostre registrazioni sperimentali; tutte le patch 6 sono ora inviate per la revisione upstream.
Etichetta
Cosa è cambiato
Risultato misurato
K3a
Chiama l’helper di drenaggio esistente quando un fetch termina
Inizio di gossip dopo un fetch completato: 3,002 → 202 ms
K3b
Lock del ricevitore limitato al dequeue
Concorrenza effettiva era 1. I worker configurati ora si sovrappongono realmente
K3c
Proprietà di ammissione contrassegnata dalla generazione
Strada dei chiamanti cancellata 0 chiavi in attesa. Baseline in stato di stallo 8
K3d-P1
Pulizia della risposta basata su set
1.9–6.1× elaborazione della risposta più veloce a carichi di attesa elevati
K3d-P2
Attivazione del batching tra pari (predefinito 1)
Picchi: 87.5–96.9% messaggi di richiesta in meno
K1
Inverti URL all’indice dell’agente
A 10,000 identità mantenute: aggiornamenti 21–33×, ricerche 118–251× più veloci, per 3.10× memoria dello store
La prima riparazione ricollega il completamento del recupero alla task di gossip in attesa di esso. Il cambiamento chiama un helper esistente che informa gli ascoltatori che la mappa in attesa è vuota. Abbiamo testato sia un recupero completato sia un recupero deliberatamente mantenuto aperto.
Gossip initiation after a fetch completes, with the control that must not move (ms)Chart data
milliseconds
Upstream 06555ee
With the drain notification restored
Fetch completed
3001
202
Fetch still pending (control)
3002
3001
Dopo il completamento, il gossip può procedere. Mentre il recupero rimane in attesa, entrambe le versioni raggiungono ancora il timer di fallback. Il test isolato sopra ha misurato 3,001 → 202 ms; il successivo replay combinato ha misurato 3,002 → 202 ms. Entrambi hanno usato un fallback di 3,000 ms e un ritardo iniziale di 200 ms. La differenza di circa 15× registra quale percorso ha seguito il task: attendere il fallback o svegliarsi al completamento.
Ogni cambiamento vive in un crate, e 5 dei 6 in un singolo file#
Un crate Rust è un pacchetto di codice. Tutte le patch 6 vivono nel core crate, che contiene i peer records e la fetch machinery. Cambiano il modo in cui gossip ottiene i suoi dati e segnali di completamento senza modificare l'algoritmo gossip o il trasporto di rete sottostante. Il batching aggiunge un campo di configurazione core opzionale.
Etichetta
File
Linee
K1
core/src/factories/core_known_peers.rs
+33 / −10
K3a
core/src/factories/core_fetch.rs
+1
K3b
core/src/factories/core_fetch.rs
+11 / −3
K3c
core/src/factories/core_fetch.rs
+71 / −53
K3d-P1
core/src/factories/core_fetch.rs
+6 / −1
K3d-P2
core/src/factories/core_fetch.rs, 1 file di test
+89 / −17
5 patch impilati in un ordine registrato su core_fetch.rs, che richiede operazioni mancanti e elabora risposte. Il patch rimanente sta in core_known_peers.rs, il record mantenuto di quale identità è associata a quale endpoint di rete. Abbiamo quindi applicato tutti 6 a un singolo albero sorgente e li abbiamo eseguiti insieme.
I dati erano arrivati, ma gossip stava ancora aspettando#
CoreFetch mantiene una mappa delle operazioni che ha richiesto e da chi. Quando la risposta di un peer arriva e le operazioni sono memorizzate con successo, il codice rimuove quegli identificatori dalla mappa. Altri parti del file, il send-error path e il peer-cleanup path, chiamano un helper chiamato notify_listeners_if_queue_drained subito dopo aver rimosso le voci. Il success path non lo chiama mai.Un nodo può espandere la porzione del DHT che memorizza, chiamata storage arc. Per fare ciò, deve recuperare i dati all'interno dell'intervallo più ampio. Nel arc-growth path che abbiamo testato, gossip aspetta che le fetch in sospeso finiscano prima di iniziare con un peer, con un timer come fallback. I dati sono arrivati e la mappa in attesa è stata svuotata, ma il task che attendeva quel segnale è rimasto addormentato finché il timer non è scaduto.Diagram source
sequenceDiagram
participant G as Gossip arc-growth loop
participant F as CoreFetch
participant P as Peer
G->>F: Register a drain waiter
P->>F: Final response, operations stored
F->>F: retain() empties the pending map
Note over F: helper exists, never called
F--xG: Notification that never arrives
G->>G: Initiate after the roughly 3-second fallback
Copy sourceVerificare dopo il completamento nasconde la differenza: un nuovo waiter registrato vede la mappa vuota e ritorna immediatamente. Abbiamo registrato il nostro prima della conclusione. Una volta che i dati sono stati memorizzati, quel waiter non aveva ancora una notifica sul codice originale; con il patch, ne ha ricevuto una. Questo ripara il passaggio tra la ricezione dei dati e l’avvio del prossimo scambio di gossip.Abbiamo anche verificato risposte parziali, errori di memorizzazione, diversi ascoltatori, e ascoltatori che si registravano come richieste completate o nuovo lavoro arrivato. Una risposta parziale deve lasciare il waiter in sospeso; solo completando l’ultimo fetch in sospeso dovrebbe svegliarlo.
5 workers erano configurati, e 1 stava effettivamente inviando#
Il lato in uscita di CoreFetch esegue un numero configurato di task worker che prelevano da un unico canale condiviso. Il ciclo è stato scritto così:rustCopy source
while let Some(..) = outgoing_request_rx.lock().await.recv().await { // send the request}
Il lock permette al worker 1 di prendere la prossima richiesta dalla coda condivisa. Ma Rust mantiene quel guardiano di lock temporaneo vivo attraverso il corpo di questo while let, incluso l'attesa per l'invio di rete. Mentre il worker 1 inviava, l'altro 4 non poteva nemmeno raccogliere la loro prossima richiesta. Tutte le richieste potevano comunque arrivare in seguito, quindi un test di consegna poteva superare mentre la concorrenza configurata non era usata.Abbiamo spostato la ricezione in un blocco breve così che il lock venga rilasciato prima che inizi l'invio. I workers continuano a prendere turni per raccogliere richieste, poi le inviano contemporaneamente. Un invio lento non detiene più il lock della coda mentre altri workers hanno richieste pronte.
Outgoing sends in flight at the same moment, by configured worker countChart data
concurrent sends observed
Upstream 06555ee
Dequeue-scoped guard
1 worker
1
1
2 workers
1
2
5 workers
1
5
La misurazione mantiene ogni invio aperto con un orologio in pausa e conta quante sono entrate prima che una venga rilasciata, poi conferma che nulla entri oltre il limite configurato.
Annullare un chiamante lasciava il nodo in attesa di operazioni non inviate di 8#
Una richiesta di recupero passa attraverso i record di 2: la mappa in attesa indica ciò che il nodo sta aspettando, e la coda in uscita contiene lavoro per i lavoratori di invio. request_ops, il metodo che richiede operazioni, aggiungeva un intero lotto alla mappa in attesa prima di attendere spazio in quella coda.Se il chiamante è stato annullato mentre aspettava capacità, alcune operazioni erano già state marcate come in attesa anche se nessun lavoratore le aveva ricevute. Abbiamo riempito la coda, annullato un chiamante bloccato, e lasciato che tutte le richieste 16,385 ammesse finissero. Le operazioni 8 rimanevano in attesa. Non erano mai entrate nella coda in uscita, quindi non c’era risposta sul suo cammino per cancellarle.Ciò si collega direttamente alla prima riparazione: una notifica di completamento non può scattare mentre la mappa contiene ancora lavoro non finito. Qui, la contabilità propria del nodo lo stava facendo attendere.Il patch riserva prima la capacità della coda, poi registra e mette in coda l’operazione senza un altro await tra questi passaggi. Ogni voce porta anche un tag di generazione, quindi la pulizia di un invio fallito più vecchio non può cancellare una richiesta più recente per la stessa operazione. Il lavoro già ammissibile sopravvive all’annullamento del chiamante; il lavoro ancora in attesa di ammissione non lascia alcuna voce in attesa dietro.Ciò ripara la proprietà delle richieste. I limiti di memoria totali rimangono una questione di design separata, poiché un chiamante può ancora fornire un lotto grande.
Meno messaggi di richiesta, con un limite su quanto grande può diventare ciascuno#
Un nodo di recupero potrebbe aver bisogno di molte operazioni dallo stesso peer. Il formato di richiesta di Kitsune2 supporta già un elenco di identificatori, ma il codice in uscita invia 1 per messaggio. Prima di combinare quelle richieste, abbiamo verificato come sarebbero gestite risposte più grandi.Per ogni operazione in sospeso, la pulizia della risposta scansionava l’elenco degli identificatori restituiti per vedere se poteva rimuovere quell’entrata. Con 8,192 voci in sospeso e 1,024 identificatori restituiti, ciò ripete una grande quantità di ricerca. Costruire un HashSet degli identificatori restituiti rende ogni verifica di appartenenza economica; l’elaborazione della risposta è risultata 6.1× più veloce in quel caso. Con solo 16 identificatori restituiti, lo stoccaggio dei dati dominava e il cambiamento apportava poco.Poi abbiamo combinato le richieste pronte per lo stesso peer. In un burst di 64 piccole operazioni, le dimensioni del batch di 8 e 32 hanno ridotto i messaggi di richiesta di 87.5% e 96.9%, rispettivamente.
Burst behaviour relative to the default batch size of 1 (percent of control)Chart data
percent of control
Request messages
Elapsed time
Batch 1 (control)
100
105.4
Batch 8
12.5
72.6
Batch 32
3.1
67.7
Il burst è terminato circa 27–32% prima. Le stesse operazioni dovevano ancora essere trasferite e memorizzate; il risparmio era in quante richieste le trasportavano. Il controllo batch-1 ha misurato 105.4% del tempo trascorso di base, mostrando un drift temporale di circa 5% anche con il batching inattivo.Un worker combina solo le richieste già pronte, quindi una singola richiesta non aspetta mai che un batch si riempia. Il suddivisione del batch utilizza sia un limite di identificatori configurato sia una soglia di richiesta codificata in 4,096-byte. Contare gli elementi da solo non limita la loro dimensione totale; il test con 200 identificatori li divide in diversi messaggi limitati. Un singolo identificatore viene ancora inviato se da solo supera quella soglia, quindi questo non è un limite universale di dimensione del filo. Le risposte trasportano i dati effettivi e avrebbero bisogno di un limite di dimensione separato sul nodo che risponde.Il candidato mantiene la dimensione del batch 1 come predefinita e accetta le configurazioni esistenti senza modifiche. Abbiamo lasciato i batch più grandi come opt-in perché il test separato per una singola richiesta ha prodotto risultati di latenza finale incoerenti, coperti di seguito.
Rimuovere la scansione dal percorso di aggiornamento è stato utile di 33×, e 251× sul lookup stesso#
CoreKnownPeers ricorda identità e gli endpoint di rete associati a esse. Diverse identità possono condividere un endpoint, e un'identità bloccata deve comunque essere identificabile dopo essere stata rimossa dallo store peer attivo. 10,000 identità mantenute quindi significa una storia di identità in questo store, non 10,000 computer connessi contemporaneamente.Su un aggiornamento dello store peer, il controllo degli accessi chiede quali identità appartengono all'endpoint. Il lookup, get_by_url, scansionava l'intera mappa mantenuta sotto un lock ogni volta. Man mano che quella storia cresceva, l'aggiornamento delle informazioni peer correnti diventava più costoso.Abbiamo aggiunto un indice dall'endpoint URL alle identità associate ad esso: HashMap<Url, HashSet<AgentId>>. I record originali rimangono autorevoli. Quando un'identità cambia endpoint, l'indice la sposta al set corrispondente; il lookup può quindi andare direttamente a quel set. Entrambe le versioni hanno superato i controlli di risultato 19,422 coprendo aggiornamenti, pubblicità stale, rimozioni e endpoint condivisi.
Microseconds per 16-advertisement update call (log scale)Chart data
microseconds per update call
retained identities
Upstream linear scan
Derived URL index
100
6.857
4.911
1,000
18.103
4.774
10,000
154.849
4.72
Ogni chiamata temporizzata sopra inserisce 16 pubblicità e esegue i listener di controllo degli accessi. A 10,000 identità mantenute, è sceso da circa 155 µs a 4.72 µs, un guadagno pari a 33× accoppiato. La versione indicizzata rimane quasi piatta su queste dimensioni perché quei listener non scansionano più la storia in crescita.Misurato a API invece che attraverso il caller, il lookup stesso passa da una scansione a un hash. Un miss a 10,000 identità mantenute è sceso da 11,423 ns a 45 ns, un guadagno pari a 251×, e un singolo hit da 9,309 ns a 79 ns, 118×. Una query che restituisce molte identità continua a scalare con ciò che restituisce, quindi il caso shared-URL guadagna 4.4× anziché 2 ordini di grandezza. Il 251× è il risultato di lookup isolato. Il 33× misura la chiamata di aggiornamento più grande che lo utilizza; questi guadagni non possono essere aggiunti o moltiplicati.
Requested store memory at 10,000 retained identities, by endpoint shapeChart data
megabytes
Upstream
With the index
Mixed endpoints
1.2
3.71
All shared
1.2
1.74
All URL-less
1.2
1.2
3.10× in un negozio misto, un extra 2.51 MB a 10,000 identità. Dove ogni identità condivide un endpoint la mappa derivata è piccola e il costo scende a 1.45×. Dove nessuna identità ha un URL non c'è nulla da derivare e il costo è zero. Quei numeri sono byte richiesti dall'allocatore per lo store mantenuto, non la memoria totale del nodo.
Con tutti i patch 6 insieme, il nodo potrebbe terminare e continuare#
Il replay combinato ha usato i componenti real gossip, fetch, peer-access e memory-store di Kitsune2, comunicando tramite il suo test transport in-memory. Abbiamo eseguito una sequenza a 5-step sugli alberi di origine e patchati:
Aggiorna le informazioni del peer. Un'identità cambia endpoint. Le informazioni obsolete che arrivano più tardi lasciano intatto il record più recente, e un'identità bloccata rimane risolvibile per il controllo degli accessi. Entrambe le versioni passano; l'indice preserva le decisioni esistenti.
Avvia gossip dopo che un fetch è completato. Il nodo patchato avvia dopo 202 ms. L'originale prende il percorso di fallback a 3,002 ms.
Ricevi dati fuori ordine. Le operazioni richieste da 3 arrivano come risposte 4, inclusa una duplicata. Entrambe le versioni le memorizzano in modo coerente e associano i conteggi di byte all'operazione corretta.
Termina il fetch. Le operazioni memorizzate possono essere recuperate. Il nodo patchato sveglia anche il listener che si è registrato mentre quelle operazioni erano in attesa.
Continua dopo un peer fallito. Un fallimento controllato di invio cancella lo stato della richiesta di quel peer. Un altro peer fornisce l'operazione, la mappa in attesa si svuota, e un fetch successivo riesce. Nell'originale, i controlli di notifica di completamento falliscono.
Test di interazione separati hanno combinato cancellazione con invii concorrenti e batching combinato con notifica di completamento. Le riparazioni sono rimaste insieme: lavoro ammesso completato, ammissioni cancellate non hanno lasciato voci orfane, e i listener si sono svegliati dopo la risposta finale.Questo ci porta finché i dati ricevuti sono nel store host e il passo di networking successivo può procedere. La validazione e l'integrazione di Holochain seguono ancora l'esterno di questo laboratorio. Non abbiamo ancora misurato quanto queste modifiche riducano il tempo di catch-up completo di un nodo reale.
L'indice consuma memoria e rende i cambi di endpoint più costosi. Nel test originale di piccola banca, l'aggiornamento di un set fisso di identità a nuovi URL girava a 0.946× la velocità di base con 100 identità mantenute. A 10,000, un'operazione isolata di cambio endpoint costava 3.68× tanto. Mantenere l'indice extra ha un prezzo; i risparmi di lookup devono ripagarlo.Poiché quel compromesso è reale, abbiamo cercato il carico di lavoro in cui l'indice perde. 36 configurazioni erano predeclarate prima della misurazione, 432 eseguiti le esecuzioni accoppiate, e le trascrizioni dei risultati hashate identicamente tra le varianti.
Paired speedup across the 36-config workload envelope, by mix (log scale)Chart data
paired speedup
retained identities
Steady, no rebind
100% rebind
Shared endpoints
URL-less heavy
100
1.61
1.47
1.42
1.09
1,000
7.2
6.26
4.12
2.13
10,000
55.56
36.42
5.55
12.16
Reference line, parity: 1
Ogni carico di lavoro in questa matrice più ampia aveva una mediana sopra la parità, incluso il mix in cui ogni aggiornamento accettato cambiava un endpoint: 1.47× a 100 identità e 36.42× a 10,000. Quei aggiornamenti innescavano anche lookup di controllo accessi, e i loro risparmi superavano le scritture aggiuntive. Questo carico di lavoro più ampio differisce dal test a set fisso precedente; il risultato positivo lascia quel regressione di piccola banca sul registro.Il caso di 100 identità, per lo più URL-meno rimane inconclusivo: la sua mediana 1.09× includeva un risultato a coppia sotto la parità. Abbiamo ancora bisogno di tracce da nodi reali che mostrino i conteggi di identità mantenute, i cambi di endpoint e la frequenza di lookup prima di raccomandare l'indice per un carico di lavoro particolare.L'invio concorrente ha esposto un'interazione di pulizia. Una volta che i lavoratori potevano sovrapporsi, la pulizia per un invio fallito poteva girare mentre un'altra richiesta allo stesso peer era in transito. Ciò ha reso la pulizia a livello di peer più ampia del lavoro che era fallito. Il patch di proprietà ha restringito la rimozione alle voci ancora appartenenti a quella generazione di richiesta. Testare i patch insieme ha avuto importanza qui.La latenza di singola richiesta del batching rimane inconclusiva. Abbiamo misurato p95, il tempo entro cui 95% delle richieste finiscono. Per una richiesta inviata da sola, l'ultima esecuzione del lavoratore mostrava 1.01–1.08× la base p95; la rielaborazione indipendente mostrava 1.44–1.58×. Queste configurazioni richiedono decine di microsecondi, e i loro controlli anch'essi si sono deviatati. Il miglioramento di picco si è riprodotto, ma il risultato di singola richiesta non si è stabilizzato, quindi i batch più grandi rimangono opt-in.
Confronti ripetuti e invii bloccati rimangono aperti#
Abbiamo anche esaminato 2 altre parti della stessa sequenza di recupero. Nessuno ha prodotto un patch accettato.Confrontare ciò che i peer già detengono (K4). Gossip utilizza riepiloghi compatti dei dati memorizzati per trovare differenze. Nel test più grande, produrre e confrontare uno snapshot invariato ha materializzato 262,144 hash; ripetendolo 10 volte ha prodotto l'output identico ogni volta. Riutilizzare un riepilogo precedente sembra allettante, ma lo store host può cambiare senza un segnale affidabile per invalidare quel risultato salvato. Un riepilogo memorizzato in cache potrebbe quindi nascondere una differenza tra i peer. Le alternative che abbiamo valutato sono state anch'esse insufficienti rispetto al risparmio di tempo richiesto 20% sullo store in memoria. Le misurazioni da un vero store Holochain sono il prossimo pezzo mancante.Recuperare quando un invio gossip si blocca (K2). Leggere la sorgente ha sollevato una domanda su un invio che detiene un lock che l'attività di timeout necessita anche essa. Abbiamo anche dovuto stabilire cosa succede allo stream di trasporto Iroh sottostante se quell'invio viene annullato a metà. Il provider dell'agente ha bloccato il lavoro sul driver di riproduzione, quindi il test di runtime non è mai stato completato. Questo rimane un problema non testato, senza patch o risultato di affidabilità.
Ciò che abbiamo misurato, e ciò che resta da misurare#
Questi esperimenti sono stati eseguiti sul codice di sviluppo 0.6.0-dev.1, su 1 Apple M4 Max condiviso con 16 core logici. Abbiamo usato nodi di test locali e trasporti in memoria, senza pinning del core o un secondo host fisico. I risultati coprono componenti nominati e le loro interazioni. Il throughput di rete, la convergenza di rete intera, la memoria totale del nodo e la latenza dell'applicazione Holochain rimangono non misurati.Il metodo segue il mio lavoro su benchmark-driven development. Abbiamo registrato ogni domanda e soglia di accettazione, mantenuto il source e le fixture fissi in ogni confronto, e conservato comandi, campioni e fallimenti in ricevute append-only.Per le 3 riparazioni, gli stessi test sono falliti sul codice originale alle asserzioni previste e sono passati con il patch. Per le ottimizzazioni, entrambe le versioni dovevano preservare il comportamento, poi le misurazioni dovevano soddisfare la soglia dichiarata. Le esecuzioni di timing alternavano l'ordine e mantenivano la compilazione fuori dalla finestra misurata. Un agente di supervisione ha rieseguito i comandi di accettazione sul source congelato prima di accettare ogni risultato; il disaccordo sulla latenza di singola richiesta è rimasto nel rapporto finale.Il pacchetto completato contiene 204 directory di ricevute. I test combinati sono stati accettati alle 12:17 p.m., e i risultati terminali sono stati registrati alle 12:20 p.m. Un controllo finale di chiusura è stato mantenuto alle 2:38 p.m. Tutti e 6 i patch sono ora aperti per la revisione upstream: completion notification, worker concurrency, admission ownership, response cleanup, request batching, e endpoint indexing.
Da me. Il laboratorio stesso: il mio metodo guidato dai benchmark, puntato su Kitsune2 per trovare dove stava spendendo tempo.Da GPT-6 Astra. Le riparazioni di notifica di completamento e di proprietà di ammissione: la diagnosi, il patch, e i test che falliscono sul codice originale. Ha anche raffinato questo articolo dai registri del laboratorio.Da GLM-5.3. La riparazione di concorrenza del lavoratore, la pulizia delle risposte e il batching, la matrice di carico di configurazione 36 per l'indice, il profilo di riepilogo DHT dietro la domanda aperta K4, e la riproduzione combinata di tutti i patch 6.Da AI. L'indice dell'endpoint e le sue misurazioni, un agente di supervisione che rieseguiva ogni accettazione sul codice congelato prima che il risultato fosse conteggiato, e la prima bozza di questo articolo.Critiche che sono rimaste.
Da me: la bozza spiegava i meccanismi interni prima di dire cosa stava facendo un nodo Holochain, e le domande aperte 2 arrivavano senza alcuna connessione a nulla. La sequenza di recupero ora introduce ogni patch, e ogni domanda aperta si trova al passo che riguarda.
Dall'AI: ho chiesto se la mattina meritava la parola "scoperte". Ha sostenuto che un indice derivato e una chiamata helper ripristinata sono correzioni corrette, non nuove tecniche. L'articolo è archiviato come scoperta.
Da GPT-6 Astra: diverse affermazioni di bozza superavano le loro ricevute. Le ha mantenute su ciò che era misurato: 10.000 identità mantenute sono una storia, non 10.000 computer connessi; il costo di memoria dell'indice rimane sul registro; la latenza di richiesta singola e il caso quasi URL-meno rimangono inconclusivi.