feat(snapshot): plausibilitaets-checks (relay-quorum, drop, min-events)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ccd7daf14d
commit
7e38b73785
|
|
@ -0,0 +1,36 @@
|
||||||
|
export interface CheckInput {
|
||||||
|
relaysQueried: number
|
||||||
|
relaysResponded: number
|
||||||
|
eventCount: number
|
||||||
|
minEvents: number
|
||||||
|
lastKnownGoodCount: number | undefined
|
||||||
|
newDeletionsCount: number
|
||||||
|
allowShrink: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runChecks(input: CheckInput): void {
|
||||||
|
const quorum = Math.ceil(input.relaysQueried * 0.6)
|
||||||
|
if (input.relaysResponded < quorum) {
|
||||||
|
throw new Error(
|
||||||
|
`Relay-Quorum nicht erreicht: ${input.relaysResponded}/${input.relaysQueried} ` +
|
||||||
|
`(brauche mindestens ${quorum})`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (input.eventCount < input.minEvents) {
|
||||||
|
throw new Error(
|
||||||
|
`Event-Count ${input.eventCount} unter min-events ${input.minEvents}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (input.lastKnownGoodCount !== undefined && !input.allowShrink) {
|
||||||
|
const drop = input.lastKnownGoodCount - input.eventCount
|
||||||
|
const dropPct = drop / input.lastKnownGoodCount
|
||||||
|
if (dropPct > 0.2 && drop > input.newDeletionsCount) {
|
||||||
|
throw new Error(
|
||||||
|
`Event-Count-Drop ${drop} (${(dropPct * 100).toFixed(0)}%) gegenueber ` +
|
||||||
|
`last-known-good ${input.lastKnownGoodCount}, ` +
|
||||||
|
`nur ${input.newDeletionsCount} korrespondierende kind:5. ` +
|
||||||
|
`Override mit --allow-shrink falls bewusst.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { assertEquals, assertThrows } from '@std/assert'
|
||||||
|
import { runChecks } from '../src/core/checks.ts'
|
||||||
|
|
||||||
|
Deno.test('runChecks: weniger als 60% relays geantwortet -> hard-fail', () => {
|
||||||
|
assertThrows(
|
||||||
|
() => runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 2,
|
||||||
|
eventCount: 27, minEvents: 1, lastKnownGoodCount: undefined,
|
||||||
|
newDeletionsCount: 0, allowShrink: false,
|
||||||
|
}),
|
||||||
|
Error, 'Relay-Quorum',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('runChecks: event-count unter min-events -> hard-fail', () => {
|
||||||
|
assertThrows(
|
||||||
|
() => runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 5,
|
||||||
|
eventCount: 0, minEvents: 1, lastKnownGoodCount: undefined,
|
||||||
|
newDeletionsCount: 0, allowShrink: false,
|
||||||
|
}),
|
||||||
|
Error, 'min-events',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('runChecks: drop > 20% ohne kind:5 -> hard-fail', () => {
|
||||||
|
assertThrows(
|
||||||
|
() => runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 5,
|
||||||
|
eventCount: 20, minEvents: 1, lastKnownGoodCount: 27,
|
||||||
|
newDeletionsCount: 0, allowShrink: false,
|
||||||
|
}),
|
||||||
|
Error, 'Event-Count-Drop',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('runChecks: drop > 20% mit korrespondierenden kind:5 -> ok', () => {
|
||||||
|
runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 5,
|
||||||
|
eventCount: 20, minEvents: 1, lastKnownGoodCount: 27,
|
||||||
|
newDeletionsCount: 7, allowShrink: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('runChecks: --allow-shrink umgeht drop-check', () => {
|
||||||
|
runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 5,
|
||||||
|
eventCount: 1, minEvents: 1, lastKnownGoodCount: 27,
|
||||||
|
newDeletionsCount: 0, allowShrink: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Deno.test('runChecks: erstlauf ohne cache + min-events=1 -> ok', () => {
|
||||||
|
runChecks({
|
||||||
|
relaysQueried: 5, relaysResponded: 5,
|
||||||
|
eventCount: 1, minEvents: 1, lastKnownGoodCount: undefined,
|
||||||
|
newDeletionsCount: 0, allowShrink: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue