openvibers/openvibe.live Commits

Account deletion erases a staged chat table on whichever side writes it now (ADR-033, C-04): Live while chat-tables.authority() is live, and its capture relays the delete to Chat's copy; Chat once Chat writes the table (OpenVibe.Chat a2d100d gates on table_authority), and its mirror relays it back. Before, Live always left the staged tables to Chat, which leaves them to Live while Live writes them, so neither erased them. node test/account-data.test.js, chat-tables-writers.

OP OpenVibers committed 27 Sept 2026 · 06cf38b12f · 1 file, +3 −3


Changes

ddiff --git a/server/auth/account-data.js b/server/auth/account-data.js
iindex 8ad38375..0c6df8fd 100644
---- a/server/auth/account-data.js
++++ b/server/auth/account-data.js
@@@ -21,8 +21,8 @@
* kept rows point at nobody.
*
* Never touched: the frozen tables (vods, clips, pastes, paste_likes, paste_comments, comments), which Media and
-- * Community own and erase themselves. The staged chat tables (chat-tables.js) are left to Chat, which erases its own
-- * copy; Live's rows there follow when a table moves.
++ * Community own and erase themselves. A staged chat table (chat-tables.js) is erased by whichever side writes it now:
++ * here while Live does (the capture relays the change to Chat's copy), by Chat once Chat does (its mirror relays it back).
*
* Applied once per export or deletion (account_data_events); a redelivery resends only what did not reach Network.
*/
@@@ -137,7 +137,7 @@ function eraseUsers(d, userIds, { now = new Date().toISOString() } = {}) {
for (const [t, list] of cols) {
const where = list.map((c) => `${q(c.col)} = ?`).join(' OR ');
if (RETAIN.has(t)) { bump(retained, t, d.prepare(`SELECT COUNT(*) AS n FROM ${q(t)} WHERE ${where}`).get(...list.map(() => uid)).n); continue; }
-- if (stagedTables.has(t)) { bump(retained, 'left_for_chat', d.prepare(`SELECT COUNT(*) AS n FROM ${q(t)} WHERE ${where}`).get(...list.map(() => uid)).n); continue; }
++ if (stagedTables.has(t) && require('../chat/chat-tables').authority(t) !== 'live') { bump(retained, 'left_for_chat', d.prepare(`SELECT COUNT(*) AS n FROM ${q(t)} WHERE ${where}`).get(...list.map(() => uid)).n); continue; }
for (const c of list) {
if (c.action === 'null') {
const info = d.prepare(`PRAGMA table_info(${q(t)})`).all().filter((x) => NAME_COLS.includes(x.name));