Kitsune2: Búsquedas 251x Más Rápidas, la Ruta de Actualización 33x, y el Rumor Iniciado 15x Más Temprano
Dentro de una mañana de experimentos sobre la capa de red de Holochain: cómo los nodos encuentran pares, recuperan datos faltantes, y reanudan el rumor, y qué pequeños parches de 6 cambiaron en el camino.
Developed by Robert E. Beckner III (Merlin) | rbeckner.com
He estado despertando alrededor de 4:30 a.m. últimamente, justo antes del amanecer, y disfrutándolo. El 19 de septiembre usé esa mañana para iniciar un laboratorio sobre Kitsune2, la capa de red peer-to-peer bajo Holochain, y busqué dónde estaba gastando tiempo.Para 12:20 p.m., el laboratorio había producido 6 parches. Búsquedas de endpoint: 251× más rápidas en 10,000 identidades retenidas. La ruta de actualización peer que las llama: 33× más rápida. Inicio de rumor después de una recuperación completada: 3,002 ms reducidos a 202 ms. Tráfico de solicitud de ráfaga: 96.9% menos mensajes. 3 de los cambios repararon trabajo que estaba esperando innecesariamente, o esperando algo que nunca sucedería.He estado programando por más de 25 años y construyendo con IA desde GPT-3. Lo uso para aislar algo que me importa o que aún no entiendo, trabajar en ello, y probar lo que creemos haber aprendido. Me encanta esa parte: convertir una pregunta en un experimento y ver qué sostiene. Esta mañana, con agentes de codificación IA, apliqué ese enfoque a la maquinaria que permite a los nodos de Holochain mantenerse actualizados entre sí.Las aplicaciones Holochain comparten datos entre computadoras participantes, o nodos. Cada participante mantiene su propio historial firmado y ayuda a validar y almacenar una porción de los datos compartidos de la aplicación. Esa tienda compartida es la distributed hash table, o DHT. Las copias viven con varios pares, por lo que los datos pueden seguir disponibles cuando su autor se desconecta. Guía de DHT de Holochain explica cómo se distribuyen esas responsabilidades.Kitsune2 maneja la comunicación punto a punto debajo de esto. Imagina un nodo poniéndose al día: aprende dónde se pueden alcanzar los pares, compara lo que tiene con lo que ellos tienen, y solicita las piezas que le faltan. Gossip es el intercambio mediante el cual los pares descubren esas diferencias; fetch recupera las operaciones faltantes, las unidades de datos que Kitsune2 transfiere. El nodo receptor las entrega al almacén de operaciones de su host. Holochain maneja su validación e integración.Diagram source
graph TD
A[Aprender las identidades y puntos finales de los pares] --> B[Comparar datos mediante gossip]
B --> C[Identificar operaciones faltantes]
C --> D[Recuperar operaciones de los pares]
D --> E[Entregar las operaciones recibidas al almacén del host]
E --> F[Señalar que las recuperaciones pendientes han finalizado]
F e1@--> B
e1@{ animation: fast }
Copy sourceLos parches se sitúan a lo largo de esa secuencia. Algunos reducen el trabajo que un nodo realiza; otros lo dejan avanzar cuando el trabajo ya ha terminado. Las cifras anteriores miden esos pasos particulares en nodos de prueba locales.
Qué movieron realmente cada uno de los cambios de 6#
Fijamos el punto de partida en el commit ascendente 06555ee, fuente de desarrollo 0.6.0-dev.1. Cada comparación usa esa línea base más la secuencia de parches registrada. Las etiquetas de abajo conectan los hallazgos con nuestros registros de experimentos; todos los parches de 6 ahora están enviados para revisión ascendente.
Etiqueta
Qué cambió
Resultado medido
K3a
Llamar al helper de drenaje existente cuando una descarga termina
Inicio de gossip después de una descarga completada: 3,002 → 202 ms
K3b
Bloqueo del receptor limitado al dequeue
La concurrencia efectiva fue 1. Los workers configurados ahora se superponen realmente
K3c
Propiedad de admisión marcada por generación
Cancelado el strand de los llamadores 0 con claves pendientes. Baseline stranded 8
K3d-P1
Limpieza de respuesta basada en conjuntos
1.9–6.1× procesamiento de respuesta más rápido en cargas pendientes grandes
K3d-P2
Agrupación opt-in de pares iguales (predeterminado 1)
Explosiones: 87.5–96.9% menos mensajes de solicitud
K1
Revertir URL al índice del agente
En 10,000 identidades retenidas: actualizaciones 21–33×, búsquedas 118–251× más rápidas, para 3.10× memoria de almacenamiento
La primera reparación reconecta la finalización de la recuperación con la tarea de gossip que la espera. El cambio llama a un asistente existente que informa a los oyentes que el mapa pendiente se ha vaciado. Probamos tanto una recuperación completada como una recuperación mantenida deliberadamente abierta.
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
Después de la finalización, gossip puede continuar. Mientras la recuperación permanece pendiente, ambas versiones aún alcanzan el temporizador de respaldo. La prueba aislada anterior midió 3,001 → 202 ms; la reproducción combinada posterior midió 3,002 → 202 ms. Ambos usaron un respaldo de 3,000 ms y un retraso inicial de 200 ms. La diferencia aproximada de 15× registra qué ruta tomó la tarea: esperar el respaldo o despertarse en la finalización.
Cada cambio vive en una sola crate, y 5 de las 6 en un solo archivo#
Una crate Rust es un paquete de código. Todos los parches 6 viven en la crate principal, que contiene los registros pares y la maquinaria de obtención. Cambian cómo el gossip obtiene sus datos y señales de finalización sin editar el algoritmo de gossip o el transporte de red subyacente. El batching agrega un campo de configuración core opcional.
Etiqueta
Archivo
Líneas
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 archivo de prueba
+89 / −17
5 parches se apilan en un orden grabado en core_fetch.rs, que solicita operaciones faltantes y procesa respuestas. El parche restante se encuentra en core_known_peers.rs, el registro retenido de cuál identidad está asociada con qué punto final de red. Luego aplicamos todos los 6 a un solo árbol fuente y los ejecutamos juntos.
Los datos habían llegado, pero el gossip todavía estaba esperando#
CoreFetch mantiene un mapa de las operaciones que ha pedido y de quién. Cuando llega la respuesta de un peer y las operaciones se almacenan correctamente, el código elimina esos identificadores del mapa. Otras partes del archivo, el send-error path y el peer-cleanup path, llaman a un helper llamado notify_listeners_if_queue_drained justo después de que eliminan las entradas. El success path nunca lo llamó.Un nodo puede expandir la porción del DHT que almacena, llamada su storage arc. Para hacer eso, necesita ponerse al día con los datos dentro del rango mayor. En el arc-growth path que probamos, el gossip espera a que los fetches pendientes terminen antes de iniciar con un peer, con un timer como fallback. Los datos llegaron y el pending map se vació, pero la tarea que esperaba esa señal siguió dormida hasta que expiró el timer.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 sourceRevisar después de la finalización oculta la diferencia: un waiter recién registrado ve el mapa vacío y devuelve inmediatamente. Registramos el nuestro antes de la finalización. Una vez que los datos se almacenaron, ese waiter todavía no tenía notificación en el código original; con el parche, recibió una. Esto repara la transición entre recibir datos y comenzar el siguiente intercambio de gossip.También revisamos respuestas parciales, errores de store, varios listeners, y listeners registrándose como requests completados o nuevo trabajo llegó. Una respuesta parcial debe dejar el waiter pendiente; solo completar la última fetch pendiente debe despertarlo.
5 trabajadores fueron configurados, y 1 estaba enviando realmente#
El lado saliente de CoreFetch ejecuta un número configurado de tareas de trabajador que extraen de un canal compartido. El bucle se escribió así:rustCopy source
while let Some(..) = outgoing_request_rx.lock().await.recv().await { // send the request}
El bloqueo permite que el trabajador 1 tome la siguiente solicitud del cuadro compartido. Pero Rust mantiene ese guardián de bloqueo temporal vivo a través del cuerpo de este while let, incluida la espera por el envío de red. Mientras el trabajador 1 enviaba, el otro 4 ni siquiera podía recoger su siguiente solicitud. Todas las solicitudes aún podían llegar eventualmente, así que una prueba de entrega podría pasar mientras la concurrencia configurada quedaba sin usar.Movimos la recepción a un bloque corto para que el bloqueo se libere antes de que comience el envío. Los trabajadores aún se turnan para recoger solicitudes, luego las envían concurrentemente. Un envío lento ya no mantiene el bloqueo de la cola mientras otros trabajadores tienen solicitudes listas.
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 medición mantiene cada envío abierto con un reloj pausado y cuenta cuántos han entrado antes de que se libere cualquiera, luego confirma que nada entra más allá del límite configurado.
Cancelar un llamante dejó el nodo esperando operaciones no enviadas de 8#
Una solicitud de búsqueda pasa por los registros de 2: el mapa pendiente indica lo que el nodo está esperando, y la cola saliente contiene trabajo para los trabajadores de envío. request_ops, el método que solicita operaciones, añadió todo un lote al mapa pendiente antes de esperar espacio en esa cola.Si el llamante fue cancelado mientras esperaba capacidad, algunas operaciones ya habían sido marcadas como pendientes aunque ningún trabajador las hubiera recibido. Llenamos la cola, cancelamos un llamante bloqueado, y dejamos que todas las solicitudes admitidas de 16,385 terminaran. Las operaciones de 8 permanecieron pendientes. Nunca entraron en la cola saliente, por lo que no hubo respuesta en su camino para limpiarlas.Eso se conecta directamente a la primera reparación: una notificación de finalización no puede dispararse mientras el mapa todavía contiene trabajo sin terminar. Aquí, la propia contabilidad del nodo lo mantenía esperando.El parche reserva primero la capacidad de la cola, luego registra y encola la operación sin otra espera entre esos pasos. Cada entrada también lleva una etiqueta de generación, así que la limpieza de un envío fallido anterior no puede borrar una solicitud más nueva para la misma operación. El trabajo ya admitido sobrevive a la cancelación del llamante; el trabajo que aún espera admisión no deja ninguna entrada pendiente atrás.Esto repara la propiedad de las solicitudes. Los límites de memoria totales siguen siendo una pregunta de diseño separada, ya que un llamante aún puede suministrar un lote grande.
Menos mensajes de solicitud, con un límite sobre cuán grande puede crecer cada uno#
Un nodo que se pone al día puede necesitar muchas operaciones del mismo par. El formato de solicitud de Kitsune2 ya admite una lista de identificadores, pero el código saliente envía 1 por mensaje. Antes de combinar esas solicitudes, verificamos cómo se manejarían las respuestas más grandes.Para cada operación pendiente, la limpieza de respuesta escaneó la lista de identificadores devueltos para ver si podía eliminar esa entrada. Con 8,192 entradas pendientes y 1,024 identificadores devueltos, eso repite una gran cantidad de búsquedas. Construir un HashSet de los identificadores devueltos hace que cada verificación de membresía sea barata; el procesamiento de la respuesta midió 6.1× más rápido en ese caso. Con solo 16 identificadores devueltos, almacenar los datos dominaba y el cambio aportó poco.Luego combinamos las solicitudes listas para el mismo par. En un estallido de 64 pequeñas operaciones, los tamaños de lote de 8 y 32 redujeron los mensajes de solicitud en 87.5% y 96.9%, respectivamente.
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
El estallido terminó aproximadamente 27–32% antes. Las mismas operaciones todavía tenían que transferirse y almacenarse; el ahorro estaba en cuántas solicitudes las transportaban. El control batch-1 midió 105.4% del tiempo transcurrido base, mostrando aproximadamente 5% deriva de tiempo incluso con el batching inactivo.Un trabajador combina solo solicitudes que ya están listas, así que una solicitud solitaria nunca espera que un lote se llene. La división de lotes usa tanto un límite de identificador configurado como un umbral de solicitud codificado en 4,096-bytes. Contar ítems por sí solo no restringe su tamaño total; la prueba con 200 identificadores los divide en varios mensajes con límite. Un solo identificador todavía se envía si por sí solo excede ese umbral, así que esto no es una restricción universal de tamaño de cable. Las respuestas llevan los datos reales y necesitarían un límite de tamaño separado en el nodo que responde.El candidato mantiene el tamaño de lote 1 como su valor predeterminado y acepta las configuraciones existentes sin cambios. Dejamos la opción de lotes más grandes porque la prueba separada para una sola solicitud produjo resultados inconsistentes de latencia final, cubiertos a continuación.
Quitar el escaneo del camino de actualización valió 33×, y 251× en la propia búsqueda#
CoreKnownPeers recuerda identidades y los puntos finales de red asociados con ellas. Varias identidades pueden compartir un punto final, y una identidad bloqueada aún necesita ser identificable después de haber sido eliminada del almacén de pares activo. 10,000 identidades retenidas por lo tanto significa un historial de identidades en este almacén, no 10,000 computadoras conectadas a la vez.En una actualización del almacén de pares, el control de acceso pregunta qué identidades pertenecen al punto final. La búsqueda, get_by_url, escaneó todo el mapa retenido bajo un bloqueo cada vez. A medida que ese historial crecía, actualizar la información actual del par se volvía más costoso.Añadimos un índice desde el punto final URL a las identidades asociadas con él: HashMap<Url, HashSet<AgentId>>. Los registros originales siguen siendo autoritativos. Cuando una identidad cambia de punto final, el índice la mueve al conjunto correspondiente; la búsqueda puede entonces ir directamente a ese conjunto. Ambas versiones pasaron las verificaciones de resultados 19,422 cubriendo actualizaciones, anuncios obsoletos, eliminaciones y puntos finales compartidos.
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
Cada llamada programada arriba inserta 16 anuncios y ejecuta los oyentes de control de acceso. En 10,000 identidades retenidas, cayó de aproximadamente 155 µs a 4.72 µs, una ganancia pareada 33×. La versión indexada permanece casi plana en estos tamaños porque esos oyentes ya no escanean el historial creciente.Medido en el API en lugar de a través del llamador, la propia búsqueda pasa de un escaneo a un hash. Un fallo en 10,000 identidades retenidas cayó de 11,423 ns a 45 ns, una ganancia pareada 251×, y un solo acierto de 9,309 ns a 79 ns, 118×. Una consulta que devuelve muchas identidades sigue escalando con lo que devuelve, por lo que el caso de URL compartido gana 4.4× en lugar de 2 órdenes de magnitud. El 251× es el resultado de búsqueda aislado. El 33× mide la llamada de actualización más grande que lo usa; estas ganancias no pueden sumarse ni multiplicarse.
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× en una tienda mixta, un extra 2.51 MB en 10,000 identidades. Cuando cada identidad comparte un punto final, el mapa derivado es pequeño y el costo cae a 1.45×. Cuando ninguna identidad tiene un URL no hay nada que derivar y el costo es cero. Esos números son bytes solicitados por el asignador para la tienda retenida, no la memoria total del nodo.
Con todas las correcciones 6 juntas, el nodo podría terminar y continuar#
La reproducción combinada usó los componentes reales de chisme, búsqueda, acceso a pares y almacén de memoria de Kitsune2, comunicándose a través de su transporte de prueba en memoria. Ejecutamos una secuencia de 5 pasos en los árboles de origen y parcheados:
Actualizar información del par. Una identidad cambia punto final. La información obsoleta que llega después deja el registro más reciente intacto, y una identidad bloqueada sigue siendo resoluble para el control de acceso. Ambas versiones pasan; el índice preserva las decisiones existentes.
Iniciar chisme después de que una búsqueda termine. El nodo parcheado inicia después de 202 ms. El original toma el camino de respaldo a 3,002 ms.
Recibir datos fuera de orden. Las operaciones solicitadas por 3 llegan como respuestas 4, incluida una duplicada. Ambas versiones las almacenan de manera consistente y asocian los recuentos de bytes con la operación correcta.
Terminar la búsqueda. Las operaciones almacenadas pueden recuperarse. El nodo parcheado también despierta al oyente que se registró mientras esas operaciones estaban pendientes.
Continuar después de un par fallido. Un fallo controlado de envío borra el estado de solicitud de ese par. Otro par suministra la operación, el mapa pendiente se vacía, y una búsqueda subsiguiente tiene éxito. En el original, las comprobaciones de notificación de finalización fallan.
Las pruebas de interacción separadas combinaron cancelación con envíos concurrentes y agrupación combinada con notificación de finalización. Las reparaciones se mantuvieron juntas: el trabajo admitido completado, las admisiones canceladas no dejaron entradas huérfanas, y los oyentes despertaron después de la respuesta final.Esto nos lleva tan lejos como los datos recibidos en el almacén del host y el siguiente paso de red puede proceder. La validación e integración de Holochain todavía siguen fuera de este laboratorio. Aún no hemos medido cuánto acortan estos cambios el tiempo total de actualización de un nodo real.
El índice cuesta memoria y hace que los cambios de endpoint sean más caros. En la prueba de pequeño almacén original, actualizar un conjunto fijo de identidades a nuevas URLs se ejecutó a 0.946× la velocidad base con identidades 100 retenidas. A 10,000, un escrito aislado de cambio de endpoint costó 3.68× tanto. Mantener el índice extra tiene un precio; los ahorros de búsqueda deben reembolsarlo.Debido a que ese compromiso es real, buscamos la carga de trabajo donde el índice pierde. 36 configuraciones fueron predeclaradas antes de medir, 432 ejecuciones emparejadas ejecutadas, y las transcripciones de resultados se han hasheado idénticamente entre variantes.
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
Cada carga de trabajo en esta matriz más amplia tuvo una mediana por encima de la paridad, incluida la mezcla donde cada actualización aceptada cambiaba un endpoint: 1.47× a 100 identidades y 36.42× a 10,000. Esas actualizaciones también disparan búsquedas de control de acceso, y sus ahorros superaron los escrituras adicionales. Esta carga de trabajo más amplia difiere de la prueba de conjunto fijo anterior; su resultado positivo deja esa regresión de pequeño almacén en el registro.El caso de 100 identidades, mayormente URL-menos sigue inconcluso: su mediana 1.09× incluyó un resultado pareado por debajo de la paridad. Todavía necesitamos trazas de nodos reales que muestren conteos de identidad retenida, cambios de endpoint y frecuencia de búsqueda antes de recomendar el índice para una carga de trabajo particular.Los envíos concurrentes expusieron una interacción de limpieza. Una vez que los trabajadores podían superponerse, la limpieza de un envío fallido podría ejecutarse mientras otra solicitud al mismo par estaba en vuelo. Eso hizo que la limpieza existente a nivel de par fuera más amplia que el trabajo que había fallado. El parche de propiedad redujo la eliminación a entradas que todavía pertenecían a esa generación de solicitud. Probar los parches juntos importó aquí.La latencia de solicitud única de la agrupación sigue inconclusa. Medimos p95, el tiempo dentro del cual 95% de solicitudes terminan. Para una solicitud enviada sola, la ejecución final del trabajador mostró 1.01–1.08× la base p95; la reejecución independiente mostró 1.44–1.58×. Estos accesorios tardan decenas de microsegundos, y sus controles también se desviaron. La mejora de ráfaga se reprodujo, pero el resultado de la solicitud única no se estabilizó, por lo que los lotes más grandes siguen siendo opt-in.
Las comparaciones repetidas y los envíos detenidos siguen abiertos#
También examinamos 2 otras partes de la misma secuencia de sincronización. Ninguna produjo un parche aceptado.Comparando lo que ya tienen los pares (K4). Gossip usa resúmenes compactos de datos almacenados para encontrar diferencias. En la prueba más grande, producir y comparar una instantánea sin cambios materializó 262,144 hashes; repetirlo 10 veces produjo la misma salida cada vez. Reutilizar un resumen previo parece atractivo, pero la tienda host puede cambiar sin una señal fiable para invalidar ese resultado guardado. Un resumen en caché podría entonces ocultar una diferencia entre pares. Las alternativas que evaluamos también quedaron por debajo del ahorro de tiempo requerido 20% en la tienda en memoria. Las mediciones de una tienda Holochain real son la siguiente pieza faltante.Recuperándose cuando un envío de gossip se detiene (K2). Leer la fuente planteó una pregunta sobre un envío que mantiene un bloqueo que la tarea de tiempo de espera también necesita. También necesitábamos establecer qué sucede con el flujo de transporte Iroh subyacente si ese envío se cancela a mitad de camino. El proveedor de agentes bloqueó el trabajo en el controlador de reproducción, por lo que la prueba de tiempo de ejecución nunca se completó. Esto sigue siendo una preocupación no probada, sin parche ni resultado de fiabilidad.
Estos experimentos se ejecutaron en el código fuente de desarrollo 0.6.0-dev.1, en un M4 Max compartido Apple con 16 núcleos lógicos. Usamos nodos de prueba locales y transportes en memoria, sin fijación de núcleo ni un segundo host físico. Los resultados cubren componentes nombrados y sus interacciones. El rendimiento de la red, la convergencia de toda la red, la memoria total del nodo y la latencia de la aplicación Holochain siguen sin medirse.El método sigue mi trabajo sobre desarrollo impulsado por benchmarks. Registramos cada pregunta y umbral de aceptación, mantuvimos el código fuente y los fixtures fijos dentro de cada comparación, y guardamos comandos, muestras y fallos en recibos de solo anexado.Para las reparaciones 3, las mismas pruebas fallaron en el código original en las aserciones esperadas y pasaron con el parche. Para las optimizaciones, ambas versiones tuvieron que preservar el comportamiento, luego las mediciones tuvieron que cumplir el umbral declarado. Las ejecuciones de tiempo alternaron el orden y mantuvieron la compilación fuera de la ventana medida. Un agente supervisor volvió a ejecutar los comandos de aceptación sobre el código congelado antes de aceptar cada resultado; el desacuerdo sobre la latencia de solicitud única permaneció en el informe final.El paquete completado contiene 204 directorios de recibos. Las pruebas combinadas fueron aceptadas a las 12:17 p.m., y los resultados terminales se registraron a las 12:20 p.m. Se mantuvo una verificación de cierre final a las 2:38 p.m. Los 6 parches están ahora abiertos para revisión ascendente: notificación de finalización, concurrencia de trabajadores, propiedad de admisión, limpieza de respuesta, agrupación de solicitudes, y indexación de puntos finales.
Por mí. El propio laboratorio: mi método basado en benchmarks, apuntado a Kitsune2 para encontrar dónde estaba gastando tiempo.Por GPT-6 Astra. Las reparaciones de notificación de finalización y de propiedad de admisión: el diagnóstico, el parche y las pruebas que fallan en el código original. También afinó este artículo a partir de los registros del laboratorio.Por GLM-5.3. La reparación de concurrencia de trabajadores, la limpieza y agrupación de respuestas, la matriz de carga de configuración 36 para el índice, el perfilado de resumen DHT detrás de la pregunta abierta K4 y la reproducción combinada de todos los parches 6.Por IA. El índice de punto final y sus mediciones, un agente supervisor que volvió a ejecutar cada aceptación sobre el código fuente congelado antes de que el resultado se contabilizara, y el primer borrador de este artículo.Críticas que se mantuvieron.
De mí: el borrador explicó los mecanismos internos antes de decir lo que un nodo Holochain estaba haciendo, y las preguntas abiertas 2 llegaron sin conexión con nada. La secuencia de recuperación ahora introduce cada parche, y cada pregunta abierta se sitúa en el paso que le concierne.
De la IA: pregunté si la mañana merecía la palabra "avances". Argumentó que un índice derivado y una llamada de ayuda restaurada son correcciones correctas, no nuevas técnicas. El artículo se archiva como una descubrimiento.
De GPT-6 Astra: varias afirmaciones de borrador superaron sus recibos. Las sostuvo a lo que se midió: 10,000 identidades retenidas son una historia, no 10,000 computadoras conectadas; el costo de memoria del índice permanece en el registro; la latencia de la solicitud única y el caso mayormente URL-menos permanecen inconclusos.