/** Monotonic timings for local requests and authoritative mesh publication. */ export class EditDiagnostics { constructor() { this.reset(); } reset() { this.requests = new Map(); this.sections = new Map(); this.last = null; } request(pos, block, now = performance.now()) { for (const [key, value] of this.requests) if (now - value.time > 5000) this.requests.delete(key); if (this.requests.size >= 64) this.requests.delete(this.requests.keys().next().value); this.requests.set(pos.join(','), { block, time: now }); } confirmed(changes, now = performance.now()) { for (const { pos, block } of changes) { const key = pos.join(','), request = this.requests.get(key); if (!request || request.block !== block || now - request.time > 5000) continue; this.requests.delete(key); const id = pos.map(v => Math.floor(v / 16)).join(','); if (this.sections.size >= 64) this.sections.delete(this.sections.keys().next().value); this.sections.set(id, { request: request.time, confirmed: now }); } } published(id, now = performance.now()) { const edit = this.sections.get(id); if (!edit) return null; this.sections.delete(id); this.last = { acknowledgementMs: edit.confirmed - edit.request, geometryMs: now - edit.confirmed, totalMs: now - edit.request }; return this.last; } }