Retain completed status batches as routine observations

This commit is contained in:
2026-10-05 16:18:24 -04:00
parent ae703617af
commit 1d9e518feb
7 changed files with 60 additions and 9 deletions
+6 -2
View File
@@ -11,7 +11,9 @@ export function safeOperationTarget(kind: string, value: string | null): string
export function successfulObservation(kind: string, payload: Record<string, unknown>, result: unknown): boolean {
const routine = observationKinds.includes(kind) || kind === 'rcon.execute' && commands.includes(String(payload.command));
const value = result && typeof result === 'object' ? result as Record<string, unknown> : {};
return routine && value.ok !== false && value.healthy !== false && (value.error == null || value.error === '');
// Older agents set ok=false when any target fails, despite completing the batch.
const completedBatch = kind === 'rcon.status-batch' && Array.isArray(value.results);
return routine && (completedBatch || value.ok !== false) && value.healthy !== false && (value.error == null || value.error === '');
}
/** Uses the operation alias o; serialized payloads may live outside the routing row. */
@@ -22,7 +24,9 @@ export const routineObservationSql = `(CASE WHEN o.kind IN (${observationKinds.m
export const successfulObservationSql = `(o.state='completed' AND COALESCE(o.error,'')='' AND ${routineObservationSql}
AND CASE WHEN o.result IS NULL THEN 1 WHEN json_valid(o.result)
THEN json_extract(o.result,'$.ok') IS NOT 0 AND json_extract(o.result,'$.healthy') IS NOT 0
THEN (json_extract(o.result,'$.ok') IS NOT 0
OR (o.kind='rcon.status-batch' AND json_type(o.result,'$.results')='array'))
AND json_extract(o.result,'$.healthy') IS NOT 0
AND COALESCE(json_extract(o.result,'$.error'),'')='' ELSE 0 END)`;
export const importantOperationSql = `(o.routine=0 OR o.state IN ('failed','unknown')
+9
View File
@@ -112,6 +112,15 @@ export function ensureHostSchema(handle: Database.Database): void {
handle.exec(`CREATE INDEX IF NOT EXISTS ec_host_operations_routine_history ON ec_host_operations(routine,created_at);
CREATE INDEX IF NOT EXISTS ec_host_operations_important_history ON ec_host_operations(created_at)
WHERE ${importantOperationSql.replaceAll('o.', '')}`);
handle.exec('CREATE TABLE IF NOT EXISTS ec_host_schema_migrations (name TEXT PRIMARY KEY)');
if (!handle.prepare('SELECT 1 FROM ec_host_schema_migrations WHERE name=?').get('completed-status-batches')) {
handle.transaction(() => {
// Reclassify existing completed batches without discarding their per-server replies.
handle.exec(`UPDATE ec_host_operations AS o SET observation_success=1
WHERE o.kind='rcon.status-batch' AND o.observation_success=0 AND ${successfulObservationSql}`);
handle.prepare('INSERT INTO ec_host_schema_migrations(name) VALUES(?)').run('completed-status-batches');
})();
}
const hostColumns = handle.prepare('PRAGMA table_info(ec_hosts)').all() as { name: string }[];
if (!hostColumns.some(column => column.name === 'deleted_at')) handle.exec('ALTER TABLE ec_hosts ADD COLUMN deleted_at TEXT');
const allowanceColumns = handle.prepare('PRAGMA table_info(ec_resource_allowances)').all() as { name: string }[];