First public release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Where a finding came from.
|
||||
*
|
||||
* The rule this type exists to enforce: a finding names the artefact that
|
||||
* produced it. SideDoor already did this — it prints the service, the port
|
||||
* binding and the compose file — and it is noticeably the most useful of these
|
||||
* outputs to read. A result that is asserted without a source leaves the
|
||||
* reader to take it on trust, and an unverified claim should count as absent.
|
||||
*/
|
||||
|
||||
/** A location in source or configuration. */
|
||||
export interface FileEvidence {
|
||||
kind: 'file'
|
||||
path: string
|
||||
/** 1-indexed. Omitted when the finding is about the file as a whole. */
|
||||
line?: number
|
||||
/** The matched text. Keep it short — one line, trimmed. */
|
||||
excerpt?: string
|
||||
}
|
||||
|
||||
/** A row in a database. */
|
||||
export interface RecordEvidence {
|
||||
kind: 'record'
|
||||
table: string
|
||||
id: string
|
||||
/** The column that carried the value the finding turns on. */
|
||||
field?: string
|
||||
value?: string
|
||||
}
|
||||
|
||||
/** Output of a command that was actually run. */
|
||||
export interface CommandEvidence {
|
||||
kind: 'command'
|
||||
command: string
|
||||
exitCode?: number
|
||||
excerpt?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* A number that was measured, together with how much data stood behind it.
|
||||
*
|
||||
* `samples` is not decoration. An availability of 100% over zero samples and
|
||||
* an availability of 100% over 8,640 samples are different claims, and only
|
||||
* one of them is evidence.
|
||||
*/
|
||||
export interface MeasurementEvidence {
|
||||
kind: 'measurement'
|
||||
metric: string
|
||||
/** Null when it could not be computed. Never substitute a flattering default. */
|
||||
value: number | null
|
||||
unit?: string
|
||||
samples: number
|
||||
/** e.g. "2026-07-01 → 2026-07-31". */
|
||||
window?: string
|
||||
}
|
||||
|
||||
/** A written source: a policy, a standard, a control catalogue. */
|
||||
export interface DocumentEvidence {
|
||||
kind: 'document'
|
||||
title: string
|
||||
section?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
export type EvidenceSource =
|
||||
| FileEvidence
|
||||
| RecordEvidence
|
||||
| CommandEvidence
|
||||
| MeasurementEvidence
|
||||
| DocumentEvidence
|
||||
|
||||
export interface Evidence {
|
||||
source: EvidenceSource
|
||||
/** ISO 8601. When the observation was made, if the caller tracks it. */
|
||||
observedAt?: string
|
||||
/** One line on why this artefact supports the finding. */
|
||||
note?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* A short, copy-pasteable citation — the thing a reader scans for.
|
||||
*
|
||||
* Formats follow the conventions each kind is already read in: `path:line`
|
||||
* for source (clickable in most terminals), `table#id` for rows.
|
||||
*/
|
||||
export function cite(e: Evidence): string {
|
||||
const s = e.source
|
||||
switch (s.kind) {
|
||||
case 'file':
|
||||
return s.line ? `${s.path}:${s.line}` : s.path
|
||||
case 'record':
|
||||
return s.field ? `${s.table}#${s.id} (${s.field})` : `${s.table}#${s.id}`
|
||||
case 'command':
|
||||
return s.exitCode === undefined ? `$ ${s.command}` : `$ ${s.command} → exit ${s.exitCode}`
|
||||
case 'measurement': {
|
||||
const v = s.value === null ? 'not computable' : `${s.value}${s.unit ?? ''}`
|
||||
const n = `${s.samples} sample${s.samples === 1 ? '' : 's'}`
|
||||
return s.window ? `${s.metric} = ${v} (${n}, ${s.window})` : `${s.metric} = ${v} (${n})`
|
||||
}
|
||||
case 'document':
|
||||
return s.section ? `${s.title} § ${s.section}` : s.title
|
||||
}
|
||||
}
|
||||
|
||||
/** Longer form: the citation plus whatever context was attached to it. */
|
||||
export function citeVerbose(e: Evidence): string[] {
|
||||
const out = [cite(e)]
|
||||
const s = e.source
|
||||
if ((s.kind === 'file' || s.kind === 'command') && s.excerpt) out.push(` ${s.excerpt.trim()}`)
|
||||
if (s.kind === 'record' && s.value !== undefined) out.push(` value: ${s.value}`)
|
||||
if (e.note) out.push(` ${e.note}`)
|
||||
return out
|
||||
}
|
||||
|
||||
/** Convenience constructors, so call sites stay one line. */
|
||||
export const evidence = {
|
||||
file(path: string, line?: number, excerpt?: string, note?: string): Evidence {
|
||||
return { source: { kind: 'file', path, line, excerpt }, note }
|
||||
},
|
||||
record(table: string, id: string, field?: string, value?: string, note?: string): Evidence {
|
||||
return { source: { kind: 'record', table, id, field, value }, note }
|
||||
},
|
||||
command(command: string, exitCode?: number, excerpt?: string, note?: string): Evidence {
|
||||
return { source: { kind: 'command', command, exitCode, excerpt }, note }
|
||||
},
|
||||
measurement(
|
||||
metric: string,
|
||||
value: number | null,
|
||||
samples: number,
|
||||
opts: { unit?: string, window?: string, note?: string } = {},
|
||||
): Evidence {
|
||||
return {
|
||||
source: { kind: 'measurement', metric, value, samples, unit: opts.unit, window: opts.window },
|
||||
note: opts.note,
|
||||
}
|
||||
},
|
||||
document(title: string, section?: string, url?: string, note?: string): Evidence {
|
||||
return { source: { kind: 'document', title, section, url }, note }
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a measurement out loud, including the case where there is nothing to
|
||||
* read.
|
||||
*
|
||||
* `uptime null, met=false` was correct and unreadable. A reader should not
|
||||
* have to know that zero samples is not 100% in order to understand the line.
|
||||
*/
|
||||
export function describeMeasurement(s: MeasurementEvidence): string {
|
||||
if (s.samples === 0) {
|
||||
return `No samples for ${s.metric}${s.window ? ` in ${s.window}` : ''}; it cannot be computed.`
|
||||
}
|
||||
if (s.value === null) {
|
||||
return `${s.metric} could not be computed from the ${s.samples} available sample${s.samples === 1 ? '' : 's'}.`
|
||||
}
|
||||
return `${s.metric} is ${s.value}${s.unit ?? ''} over ${s.samples} sample${s.samples === 1 ? '' : 's'}${s.window ? ` (${s.window})` : ''}.`
|
||||
}
|
||||
Reference in New Issue
Block a user