moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
/**
* Canonical risk / approval / audit taxonomy (P7/D15 Track A, binding A1).
*
* Before this module the vocabulary was redeclared in five places that had
* drifted apart — trust-model.ts (RiskLevel without 'critical'), confirmation.ts
* (a hardcoded ApprovalClass mapper), install-audit.ts (the widest set, plus a
* hand-duplicated SQLite CHECK in hive-mind-core/schema.ts), and
* team-capability-governance.ts (a 4th set keyed on 'none'). A producer narrower
* than its store meant a `critical` risk could only ever be hand-written, and the
* FE modal couldn't represent the `critical`/`blocked` levels the audit recorded.
*
* This is the SINGLE SOURCE. Each enum is the WIDEST of the prior sets so no
* producer/store mismatch remains. Every other module imports from here.
*
* Two axes, one rule:
* - `RiskLevel` = how dangerous the action is (severity → display colour).
* - `ApprovalClass` = how strongly to gate it (standard < elevated < critical < blocked).
* They are NOT the same axis; surfaces that collapsed them must keep them distinct.
*
* Each type is derived from a runtime `const` array so the array can also drive
* the SQLite CHECK constraints (A3) and parity tests, with zero chance of the
* type and the value list drifting.
*/
/** Severity of an action. Widest prior set = install-audit's (adds 'critical'). */
export const RISK_LEVELS = ['low', 'medium', 'high', 'critical'] as const;
export type RiskLevel = (typeof RISK_LEVELS)[number];
/** Gating strength. Widest prior set = install-audit's (adds 'blocked'). */
export const APPROVAL_CLASSES = ['standard', 'elevated', 'critical', 'blocked'] as const;
export type ApprovalClass = (typeof APPROVAL_CLASSES)[number];
/** Provenance of a capability. Widest prior set = install-audit's (adds 'security-gate'). */
export const TRUST_SOURCES = [
'builtin', // First-party, ships with Waggle
'starter_pack', // Curated starter skills
'local_user', // User-created via create_skill
'third_party_verified', // Verified registry
'third_party_unverified', // Unknown registry source
'unknown', // No provenance information
'security-gate', // Set by the SecurityGate scan (blocked/flagged)
] as const;
export type TrustSource = (typeof TRUST_SOURCES)[number];
/** How a risk assessment was derived. */
export const ASSESSMENT_MODES = ['declared', 'heuristic', 'mixed'] as const;
export type AssessmentMode = (typeof ASSESSMENT_MODES)[number];
/** Lifecycle action recorded in install_audit. Includes 'uninstalled' (P5/D4). */
export const AUDIT_ACTIONS = [
'proposed', 'approved', 'installed', 'rejected', 'failed', 'blocked', 'uninstalled',
] as const;
export type AuditAction = (typeof AUDIT_ACTIONS)[number];
/** Kind of capability an audit row concerns. */
export const AUDIT_CAPABILITY_TYPES = [
'native', 'skill', 'plugin', 'mcp', 'connector', 'marketplace',
] as const;
export type AuditCapabilityType = (typeof AUDIT_CAPABILITY_TYPES)[number];
/** Who initiated an audited action. */
export const AUDIT_INITIATORS = ['agent', 'user', 'system'] as const;
export type AuditInitiator = (typeof AUDIT_INITIATORS)[number];
/** Ascending severity order — index = rank. Used to compare/sort risk levels so a
* `critical` always outranks `low` (the team-governance bug was a `?? 0` that
* sorted `critical` BELOW `low`). */
export function riskRank(level: RiskLevel): number {
return RISK_LEVELS.indexOf(level);
}
/** True when `level` meets or exceeds `threshold` on the canonical severity scale. */
export function riskAtLeast(level: RiskLevel, threshold: RiskLevel): boolean {
return riskRank(level) >= riskRank(threshold);
}
/** Build a SQLite `CHECK (col IN (...))` clause body from a const value list, so
* the DDL constraint and the TS union can never drift (A3 single-sources both
* install-audit.ts and hive-mind-core/schema.ts from these arrays). */
export function sqlInList(values: readonly string[]): string {
return values.map((v) => `'${v}'`).join(', ');
}