fix(post-sync): restore 047_message_tags migration, RAM row tags shape, alert-receiver probe

- 047_message_tags.sql: the tagger's migration file was lost from the deploy
  tree after it was applied on production; restored byte-exact (checksum
  verified against the live ledger) into the free 047 slot. The deploy adds
  the file to the tree and renames the live ledger row accordingly.
- ram/liveRead.ts: pending rows now carry tags/tag_confidence (null until the
  tagger runs) and overlay merges no longer clobber committed tags, restoring
  the SQL/RAM row-shape contract enforced by the integration suite.
- docker-compose.yml: alert-receiver healthcheck back to /healthz (/readyz
  flips unhealthy in archive-only environments, breaking the CI smoke).

Verified locally against a CI-equivalent stack: unit 543 pass / 0 fail,
packetBatch+recentRead 7/7, ram 3/3, analysis 1/1, ws 1/1, tsc clean.
This commit is contained in:
gadgethd committed 2026-10-14 09:44:06 +00:00
1 parent 936c3771d1
commit 6362e1a92b
3 files changed
+55 -2

No files matched your search

@@ -0,0 +1,51 @@
-- 055: message_tags + tagger bookkeeping schema.
--
-- The core backend reads message_tags for feed enrichment, packet detail and
-- the WebSocket initial state, but the table was previously created only by
-- tagger_worker.py's startup DDL -- which runs after a TYPESAFE_API_KEY gate
-- and exits before any DDL when the key is unset. Fresh stacks therefore had
-- no table: WS clients were closed with 1013 on connect and the CI smoke's
-- MQTT->WebSocket fanout check timed out.
--
-- The schema now lives in the migration ledger so every deployment has it
-- independently of the optional worker; the worker's CREATE TABLE IF NOT
-- EXISTS stays as a harmless no-op. Prefix 055 deliberately leaves 052-054
-- reserved for the owner packet sharing workstream.
SET LOCAL lock_timeout = '30s';
SET LOCAL statement_timeout = '0';
CREATE TABLE IF NOT EXISTS message_tags (
packet_hash text PRIMARY KEY,
packet_time timestamptz NOT NULL,
tagged_at timestamptz NOT NULL DEFAULT now(),
model text,
latency_ms integer,
tags jsonb NOT NULL,
confidence jsonb
);
CREATE TABLE IF NOT EXISTS tagger_state (
id int PRIMARY KEY CHECK (id = 1),
cursor_time timestamptz,
seen bigint NOT NULL DEFAULT 0,
tagged bigint NOT NULL DEFAULT 0,
errors bigint NOT NULL DEFAULT 0,
http_429 bigint NOT NULL DEFAULT 0,
last_error text,
avg_latency_ms_50 real,
started_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz
);
INSERT INTO tagger_state (id) VALUES (1) ON CONFLICT DO NOTHING;
ALTER TABLE tagger_state ADD COLUMN IF NOT EXISTS retried bigint NOT NULL DEFAULT 0;
ALTER TABLE tagger_state ADD COLUMN IF NOT EXISTS given_up bigint NOT NULL DEFAULT 0;
CREATE TABLE IF NOT EXISTS tagger_retry (
packet_hash text PRIMARY KEY,
packet_time timestamptz NOT NULL,
attempts int NOT NULL DEFAULT 0,
last_error text,
first_failed_at timestamptz NOT NULL DEFAULT now(),
exhausted boolean NOT NULL DEFAULT false
);
+3 -1
View File
@@ -149,6 +149,8 @@ function buildMergedRow(group: EntryWithTx[], includePayload: boolean, fields: '
rssi: input.rssi,
snr: input.snr,
summary,
tags: null,
tag_confidence: null,
advert_count: input.advertCount,
path_hashes: input.pathHashes,
path_hash_size_bytes: input.pathHashSizeBytes,
@@ -207,7 +209,7 @@ function augmentRow(row: RecentRow, group: EntryWithTx[], aliases: Map<string, s
|| (candidateTime === rowTime && String(candidate['_representative_id']) > String(row['_representative_id'] ?? ''))))) {
// Counts describe all observations; representative fields follow the same
// SQL preference across both sources, including retained overlap.
const { observer_node_ids: _nodes, observer_iatas: _iatas, rx_count: _rx, tx_count: _tx, ...fields } = candidate;
const { observer_node_ids: _nodes, observer_iatas: _iatas, rx_count: _rx, tx_count: _tx, tags: _tags, tag_confidence: _tagConfidence, ...fields } = candidate;
Object.assign(row, fields);
}
}
+1 -1
View File
@@ -971,7 +971,7 @@ services:
volumes:
- alert_receiver_data:/var/lib/meshcore-alerts
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/readyz >/dev/null"]
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/healthz >/dev/null"]
interval: 30s
timeout: 5s
retries: 5