23 lines
1.6 KiB
TypeScript
Executable File
23 lines
1.6 KiB
TypeScript
Executable File
import { z } from 'zod';
|
|
const nonnegative=z.number().finite().nonnegative();
|
|
const schema=z.object({schema:z.literal('wikideck-operations-v1'),observedAt:z.string().datetime(),
|
|
native:z.object({available:z.boolean(),queued:nonnegative}),
|
|
ledger:z.object({height:nonnegative,mutationQueue:nonnegative,tipAgeSeconds:nonnegative.nullable()}),
|
|
peers:z.object({configured:nonnegative,connected:nonnegative}),
|
|
eventLoop:z.object({meanMs:nonnegative}),disk:z.unknown(),diskSampledAt:nonnegative.nullable()});
|
|
export function checkOperations(raw:unknown,now=Date.now()){
|
|
const s=schema.parse(raw),warnings:string[]=[];
|
|
const observation=Date.parse(s.observedAt);
|
|
if(Math.abs(now-observation)>60000)warnings.push('diagnostics-clock-or-freshness');
|
|
if(!s.native.available)warnings.push('native-engine-unavailable');
|
|
if(s.native.queued>=48||s.ledger.mutationQueue>=192)warnings.push('queue-pressure');
|
|
if(!s.peers.configured||!s.peers.connected)warnings.push('peer-isolation');
|
|
if(s.ledger.height===0||s.ledger.tipAgeSeconds===null||s.ledger.tipAgeSeconds>3600)warnings.push('empty-or-stale-chain');
|
|
if(s.eventLoop.meanMs>250)warnings.push('event-loop-delay');
|
|
const disk=z.object({availableBytes:nonnegative}).safeParse(s.disk);
|
|
if(!disk.success||!s.diskSampledAt||now-s.diskSampledAt>90000)warnings.push('disk-sample-unavailable-or-stale');
|
|
else if(disk.data.availableBytes<512*1024*1024)warnings.push('disk-low');
|
|
return {healthy:warnings.length===0,warnings,
|
|
note:'Local threshold hints only, not consensus readiness or launch approval. Reorg/rejection counters and native RSS need external time-series monitoring.'};
|
|
}
|