feat(m3): durabilidad del relay — persist-before-broadcast + fsync (CHARTER-14) - #30
Merged
Merged
Conversation
…HARTER-14) Cierra FU-010, último Charter del vaciado del backlog antes del publish: de 2 open a 1 (FU-015, bloqueado upstream). Invierte el orden del relay a persist-before- broadcast (default), añade fsync al store de referencia y la cobertura de carga del relay que no existía. Decisiones en AIDEC-2026-07-16-001 (supersede de §5 de AIDEC-2026-07-13-001). La premisa del follow-up sobre el coste era falsa: AppendUpdateAsync ya se espera en el receive loop, así que invertir el orden no añade I/O a ningún hot path — solo mueve el broadcast a después del append. MEDIDO (carga del relay, ambos modos, fsync real): p50/p99 idénticos (2.1ms), el coste del orden seguro es ~0; solo el max sube por picos de fsync. La evidencia respalda el default con datos. Cambios: - WeftServerOptions.Durability (default PersistThenBroadcast; BroadcastThenPersist como válvula de escape opt-in). - DocumentSession.ApplyAndCaptureDeltaAsync: aplica y devuelve el delta como valor de retorno del turno (race-free frente a conexiones concurrentes del mismo hub). El hub deja de usar el evento UpdateApplied para el broadcast. - Fallo de append → DisconnectAll + cierre 1011 → reconexión resincroniza desde el servidor autoritativo (el único modo de equivocarse en persist-first; obligatorio). - FileSystemDocumentStore: Flush(flushToDisk:true) + fsync del directorio (POSIX). - Weft.LoadTest modo --relay: editor→observador vía TestServer real, p50/p99 por modo. - RelayTests +4: fallo inyectado no observado + 1011, reconexión, orden en ambos modos. El contrato de IDocumentStore NO cambia (contract suite intacta). Verificado: 155/155 tests, convergencia real de 2 clientes y-websocket con el default nuevo (reorden no rompe Yjs), carga del relay PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Último Charter del vaciado del backlog antes del publish (T060). Cierra FU-010: invierte el orden del relay a persist-before-broadcast (default), añade fsync al store de referencia y la cobertura de carga del relay que no existía. Backlog: 2 open → 1 (FU-015, bloqueado upstream) — el vaciado está completo salvo lo que depende de terceros.
Decisiones en AIDEC-2026-07-16-001 (supersede de §5 de AIDEC-2026-07-13-001). Tres las fijó el operador ex-ante: fsync en scope, default persist-first, cobertura de carga.
La premisa del follow-up era falsa — y eso lo simplificó
FU-010 temía que persist-before-broadcast metiera I/O en el hot path del actor. No es así:
AppendUpdateAsyncya se espera en el receive loop antes de leer el siguiente frame, así que invertir el orden no añade I/O a ningún hot path — solo mueve el broadcast a después del append.Medido (carga del relay, ambos modos,
FileSystemDocumentStorecon fsync):El coste del orden seguro es ~0 en p50/p99; solo el
maxsube por picos ocasionales de fsync. La evidencia respalda el default con datos, no con criterio.Cambios
WeftServerOptions.Durability(defaultPersistThenBroadcast;BroadcastThenPersistcomo válvula de escape opt-in).DocumentSession.ApplyAndCaptureDeltaAsync: aplica y devuelve el delta como valor de retorno del turno — race-free frente a conexiones concurrentes del mismo hub. El hub deja de usar el eventoUpdateAppliedpara el broadcast (refinamiento sobre el plan; AIDEC Decisión 4).DisconnectAll+ cierre 1011 → reconexión resincroniza desde el servidor autoritativo. Es el único modo de equivocarse en persist-first (un update aplicado pero no difundido dejaría pares callados para siempre), así que es obligatorio.FileSystemDocumentStore:Flush(flushToDisk:true)+ fsync del directorio (POSIX). Sin esto, el orden protege solo del crash de proceso, no de máquina — y el trigger de FU-010 pide «SLA de no-pérdida».Weft.LoadTestmodo--relay: editor→observador vía TestServer real, p50/p99 por modo.RelayTests+4: fallo inyectado no observado + 1011, reconexión resincroniza, orden en ambos modos.Verificación
IDocumentStore)y-websocket→"Hello from A. And B too."(el reorden no rompe Yjs)straymark validateNota: el drift marca
Weft.LoadTest.csprojcomo no declarado pese a estarlo — es el FP conocido de StrayMark #354 (el matcher no casa.csproj), documentado en el AILOG.🤖 Generated with Claude Code