fix(traffic): подтверждать идентичность соседних счётчиков

This commit is contained in:
Denozordec committed 2026-10-13 01:19:22 +07:00
1 parent 493c30bebc
commit b57ae316ba
27 files changed
+1444 -36

No files matched your search

+1
View File
@@ -310,6 +310,7 @@ export const flowAsnMeta = pgTable("flow_asn_meta", {
})
export const trafficSamples = pgTable("traffic_samples", {
nativeCounterIdentity: text("native_counter_identity"),
serverId: intPkRef().references(() => servers.id, { onDelete: "cascade" }),
interfaceName: text("interface_name").notNull(),
peerPublicKey: text("peer_public_key").notNull().default(""),
+9 -1
View File
@@ -2,11 +2,19 @@ export const TRAFFIC_FLAG_RUNNING = 1
export const TRAFFIC_FLAG_DISABLED = 2
export const TRAFFIC_FLAG_COUNTERS_KNOWN = 4
export const TRAFFIC_FLAG_STATUS_KNOWN = 8
export const TRAFFIC_FLAG_CONTINUITY_KNOWN = 16
export const TRAFFIC_FLAG_CONTINUITY_RECORDED = 32
export function encodeTrafficFlags(running: boolean, disabled: boolean, countersKnown = false, statusKnown = false): number {
export function encodeTrafficFlags(running: boolean, disabled: boolean, countersKnown = false, statusKnown = false, continuityKnown?: boolean): number {
return (running ? TRAFFIC_FLAG_RUNNING : 0) | (disabled ? TRAFFIC_FLAG_DISABLED : 0)
| (countersKnown ? TRAFFIC_FLAG_COUNTERS_KNOWN : 0)
| (statusKnown ? TRAFFIC_FLAG_STATUS_KNOWN : 0)
| (continuityKnown === undefined ? 0 : TRAFFIC_FLAG_CONTINUITY_RECORDED | (continuityKnown ? TRAFFIC_FLAG_CONTINUITY_KNOWN : 0))
}
/** Undefined retains the documented legacy boundary; new producers explicitly mark both outcomes. */
export function trafficCounterContinuity(flags: number): boolean | undefined {
return flags & TRAFFIC_FLAG_CONTINUITY_RECORDED ? !!(flags & TRAFFIC_FLAG_CONTINUITY_KNOWN) : undefined
}
export function trafficFlagRunning(flags: number | null | undefined): boolean {
+18 -9
View File
@@ -1,12 +1,12 @@
import { and, asc, desc, eq, gte } from "drizzle-orm"
import { db } from "../db/index.js"
import { servers, trafficSamples, trafficSettings } from "../db/schema.js"
import { decodeTrafficSampleFlags, encodeTrafficFlags } from "../db/traffic-flags.js"
import { decodeTrafficSampleFlags, encodeTrafficFlags, trafficCounterContinuity } from "../db/traffic-flags.js"
import type { TrafficRunSnapshot } from "../types/scheduler-run-snapshot.js"
import { SCHEDULER_RUN_SNAPSHOT_VERSION } from "../types/scheduler-run-snapshot.js"
import { MikrotikClient } from "./mikrotik.js"
import { bpsToMbps, shouldIncludeIface } from "./traffic-rate.js"
import { observedTrafficRate, parseTrafficCounter, parseTrafficFlag } from "./traffic-observation.js"
import { observedTrafficRate, parseTrafficCounter, parseTrafficFlag, nativeTrafficCounterIdentity } from "./traffic-observation.js"
import { rememberServerIfaces } from "./traffic-flow-ifindex.js"
import { recordTrafficCollectionAttempt } from "./traffic-collection-state.js"
import { parseTrafficPeers } from "./traffic-peer-observation.js"
@@ -38,14 +38,15 @@ function waveKey(interfaceName: string, peerPublicKey = ""): string {
}
function sampleRate(
prevWave: Map<string, { rxBytes: number; txBytes: number; sampledAt: string }>,
prevWave: Map<string, { rxBytes: number; txBytes: number; sampledAt: string; nativeCounterIdentity: string|null }>,
key: string,
rxBytes: number,
txBytes: number,
nowMs: number,
maxIntervalMs: number,
identity: string|null,
): { rxBps: number; txBps: number; measured: boolean } {
return observedTrafficRate(prevWave.get(key), rxBytes, txBytes, nowMs, maxIntervalMs)
return observedTrafficRate(identity !== null && prevWave.get(key)?.nativeCounterIdentity === identity ? prevWave.get(key) : undefined, rxBytes, txBytes, nowMs, maxIntervalMs)
}
export interface TrafficCollectorState {
@@ -75,7 +76,7 @@ async function getSettingsRow() {
return (await db.select().from(trafficSettings).where(eq(trafficSettings.id, 1)).limit(1))[0]
}
async function readPreviousWave(serverId: number): Promise<Map<string, { rxBytes: number; txBytes: number; sampledAt: string }>> {
async function readPreviousWave(serverId: number): Promise<Map<string, { rxBytes: number; txBytes: number; sampledAt: string; nativeCounterIdentity: string|null }>> {
const last = (await db
.select({ sampledAt: trafficSamples.sampledAt })
.from(trafficSamples)
@@ -90,6 +91,7 @@ async function readPreviousWave(serverId: number): Promise<Map<string, { rxBytes
rxBytes: trafficSamples.rxBytes,
txBytes: trafficSamples.txBytes,
flags: trafficSamples.flags,
nativeCounterIdentity: trafficSamples.nativeCounterIdentity,
sampledAt: trafficSamples.sampledAt,
})
.from(trafficSamples)
@@ -144,11 +146,13 @@ export async function collectTrafficOnce(): Promise<TrafficRunSnapshot> {
let totalsMeasured = true
const rows = ifaces.map((i) => {
const interfaceName = i.name!
const nativeCounterIdentity = nativeTrafficCounterIdentity(srv.updatedAt,i[".id"])
const continuityKnown = nativeCounterIdentity !== null && prevWave.get(waveKey(interfaceName))?.nativeCounterIdentity === nativeCounterIdentity
const rxBytes = toNum(i["rx-byte"])
const txBytes = toNum(i["tx-byte"])
const running = parseTrafficFlag(i.running)
const disabled = parseTrafficFlag(i.disabled)
const { rxBps, txBps, measured } = sampleRate(prevWave, waveKey(interfaceName), rxBytes, txBytes, nowMs, maxIntervalMs)
const { rxBps, txBps, measured } = sampleRate(prevWave, waveKey(interfaceName), rxBytes, txBytes, nowMs, maxIntervalMs, nativeCounterIdentity)
if (shouldIncludeIface(interfaceName, running, disabled)) {
includedInterfaces++
totalsMeasured &&= measured
@@ -164,7 +168,8 @@ export async function collectTrafficOnce(): Promise<TrafficRunSnapshot> {
txBytes,
rxBps: Math.round(rxBps),
txBps: Math.round(txBps),
flags: encodeTrafficFlags(running, disabled, true, true),
flags: encodeTrafficFlags(running, disabled, true, true, continuityKnown),
nativeCounterIdentity,
}
})
let peerWarning: string | undefined
@@ -172,6 +177,8 @@ export async function collectTrafficOnce(): Promise<TrafficRunSnapshot> {
const peers = await client.get<RosWgPeerTraffic[]>("/interface/wireguard/peers")
for (const p of parseTrafficPeers(peers)) {
const { interfaceName, peerPublicKey, rxBytes, txBytes, disabled } = p
const nativeCounterIdentity = nativeTrafficCounterIdentity(srv.updatedAt,p.nativeId)
const continuityKnown = nativeCounterIdentity !== null && prevWave.get(waveKey(interfaceName,peerPublicKey))?.nativeCounterIdentity === nativeCounterIdentity
const running = !disabled
const { rxBps, txBps } = sampleRate(
prevWave,
@@ -180,6 +187,7 @@ export async function collectTrafficOnce(): Promise<TrafficRunSnapshot> {
txBytes,
nowMs,
maxIntervalMs,
nativeCounterIdentity,
)
rows.push({
serverId: srv.id,
@@ -190,7 +198,8 @@ export async function collectTrafficOnce(): Promise<TrafficRunSnapshot> {
txBytes,
rxBps: Math.round(rxBps),
txBps: Math.round(txBps),
flags: encodeTrafficFlags(running, disabled, true, true),
flags: encodeTrafficFlags(running, disabled, true, true, continuityKnown),
nativeCounterIdentity,
})
}
} catch (error) {
@@ -292,5 +301,5 @@ export async function readServerSamplesInRange(serverId: number, sinceIso: strin
gte(trafficSamples.sampledAt, sinceIso),
))
.orderBy(asc(trafficSamples.sampledAt))
return rows.map((r) => ({ ...r, ...decodeTrafficSampleFlags(r.flags) }))
return rows.map((r) => ({ ...r, ...decodeTrafficSampleFlags(r.flags), continuityKnown: trafficCounterContinuity(r.flags) }))
}
@@ -16,7 +16,7 @@ else {
assert.equal((await pool.query("SELECT current_database() AS name")).rows[0].name,database)
const prefix="own-history178-"+Date.now()+"-",userId=prefix+"user"
let serverId:number|undefined,deny=false,counter="1000",cases=0,requests=0
const http=createServer((req,res)=>{requests++;res.setHeader("Content-Type","application/json");if(deny){res.statusCode=401;res.end('{"message":"Unauthorized"}')}else res.end(JSON.stringify(req.url?.includes("/wireguard/")?[]:[{name:"ether1",running:"true",disabled:"false","rx-byte":counter,"tx-byte":counter}]))})
const http=createServer((req,res)=>{requests++;res.setHeader("Content-Type","application/json");if(deny){res.statusCode=401;res.end('{"message":"Unauthorized"}')}else res.end(JSON.stringify(req.url?.includes("/wireguard/")?[]:[{".id":"*1",name:"ether1",running:"true",disabled:"false","rx-byte":counter,"tx-byte":counter}]))})
await new Promise<void>(resolve=>http.listen(0,"127.0.0.1",resolve));const address=http.address();assert(address&&typeof address==="object")
const app=Fastify();await app.register(trafficRoutes)
const get=async(path:string)=>{const r=await app.inject({method:"GET",url:path});assert.equal(r.statusCode,200);return r.json()}
@@ -0,0 +1,15 @@
import assert from 'node:assert/strict'
import {nativeTrafficCounterIdentity} from './traffic-observation.js'
import {buildTrafficFromSamples} from './traffic-rate.js'
import {encodeTrafficFlags,trafficCounterContinuity} from '../db/traffic-flags.js'
const at=Date.parse('2026-10-13T00:00:00Z'),iso=new Date(at).toISOString(),identity=nativeTrafficCounterIdentity(iso,'*a')!
assert.equal(identity,nativeTrafficCounterIdentity(new Date(at),'*A'))
for(const id of[undefined,null,'','bad','*z',{},1])assert.equal(nativeTrafficCounterIdentity(iso,id),null)
assert.equal(trafficCounterContinuity(13),undefined);assert.equal(trafficCounterContinuity(encodeTrafficFlags(true,false,true,true,false)),false);assert.equal(trafficCounterContinuity(encodeTrafficFlags(true,false,true,true,true)),true)
const first={interfaceName:'ether1',sampledAt:new Date(at-30_000).toISOString(),rxBytes:1000,txBytes:1000,rxBps:0,txBps:0,running:true,disabled:false,countersKnown:true,nativeCounterIdentity:identity,continuityKnown:false}
for(const nextIdentity of[identity,nativeTrafficCounterIdentity(iso,'*b'),nativeTrafficCounterIdentity(new Date(at+1),'*a'),null]){
const cur={...first,sampledAt:iso,rxBytes:2000,txBytes:2000,nativeCounterIdentity:nextIdentity,continuityKnown:nextIdentity===identity}
const built=buildTrafficFromSamples([first,cur],at-30_000,at,undefined,undefined,true)
assert.equal(built.observations!.rxNow,nextIdentity===identity);assert.equal(built.rxTotalGiB,nextIdentity===identity?1000/1024**3:0)
}
console.log('native counter identity/config/legacy marker/pair guards passed')
@@ -15,8 +15,8 @@ else {
let serverId: number | undefined, counters: unknown = "1000", second = false, cases = 0, requests = 0
const http = createServer((req, res) => {
requests++; res.setHeader("Content-Type", "application/json")
const rows = [{ name: "ether1", running: "true", disabled: "false", "rx-byte": counters, "tx-byte": counters }]
if (second) rows.push({ name: "ether2", running: "true", disabled: "false", "rx-byte": "1000", "tx-byte": "1000" })
const rows = [{ ".id":"*1",name: "ether1", running: "true", disabled: "false", "rx-byte": counters, "tx-byte": counters }]
if (second) rows.push({ ".id":"*2",name: "ether2", running: "true", disabled: "false", "rx-byte": "1000", "tx-byte": "1000" })
res.end(JSON.stringify(req.url?.includes("/wireguard/") ? [] : rows))
})
await new Promise<void>(resolve => http.listen(0, "127.0.0.1", resolve))
@@ -1,5 +1,6 @@
import {parseTrafficPeers} from "./traffic-peer-observation.js"
import assert from "node:assert/strict"
import { observedTrafficRate, parseTrafficCounter, parseTrafficFlag } from "./traffic-observation.js"
import { observedTrafficRate, parseTrafficCounter, parseTrafficFlag, nativeTrafficCounterIdentity } from "./traffic-observation.js"
import { collectSourceSignals } from "./alert-engine/collector-source-signals.js"
import fs from "node:fs"
import vm from "node:vm"
@@ -38,18 +39,18 @@ const ast = ts.createSourceFile("traffic-collector.ts", collector, ts.ScriptTarg
const functions = ast.statements.filter(n => ts.isFunctionDeclaration(n) && n.name &&
["waveKey", "sampleRate", "toNum", "collectTrafficOnce"].includes(n.name.text)).map(n => n.getText(ast)).join("\n")
assert.equal(ast.statements.filter(n => ts.isFunctionDeclaration(n) && n.name && n.name.text === "collectTrafficOnce").length, 1)
let inserted: unknown[] = [], wave = new Map<string, typeof previous>(), counters: unknown = "1000"
let inserted: unknown[] = [], wave = new Map<string, typeof previous & {nativeCounterIdentity?:string|null}>(), counters: unknown = "1000"
let included = true
const context = vm.createContext({
Date, observedTrafficRate, parseTrafficCounter, parseTrafficFlag, bpsToMbps, shouldIncludeIface,
Date, nativeTrafficCounterIdentity,parseTrafficPeers, observedTrafficRate, parseTrafficCounter, parseTrafficFlag, bpsToMbps, shouldIncludeIface,
SCHEDULER_RUN_SNAPSHOT_VERSION: 1, servers: {}, trafficSamples: {}, trafficSettings: {}, eq: () => ({}),
getSettingsRow: async () => ({}), readPreviousWave: async () => wave, rememberServerIfaces: () => {},
encodeTrafficFlags: () => 1,
recordTrafficCollectionAttempt: async () => {},
MikrotikClient: { fromServer: () => ({ get: async (path: string) => path === "/interface" ?
[{ name: "ether1", running: String(included), disabled: "false", "rx-byte": counters, "tx-byte": counters }] : [] }) },
[{ ".id":"*1",name: "ether1", running: String(included), disabled: "false", "rx-byte": counters, "tx-byte": counters }] : [] }) },
db: {
select: () => ({ from: () => ({ where: async () => [{ id: 1, name: "audit", host: "audit.example", enabled: true }] }) }),
select: () => ({ from: () => ({ where: async () => [{ updatedAt:iso,id: 1, name: "audit", host: "audit.example", enabled: true }] }) }),
insert: () => ({ values: async (rows: unknown[]) => { inserted.push(...rows) } }),
update: () => ({ set: () => ({ where: async () => {} }) }),
},
@@ -58,7 +59,7 @@ vm.runInContext(ts.transpileModule("let collecting=false;\n" + functions.replace
"\nglobalThis.run=collectTrafficOnce;", { compilerOptions: { target: ts.ScriptTarget.ES2022 } }).outputText, context)
let snapshot = await context.run()
assert.equal(snapshot.servers[0].ok, true); assert.equal(snapshot.servers[0].sumRxMbps, undefined); assert.equal(inserted.length, 1)
wave = new Map([["ether1\0", { ...previous, sampledAt: new Date(Date.now() - 30_000).toISOString() }]])
wave = new Map([["ether1\0", { ...previous, nativeCounterIdentity:nativeTrafficCounterIdentity(iso,"*1"),sampledAt: new Date(Date.now() - 30_000).toISOString() }]])
snapshot = await context.run(); assert.equal(snapshot.servers[0].sumRxMbps, 0)
counters = "10"; snapshot = await context.run(); assert.equal(snapshot.servers[0].sumRxMbps, undefined)
counters = "bad"; inserted = []; snapshot = await context.run()
@@ -1,4 +1,9 @@
import { rateBpsFromDelta } from "./traffic-rate.js"
export function nativeTrafficCounterIdentity(updatedAt: string | Date, nativeId: unknown): string | null {
const at = updatedAt instanceof Date ? updatedAt.getTime() : Date.parse(updatedAt)
if (!Number.isFinite(at) || typeof nativeId !== "string" || !/^\*[0-9a-f]+$/i.test(nativeId)) return null
return JSON.stringify([new Date(at).toISOString(), nativeId.toUpperCase()])
}
export function parseTrafficFlag(raw: unknown): boolean {
if (raw === true || raw === "true" || raw === "yes") return true
if (raw === false || raw === "false" || raw === "no") return false
@@ -13,6 +13,6 @@ export function parseTrafficPeers(raw: unknown) {
const key = `${interfaceName}\0${peerPublicKey}`
if (seen.has(key)) throw new Error("Повторное измерение WireGuard peer")
seen.add(key)
return { interfaceName, peerPublicKey, rxBytes: parseTrafficCounter(p.rx), txBytes: parseTrafficCounter(p.tx), disabled: parseTrafficFlag(p.disabled) }
return { interfaceName, peerPublicKey, nativeId: p[".id"], rxBytes: parseTrafficCounter(p.rx), txBytes: parseTrafficCounter(p.tx), disabled: parseTrafficFlag(p.disabled) }
})
}
+4 -1
View File
@@ -14,6 +14,8 @@ export interface TrafficSampleLike {
running: boolean
disabled: boolean
countersKnown?: boolean
continuityKnown?: boolean
nativeCounterIdentity?: string | null
}
export interface RatePoint {
@@ -180,7 +182,8 @@ export function buildTrafficFromSamples(
const t0 = parseIsoMs(prev.sampledAt)
const t1 = parseIsoMs(cur.sampledAt)
if(Number.isFinite(Date.parse(cur.sampledAt))&&t1>=rangeStartMs&&t1<=rangeEndMs)lastAttemptAt=Math.max(lastAttemptAt??t1,t1)
const countersKnown = prev.countersKnown !== false && cur.countersKnown !== false
const sameIdentity = (prev.nativeCounterIdentity ?? null) === (cur.nativeCounterIdentity ?? null)
const countersKnown = prev.countersKnown !== false && cur.countersKnown !== false && cur.continuityKnown !== false && sameIdentity
const rxBps = countersKnown ? rateBpsFromDelta(prev.rxBytes, cur.rxBytes, t0, t1) : null
const txBps = countersKnown ? rateBpsFromDelta(prev.txBytes, cur.txBytes, t0, t1) : null
if (t1 >= rangeStartMs && t1 <= rangeEndMs) {
@@ -9,8 +9,8 @@ const database=process.env.MMAPP_OWN_SQL_DB
if(!database)console.log("traffic status SQL: skipped; explicit owned database required")
else{
assert(/^mm_accept_166_\d+$/.test(database));assert.equal(new URL(process.env.DATABASE_URL!).pathname,"/"+database);assert.equal((await pool.query("SELECT current_database() AS name")).rows[0].name,database)
const prefix="own-status181-"+Date.now()+"-",userId=prefix+"user";let serverId:number|undefined,cases=0,deny=false,flag:unknown=true,peerDisabled=false,peerVariant="valid",denyPeer=false
const http=createServer((req,res)=>{res.setHeader("Content-Type","application/json");if(deny || denyPeer && req.url?.includes("/wireguard/")){res.statusCode=401;return res.end('{"message":"Unauthorized"}')}res.end(JSON.stringify(req.url?.includes("/wireguard/")?(peerVariant==="shape"?{}:peerVariant==="duplicate"?[{interface:"wg1","public-key":"fixturekey",rx:"1000",tx:"1000",disabled:false},{interface:"wg1","public-key":"fixturekey",rx:"1000",tx:"1000",disabled:false}]:[{interface:"wg1","public-key":"fixturekey",rx:"1000",tx:"1000",disabled:peerDisabled},...(peerVariant==="partial"?[{interface:"wg1","public-key":"broken",rx:"invalid",tx:"1000",disabled:false}]:[])]):[{name:"ether1",running:flag,disabled:false,"rx-byte":"1000","tx-byte":"1000"}]))})
const prefix="own-status181-"+Date.now()+"-",userId=prefix+"user";let serverId:number|undefined,cases=0,deny=false,flag:unknown=true,peerDisabled=false,peerVariant="valid",denyPeer=false,ifaceId:unknown="*1",counterValue="1000",peerId="*2",peerCounter="1000"
const http=createServer((req,res)=>{res.setHeader("Content-Type","application/json");if(deny || denyPeer && req.url?.includes("/wireguard/")){res.statusCode=401;return res.end('{"message":"Unauthorized"}')}res.end(JSON.stringify(req.url?.includes("/wireguard/")?(peerVariant==="shape"?{}:peerVariant==="duplicate"?[{".id":peerId,interface:"wg1","public-key":"fixturekey",rx:"1000",tx:"1000",disabled:false},{".id":peerId,interface:"wg1","public-key":"fixturekey",rx:"1000",tx:"1000",disabled:false}]:[{".id":peerId,interface:"wg1","public-key":"fixturekey",rx:peerCounter,tx:peerCounter,disabled:peerDisabled},...(peerVariant==="partial"?[{".id":peerId,interface:"wg1","public-key":"broken",rx:"invalid",tx:"1000",disabled:false}]:[])]):[{".id":ifaceId,name:"ether1",running:flag,disabled:false,"rx-byte":counterValue,"tx-byte":counterValue}]))})
await new Promise<void>(resolve=>http.listen(0,"127.0.0.1",resolve));const address=http.address();assert(address&&typeof address==="object");const app=Fastify();await app.register(trafficRoutes)
const bindings=async()=>{const r=await app.inject({method:"GET",url:"/traffic/bound-interfaces?range=1h"});assert.equal(r.statusCode,200);return r.json().interfaces.filter((i:{userId:string})=>i.userId===userId)}
try{
@@ -39,6 +39,14 @@ else{
await pool.query("UPDATE traffic_samples SET sampled_at=$1 WHERE server_id=$2",[new Date(Date.now()-120_000).toISOString(),serverId]);
let gap=await collectTrafficOnce();assert.equal(gap.servers[0].ok,true);assert.equal(gap.servers[0].sumRxMbps,undefined);rows=await bindings();assert.equal(rows.find((r:{interfaceName:string})=>r.interfaceName==="ether1").observations.rxNow,false);
gap=await collectTrafficOnce();assert.equal(gap.servers[0].sumRxMbps,0);rows=await bindings();assert.equal(rows.find((r:{interfaceName:string})=>r.interfaceName==="ether1").observations.rxNow,true);cases++;
for(const change of["native-id","config","missing-id"]){
counterValue=String(Number(counterValue)+1000);
if(change==="native-id")ifaceId="*10";else if(change==="missing-id")ifaceId=undefined;else await pool.query("UPDATE servers SET updated_at=$1 WHERE id=$2",[new Date().toISOString(),serverId]);
const switched=await collectTrafficOnce();assert.equal(switched.servers[0].sumRxMbps,undefined);rows=await bindings();assert.equal(rows.find((r:{interfaceName:string})=>r.interfaceName==="ether1").observations.rxNow,false);assert.equal(rows.find((r:{interfaceName:string})=>r.interfaceName==="ether1").rxTotal,0);cases++;
if(change!=="missing-id"){const next=await collectTrafficOnce();assert.equal(next.servers[0].sumRxMbps,0);rows=await bindings();assert.equal(rows.find((r:{interfaceName:string})=>r.interfaceName==="ether1").observations.rxNow,true)}
}
ifaceId="*10";await collectTrafficOnce();await collectTrafficOnce();peerId="*20";peerCounter="2000";await collectTrafficOnce();rows=await bindings();let peer=rows.find((r:{interfaceName:string})=>r.interfaceName==="wg1");assert.equal(peer.observations.rxNow,false);assert.equal(peer.rxTotal,0);
await collectTrafficOnce();rows=await bindings();peer=rows.find((r:{interfaceName:string})=>r.interfaceName==="wg1");assert.equal(peer.observations.rxNow,true);assert.equal(peer.rxNow,0);cases++;
await pool.query("UPDATE servers SET enabled=false WHERE id=$1",[serverId]);rows=await bindings();assert(rows.every((r:{status:string})=>r.status==="unknown"));cases++
console.log(`traffic status owned SQL: ${cases} cases; first-wave native flags/peer config/invalid/error/legacy/stale/disabled passed`)
}finally{await app.close();await new Promise<void>(resolve=>http.close(()=>resolve()));await pool.query("DELETE FROM app_users WHERE id=$1",[userId]);if(serverId!==undefined){await pool.query("DELETE FROM traffic_samples WHERE server_id=$1",[serverId]);await pool.query("DELETE FROM servers WHERE id=$1",[serverId])}await closePool()}