usertrust 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/canonical.d.ts +7 -0
- package/dist/audit/canonical.d.ts.map +1 -0
- package/dist/audit/canonical.js +24 -0
- package/dist/audit/canonical.js.map +1 -0
- package/dist/audit/chain.d.ts +33 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +285 -0
- package/dist/audit/chain.js.map +1 -0
- package/dist/audit/entropy.d.ts +95 -0
- package/dist/audit/entropy.d.ts.map +1 -0
- package/dist/audit/entropy.js +229 -0
- package/dist/audit/entropy.js.map +1 -0
- package/dist/audit/merkle.d.ts +87 -0
- package/dist/audit/merkle.d.ts.map +1 -0
- package/dist/audit/merkle.js +315 -0
- package/dist/audit/merkle.js.map +1 -0
- package/dist/audit/rotation.d.ts +61 -0
- package/dist/audit/rotation.d.ts.map +1 -0
- package/dist/audit/rotation.js +160 -0
- package/dist/audit/rotation.js.map +1 -0
- package/dist/audit/verify.d.ts +20 -0
- package/dist/audit/verify.d.ts.map +1 -0
- package/dist/audit/verify.js +73 -0
- package/dist/audit/verify.js.map +1 -0
- package/dist/board/board.d.ts +67 -0
- package/dist/board/board.d.ts.map +1 -0
- package/dist/board/board.js +191 -0
- package/dist/board/board.js.map +1 -0
- package/dist/board/concerns.d.ts +59 -0
- package/dist/board/concerns.d.ts.map +1 -0
- package/dist/board/concerns.js +149 -0
- package/dist/board/concerns.js.map +1 -0
- package/dist/board/director.d.ts +49 -0
- package/dist/board/director.d.ts.map +1 -0
- package/dist/board/director.js +127 -0
- package/dist/board/director.js.map +1 -0
- package/dist/cli/health.d.ts +8 -0
- package/dist/cli/health.d.ts.map +1 -0
- package/dist/cli/health.js +119 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/init.d.ts +8 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +67 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/inspect.d.ts +8 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +114 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +35 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/snapshot.d.ts +10 -0
- package/dist/cli/snapshot.d.ts.map +1 -0
- package/dist/cli/snapshot.js +61 -0
- package/dist/cli/snapshot.js.map +1 -0
- package/dist/cli/tb.d.ts +8 -0
- package/dist/cli/tb.d.ts.map +1 -0
- package/dist/cli/tb.js +43 -0
- package/dist/cli/tb.js.map +1 -0
- package/dist/cli/verify.d.ts +7 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +32 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +18 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +49 -0
- package/dist/detect.js.map +1 -0
- package/dist/govern.d.ts +75 -0
- package/dist/govern.d.ts.map +1 -0
- package/dist/govern.js +581 -0
- package/dist/govern.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/client.d.ts +89 -0
- package/dist/ledger/client.d.ts.map +1 -0
- package/dist/ledger/client.js +417 -0
- package/dist/ledger/client.js.map +1 -0
- package/dist/ledger/engine.d.ts +68 -0
- package/dist/ledger/engine.d.ts.map +1 -0
- package/dist/ledger/engine.js +142 -0
- package/dist/ledger/engine.js.map +1 -0
- package/dist/ledger/pricing.d.ts +35 -0
- package/dist/ledger/pricing.d.ts.map +1 -0
- package/dist/ledger/pricing.js +142 -0
- package/dist/ledger/pricing.js.map +1 -0
- package/dist/memory/patterns.d.ts +35 -0
- package/dist/memory/patterns.d.ts.map +1 -0
- package/dist/memory/patterns.js +152 -0
- package/dist/memory/patterns.js.map +1 -0
- package/dist/policy/decay.d.ts +95 -0
- package/dist/policy/decay.d.ts.map +1 -0
- package/dist/policy/decay.js +133 -0
- package/dist/policy/decay.js.map +1 -0
- package/dist/policy/default-rules.d.ts +21 -0
- package/dist/policy/default-rules.d.ts.map +1 -0
- package/dist/policy/default-rules.js +60 -0
- package/dist/policy/default-rules.js.map +1 -0
- package/dist/policy/gate.d.ts +116 -0
- package/dist/policy/gate.d.ts.map +1 -0
- package/dist/policy/gate.js +227 -0
- package/dist/policy/gate.js.map +1 -0
- package/dist/policy/pii.d.ts +28 -0
- package/dist/policy/pii.d.ts.map +1 -0
- package/dist/policy/pii.js +124 -0
- package/dist/policy/pii.js.map +1 -0
- package/dist/proxy.d.ts +33 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +36 -0
- package/dist/proxy.js.map +1 -0
- package/dist/resilience/circuit.d.ts +87 -0
- package/dist/resilience/circuit.d.ts.map +1 -0
- package/dist/resilience/circuit.js +167 -0
- package/dist/resilience/circuit.js.map +1 -0
- package/dist/resilience/scope.d.ts +97 -0
- package/dist/resilience/scope.d.ts.map +1 -0
- package/dist/resilience/scope.js +244 -0
- package/dist/resilience/scope.js.map +1 -0
- package/dist/shared/constants.d.ts +7 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +7 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +31 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +61 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/ids.d.ts +7 -0
- package/dist/shared/ids.d.ts.map +1 -0
- package/dist/shared/ids.js +31 -0
- package/dist/shared/ids.js.map +1 -0
- package/dist/shared/types.d.ts +162 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +41 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/snapshot/checkpoint.d.ts +22 -0
- package/dist/snapshot/checkpoint.d.ts.map +1 -0
- package/dist/snapshot/checkpoint.js +172 -0
- package/dist/snapshot/checkpoint.js.map +1 -0
- package/dist/streaming.d.ts +44 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +123 -0
- package/dist/streaming.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Rotation — Daily receipt indexing
|
|
3
|
+
*
|
|
4
|
+
* Writes individual audit receipts to date-organized directories under
|
|
5
|
+
* the vault's audit directory. Maintains a bounded index.json for fast
|
|
6
|
+
* receipt lookup.
|
|
7
|
+
*
|
|
8
|
+
* Structure: .usertrust/audit/<kind>/<YYYY-MM-DD>/<receiptId>.json
|
|
9
|
+
*
|
|
10
|
+
* Adapted from Turf governance audit.ts (receipt emission + daily rotation).
|
|
11
|
+
*/
|
|
12
|
+
export interface AuditReceipt {
|
|
13
|
+
v: number;
|
|
14
|
+
ts: string;
|
|
15
|
+
kind: string;
|
|
16
|
+
subsystem: string;
|
|
17
|
+
actor: string;
|
|
18
|
+
correlationId?: string;
|
|
19
|
+
data: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface WriteReceiptInput {
|
|
22
|
+
kind: string;
|
|
23
|
+
subsystem: string;
|
|
24
|
+
actor: string;
|
|
25
|
+
correlationId?: string;
|
|
26
|
+
data: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export interface IndexEntry {
|
|
29
|
+
receiptId: string;
|
|
30
|
+
kind: string;
|
|
31
|
+
ts: string;
|
|
32
|
+
actor: string;
|
|
33
|
+
correlationId?: string;
|
|
34
|
+
path: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Write an audit receipt to the daily-rotated directory structure.
|
|
38
|
+
*
|
|
39
|
+
* @param vaultPath - Root vault directory (parent of .usertools/)
|
|
40
|
+
* @param input - Receipt data to write
|
|
41
|
+
* @param indexLimit - Maximum index entries (default: 10000)
|
|
42
|
+
* @returns The written receipt, or undefined if the write failed
|
|
43
|
+
*/
|
|
44
|
+
export declare function writeReceipt(vaultPath: string, input: WriteReceiptInput, indexLimit?: number): AuditReceipt | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* List all receipts of a given kind (optionally filtered by date).
|
|
47
|
+
*
|
|
48
|
+
* @param vaultPath - Root vault directory
|
|
49
|
+
* @param kind - Receipt kind to list
|
|
50
|
+
* @param date - Optional date filter (YYYY-MM-DD)
|
|
51
|
+
* @returns Array of receipts, sorted newest-first
|
|
52
|
+
*/
|
|
53
|
+
export declare function listReceipts(vaultPath: string, kind: string, date?: string): AuditReceipt[];
|
|
54
|
+
/**
|
|
55
|
+
* Load the audit index.
|
|
56
|
+
*
|
|
57
|
+
* @param vaultPath - Root vault directory
|
|
58
|
+
* @returns Array of index entries
|
|
59
|
+
*/
|
|
60
|
+
export declare function loadIndex(vaultPath: string): IndexEntry[];
|
|
61
|
+
//# sourceMappingURL=rotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation.d.ts","sourceRoot":"","sources":["../../src/audit/rotation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,MAAM,WAAW,YAAY;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACb;AA4CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC3B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,iBAAiB,EACxB,UAAU,SAAS,GACjB,YAAY,GAAG,SAAS,CA6C1B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAoC3F;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAUzD"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Rotation — Daily receipt indexing
|
|
3
|
+
*
|
|
4
|
+
* Writes individual audit receipts to date-organized directories under
|
|
5
|
+
* the vault's audit directory. Maintains a bounded index.json for fast
|
|
6
|
+
* receipt lookup.
|
|
7
|
+
*
|
|
8
|
+
* Structure: .usertrust/audit/<kind>/<YYYY-MM-DD>/<receiptId>.json
|
|
9
|
+
*
|
|
10
|
+
* Adapted from Turf governance audit.ts (receipt emission + daily rotation).
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { AUDIT_DIR, RECEIPT_VERSION, VAULT_DIR } from "../shared/constants.js";
|
|
15
|
+
import { trustId } from "../shared/ids.js";
|
|
16
|
+
// ── Helpers ──
|
|
17
|
+
function getTodayDate() {
|
|
18
|
+
const now = new Date();
|
|
19
|
+
return now.toISOString().split("T")[0] ?? "unknown";
|
|
20
|
+
}
|
|
21
|
+
function getDailyDir(auditRoot, kind) {
|
|
22
|
+
return join(auditRoot, kind, getTodayDate());
|
|
23
|
+
}
|
|
24
|
+
function getIndexPath(auditRoot) {
|
|
25
|
+
return join(auditRoot, "index.json");
|
|
26
|
+
}
|
|
27
|
+
// ── Index management ──
|
|
28
|
+
function updateIndex(auditRoot, entry, indexLimit) {
|
|
29
|
+
try {
|
|
30
|
+
const indexPath = getIndexPath(auditRoot);
|
|
31
|
+
let index = [];
|
|
32
|
+
if (existsSync(indexPath)) {
|
|
33
|
+
const raw = readFileSync(indexPath, "utf-8");
|
|
34
|
+
index = JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
index.push(entry);
|
|
37
|
+
// Keep index bounded
|
|
38
|
+
if (index.length > indexLimit) {
|
|
39
|
+
index = index.slice(-indexLimit);
|
|
40
|
+
}
|
|
41
|
+
writeFileSync(indexPath, JSON.stringify(index, null, "\t"));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Index update failure is non-fatal
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ── Public API ──
|
|
48
|
+
/**
|
|
49
|
+
* Write an audit receipt to the daily-rotated directory structure.
|
|
50
|
+
*
|
|
51
|
+
* @param vaultPath - Root vault directory (parent of .usertools/)
|
|
52
|
+
* @param input - Receipt data to write
|
|
53
|
+
* @param indexLimit - Maximum index entries (default: 10000)
|
|
54
|
+
* @returns The written receipt, or undefined if the write failed
|
|
55
|
+
*/
|
|
56
|
+
export function writeReceipt(vaultPath, input, indexLimit = 10_000) {
|
|
57
|
+
try {
|
|
58
|
+
const auditRoot = join(vaultPath, VAULT_DIR, AUDIT_DIR);
|
|
59
|
+
const receiptId = trustId("rcpt");
|
|
60
|
+
const ts = new Date().toISOString();
|
|
61
|
+
const receipt = {
|
|
62
|
+
v: RECEIPT_VERSION,
|
|
63
|
+
ts,
|
|
64
|
+
kind: input.kind,
|
|
65
|
+
subsystem: input.subsystem,
|
|
66
|
+
actor: input.actor,
|
|
67
|
+
...(input.correlationId !== undefined ? { correlationId: input.correlationId } : {}),
|
|
68
|
+
data: {
|
|
69
|
+
receiptId,
|
|
70
|
+
...input.data,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
// Write individual receipt file with daily rotation
|
|
74
|
+
const dailyDir = getDailyDir(auditRoot, input.kind);
|
|
75
|
+
if (!existsSync(dailyDir)) {
|
|
76
|
+
mkdirSync(dailyDir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
const receiptFile = join(dailyDir, `${receiptId}.json`);
|
|
79
|
+
writeFileSync(receiptFile, JSON.stringify(receipt, null, "\t"));
|
|
80
|
+
// Update index
|
|
81
|
+
updateIndex(auditRoot, {
|
|
82
|
+
receiptId,
|
|
83
|
+
kind: input.kind,
|
|
84
|
+
ts,
|
|
85
|
+
actor: input.actor,
|
|
86
|
+
...(input.correlationId !== undefined ? { correlationId: input.correlationId } : {}),
|
|
87
|
+
path: `${input.kind}/${getTodayDate()}/${receiptId}.json`,
|
|
88
|
+
}, indexLimit);
|
|
89
|
+
return receipt;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* List all receipts of a given kind (optionally filtered by date).
|
|
97
|
+
*
|
|
98
|
+
* @param vaultPath - Root vault directory
|
|
99
|
+
* @param kind - Receipt kind to list
|
|
100
|
+
* @param date - Optional date filter (YYYY-MM-DD)
|
|
101
|
+
* @returns Array of receipts, sorted newest-first
|
|
102
|
+
*/
|
|
103
|
+
export function listReceipts(vaultPath, kind, date) {
|
|
104
|
+
const kindDir = join(vaultPath, VAULT_DIR, AUDIT_DIR, kind);
|
|
105
|
+
if (!existsSync(kindDir))
|
|
106
|
+
return [];
|
|
107
|
+
try {
|
|
108
|
+
const results = [];
|
|
109
|
+
const entries = readdirSync(kindDir, { withFileTypes: true });
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
if (entry.isDirectory()) {
|
|
112
|
+
if (date && entry.name !== date)
|
|
113
|
+
continue;
|
|
114
|
+
const dateDir = join(kindDir, entry.name);
|
|
115
|
+
const files = readdirSync(dateDir).filter((f) => f.endsWith(".json"));
|
|
116
|
+
for (const f of files) {
|
|
117
|
+
try {
|
|
118
|
+
const raw = readFileSync(join(dateDir, f), "utf-8");
|
|
119
|
+
results.push(JSON.parse(raw));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Skip invalid files
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
127
|
+
try {
|
|
128
|
+
const raw = readFileSync(join(kindDir, entry.name), "utf-8");
|
|
129
|
+
results.push(JSON.parse(raw));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Skip invalid files
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return results.sort((a, b) => new Date(b.ts).getTime() - new Date(a.ts).getTime());
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Load the audit index.
|
|
144
|
+
*
|
|
145
|
+
* @param vaultPath - Root vault directory
|
|
146
|
+
* @returns Array of index entries
|
|
147
|
+
*/
|
|
148
|
+
export function loadIndex(vaultPath) {
|
|
149
|
+
const indexPath = getIndexPath(join(vaultPath, VAULT_DIR, AUDIT_DIR));
|
|
150
|
+
if (!existsSync(indexPath))
|
|
151
|
+
return [];
|
|
152
|
+
try {
|
|
153
|
+
const raw = readFileSync(indexPath, "utf-8");
|
|
154
|
+
return JSON.parse(raw);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation.js","sourceRoot":"","sources":["../../src/audit/rotation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AA+B3C,gBAAgB;AAEhB,SAAS,YAAY;IACpB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;AACrD,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB,EAAE,IAAY;IACnD,OAAO,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,YAAY,CAAC,SAAiB;IACtC,OAAO,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACtC,CAAC;AAED,yBAAyB;AAEzB,SAAS,WAAW,CAAC,SAAiB,EAAE,KAAiB,EAAE,UAAkB;IAC5E,IAAI,CAAC;QACJ,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,KAAK,GAAiB,EAAE,CAAC;QAE7B,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC7C,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;QACzC,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAElB,qBAAqB;QACrB,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAED,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACR,oCAAoC;IACrC,CAAC;AACF,CAAC;AAED,mBAAmB;AAEnB;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC3B,SAAiB,EACjB,KAAwB,EACxB,UAAU,GAAG,MAAM;IAEnB,IAAI,CAAC;QACJ,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAEpC,MAAM,OAAO,GAAiB;YAC7B,CAAC,EAAE,eAAe;YAClB,EAAE;YACF,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,IAAI,EAAE;gBACL,SAAS;gBACT,GAAG,KAAK,CAAC,IAAI;aACb;SACD,CAAC;QAEF,oDAAoD;QACpD,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;QACxD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAEhE,eAAe;QACf,WAAW,CACV,SAAS,EACT;YACC,SAAS;YACT,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,EAAE;YACF,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,YAAY,EAAE,IAAI,SAAS,OAAO;SACzD,EACD,UAAU,CACV,CAAC;QAEF,OAAO,OAAO,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,IAAY,EAAE,IAAa;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACJ,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAE9D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;oBAAE,SAAS;gBAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBACtE,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;oBACvB,IAAI,CAAC;wBACJ,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;wBACpD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC,CAAC;oBAC/C,CAAC;oBAAC,MAAM,CAAC;wBACR,qBAAqB;oBACtB,CAAC;gBACF,CAAC;YACF,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3D,IAAI,CAAC;oBACJ,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;oBAC7D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC,CAAC;gBAC/C,CAAC;gBAAC,MAAM,CAAC;oBACR,qBAAqB;gBACtB,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB;IAC1C,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Chain Verifier
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSONL audit log and verifies:
|
|
5
|
+
* 1. Each event's hash matches the SHA-256 of its canonical representation
|
|
6
|
+
* 2. Each event's previousHash links to the prior event's hash
|
|
7
|
+
* 3. The first event chains from GENESIS_HASH
|
|
8
|
+
*
|
|
9
|
+
* Adapted from usertools-stealth governance/audit/verifier.ts — removes
|
|
10
|
+
* flushAuditWriter dependency (verifier should NOT flush the writer).
|
|
11
|
+
*/
|
|
12
|
+
export interface ChainVerificationResult {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
eventsVerified: number;
|
|
15
|
+
errors: string[];
|
|
16
|
+
latestHash: string;
|
|
17
|
+
verifiedAt: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function verifyChain(logPath: string): ChainVerificationResult;
|
|
20
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/audit/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,CAuEpE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Chain Verifier
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSONL audit log and verifies:
|
|
5
|
+
* 1. Each event's hash matches the SHA-256 of its canonical representation
|
|
6
|
+
* 2. Each event's previousHash links to the prior event's hash
|
|
7
|
+
* 3. The first event chains from GENESIS_HASH
|
|
8
|
+
*
|
|
9
|
+
* Adapted from usertools-stealth governance/audit/verifier.ts — removes
|
|
10
|
+
* flushAuditWriter dependency (verifier should NOT flush the writer).
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { GENESIS_HASH } from "../shared/constants.js";
|
|
15
|
+
import { canonicalize } from "./canonical.js";
|
|
16
|
+
export function verifyChain(logPath) {
|
|
17
|
+
const errors = [];
|
|
18
|
+
if (!existsSync(logPath)) {
|
|
19
|
+
return {
|
|
20
|
+
valid: true,
|
|
21
|
+
eventsVerified: 0,
|
|
22
|
+
errors: [],
|
|
23
|
+
latestHash: GENESIS_HASH,
|
|
24
|
+
verifiedAt: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const content = readFileSync(logPath, "utf-8").trim();
|
|
28
|
+
if (!content) {
|
|
29
|
+
return {
|
|
30
|
+
valid: true,
|
|
31
|
+
eventsVerified: 0,
|
|
32
|
+
errors: [],
|
|
33
|
+
latestHash: GENESIS_HASH,
|
|
34
|
+
verifiedAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
38
|
+
let expectedPreviousHash = GENESIS_HASH;
|
|
39
|
+
let latestHash = GENESIS_HASH;
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
const line = lines[i];
|
|
42
|
+
let event;
|
|
43
|
+
try {
|
|
44
|
+
event = JSON.parse(line);
|
|
45
|
+
}
|
|
46
|
+
catch (parseErr) {
|
|
47
|
+
errors.push(`Event ${i + 1}: malformed JSON — ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
48
|
+
expectedPreviousHash = "";
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (event.previousHash !== expectedPreviousHash) {
|
|
52
|
+
errors.push(`Event ${i + 1} (${event.id}): previousHash mismatch. ` +
|
|
53
|
+
`Expected ${expectedPreviousHash}, got ${event.previousHash}`);
|
|
54
|
+
}
|
|
55
|
+
const { hash: storedHash, ...eventWithoutHash } = event;
|
|
56
|
+
const canonical = canonicalize(eventWithoutHash);
|
|
57
|
+
const computedHash = createHash("sha256").update(canonical).digest("hex");
|
|
58
|
+
if (storedHash !== computedHash) {
|
|
59
|
+
errors.push(`Event ${i + 1} (${event.id}): hash mismatch. ` +
|
|
60
|
+
`Expected ${computedHash}, got ${storedHash}`);
|
|
61
|
+
}
|
|
62
|
+
expectedPreviousHash = storedHash;
|
|
63
|
+
latestHash = storedHash;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
valid: errors.length === 0,
|
|
67
|
+
eventsVerified: lines.length,
|
|
68
|
+
errors,
|
|
69
|
+
latestHash,
|
|
70
|
+
verifiedAt: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/audit/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAU9C,MAAM,UAAU,WAAW,CAAC,OAAe;IAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO;YACN,KAAK,EAAE,IAAI;YACX,cAAc,EAAE,CAAC;YACjB,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO;YACN,KAAK,EAAE,IAAI;YACX,cAAc,EAAE,CAAC;YACjB,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,YAAY;YACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,oBAAoB,GAAG,YAAY,CAAC;IACxC,IAAI,UAAU,GAAG,YAAY,CAAC;IAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAEhC,IAAI,KAAiB,CAAC;QACtB,IAAI,CAAC;YACJ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;QACxC,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CACV,SAAS,CAAC,GAAG,CAAC,sBAAsB,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CACrG,CAAC;YACF,oBAAoB,GAAG,EAAE,CAAC;YAC1B,SAAS;QACV,CAAC;QAED,IAAI,KAAK,CAAC,YAAY,KAAK,oBAAoB,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CACV,SAAS,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,EAAE,4BAA4B;gBACtD,YAAY,oBAAoB,SAAS,KAAK,CAAC,YAAY,EAAE,CAC9D,CAAC;QACH,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,gBAAgB,EAAE,GAAG,KAAK,CAAC;QACxD,MAAM,SAAS,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE1E,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CACV,SAAS,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,EAAE,oBAAoB;gBAC9C,YAAY,YAAY,SAAS,UAAU,EAAE,CAC9C,CAAC;QACH,CAAC;QAED,oBAAoB,GAAG,UAAU,CAAC;QAClC,UAAU,GAAG,UAAU,CAAC;IACzB,CAAC;IAED,OAAO;QACN,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC1B,cAAc,EAAE,KAAK,CAAC,MAAM;QAC5B,MAAM;QACN,UAAU;QACV,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board of Directors — Board Coordination
|
|
3
|
+
*
|
|
4
|
+
* Coordinates two isolated Directors for democratic oversight.
|
|
5
|
+
* Decision matrix:
|
|
6
|
+
* Both APPROVE → approved
|
|
7
|
+
* Unanimous VETO → blocked (requires human escalation)
|
|
8
|
+
* VETO + APPROVE → escalated (conflict, human review)
|
|
9
|
+
* Both ABSTAIN → escalated (insufficient confidence)
|
|
10
|
+
*
|
|
11
|
+
* Persists JSONL session history with a 100-review buffer.
|
|
12
|
+
*/
|
|
13
|
+
import type { BoardDecision } from "../shared/types.js";
|
|
14
|
+
import type { BoardRequest } from "./concerns.js";
|
|
15
|
+
import type { DirectorReview } from "./director.js";
|
|
16
|
+
export interface BoardReviewResult {
|
|
17
|
+
request: BoardRequest & {
|
|
18
|
+
reviewId: string;
|
|
19
|
+
requestedAt: string;
|
|
20
|
+
};
|
|
21
|
+
reviews: DirectorReview[];
|
|
22
|
+
decision: BoardDecision;
|
|
23
|
+
reasoning: string;
|
|
24
|
+
requiresHumanEscalation: boolean;
|
|
25
|
+
escalationReason?: string | undefined;
|
|
26
|
+
decidedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export interface BoardOpts {
|
|
29
|
+
/** Maximum completed reviews to keep in the session file (default 100) */
|
|
30
|
+
maxHistory?: number | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface Board {
|
|
33
|
+
/**
|
|
34
|
+
* Submit, review, and decide in one synchronous call.
|
|
35
|
+
* Returns the full review result.
|
|
36
|
+
*/
|
|
37
|
+
reviewNow(decisionType: string, actor: string, description: string, options?: {
|
|
38
|
+
scope?: string[];
|
|
39
|
+
context?: Record<string, unknown>;
|
|
40
|
+
}): BoardReviewResult;
|
|
41
|
+
/** Get recent completed reviews. */
|
|
42
|
+
getRecentReviews(limit?: number): BoardReviewResult[];
|
|
43
|
+
/** Get aggregate stats. */
|
|
44
|
+
getStats(): BoardStats;
|
|
45
|
+
}
|
|
46
|
+
export interface BoardStats {
|
|
47
|
+
totalReviews: number;
|
|
48
|
+
approved: number;
|
|
49
|
+
blocked: number;
|
|
50
|
+
escalated: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Determine final Board decision from Director reviews.
|
|
54
|
+
*/
|
|
55
|
+
export declare function determineDecision(reviews: DirectorReview[]): {
|
|
56
|
+
decision: BoardDecision;
|
|
57
|
+
requiresHumanEscalation: boolean;
|
|
58
|
+
escalationReason?: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Create a Board of Directors instance backed by a vault directory.
|
|
62
|
+
*
|
|
63
|
+
* @param vaultPath — absolute or relative path to `.usertools/` (or custom vault)
|
|
64
|
+
* @param opts — optional configuration
|
|
65
|
+
*/
|
|
66
|
+
export declare function createBoard(vaultPath: string, opts?: BoardOpts): Board;
|
|
67
|
+
//# sourceMappingURL=board.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../src/board/board.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,YAAY,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CAClB;AASD,MAAM,WAAW,SAAS;IACzB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,KAAK;IACrB;;;OAGG;IACH,SAAS,CACR,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,GACC,iBAAiB,CAAC;IAErB,oCAAoC;IACpC,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAC;IAEtD,2BAA2B;IAC3B,QAAQ,IAAI,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG;IAC7D,QAAQ,EAAE,aAAa,CAAC;IACxB,uBAAuB,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CA+CA;AA2ED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,CAiEtE"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board of Directors — Board Coordination
|
|
3
|
+
*
|
|
4
|
+
* Coordinates two isolated Directors for democratic oversight.
|
|
5
|
+
* Decision matrix:
|
|
6
|
+
* Both APPROVE → approved
|
|
7
|
+
* Unanimous VETO → blocked (requires human escalation)
|
|
8
|
+
* VETO + APPROVE → escalated (conflict, human review)
|
|
9
|
+
* Both ABSTAIN → escalated (insufficient confidence)
|
|
10
|
+
*
|
|
11
|
+
* Persists JSONL session history with a 100-review buffer.
|
|
12
|
+
*/
|
|
13
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { trustId } from "../shared/ids.js";
|
|
16
|
+
import { listDirectors, reviewDecision } from "./director.js";
|
|
17
|
+
// ── Decision Logic ──
|
|
18
|
+
/**
|
|
19
|
+
* Determine final Board decision from Director reviews.
|
|
20
|
+
*/
|
|
21
|
+
export function determineDecision(reviews) {
|
|
22
|
+
const votes = reviews.map((r) => r.vote);
|
|
23
|
+
const vetoCount = votes.filter((v) => v === "veto").length;
|
|
24
|
+
const approveCount = votes.filter((v) => v === "approve").length;
|
|
25
|
+
const abstainCount = votes.filter((v) => v === "abstain").length;
|
|
26
|
+
// Unanimous veto → blocked
|
|
27
|
+
if (vetoCount === reviews.length) {
|
|
28
|
+
return {
|
|
29
|
+
decision: "blocked",
|
|
30
|
+
requiresHumanEscalation: true,
|
|
31
|
+
escalationReason: "Unanimous Board veto - all Directors flagged critical concerns",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Any veto with any approve → conflict, escalate
|
|
35
|
+
if (vetoCount > 0 && approveCount > 0) {
|
|
36
|
+
return {
|
|
37
|
+
decision: "escalated",
|
|
38
|
+
requiresHumanEscalation: true,
|
|
39
|
+
escalationReason: "Director disagreement - veto conflicts with approval",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Both abstain → need more info
|
|
43
|
+
if (abstainCount === reviews.length) {
|
|
44
|
+
return {
|
|
45
|
+
decision: "escalated",
|
|
46
|
+
requiresHumanEscalation: true,
|
|
47
|
+
escalationReason: "Both Directors abstained - insufficient confidence",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Single veto with abstain → blocked but escalate
|
|
51
|
+
if (vetoCount > 0) {
|
|
52
|
+
return {
|
|
53
|
+
decision: "blocked",
|
|
54
|
+
requiresHumanEscalation: true,
|
|
55
|
+
escalationReason: "Director veto with abstention",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Approved (both approve, or approve + abstain)
|
|
59
|
+
return {
|
|
60
|
+
decision: "approved",
|
|
61
|
+
requiresHumanEscalation: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Combine Director reasoning into final reasoning string.
|
|
66
|
+
*/
|
|
67
|
+
function combineReasoning(reviews, decision) {
|
|
68
|
+
const parts = reviews.map((r) => `[${r.directorId}] ${r.reasoning}`);
|
|
69
|
+
const prefix = decision === "approved"
|
|
70
|
+
? "Board APPROVED:"
|
|
71
|
+
: decision === "blocked"
|
|
72
|
+
? "Board BLOCKED:"
|
|
73
|
+
: "Board ESCALATED:";
|
|
74
|
+
return `${prefix} ${parts.join(" | ")}`;
|
|
75
|
+
}
|
|
76
|
+
// ── Session Persistence ──
|
|
77
|
+
function boardDir(vaultPath) {
|
|
78
|
+
return join(vaultPath, "board");
|
|
79
|
+
}
|
|
80
|
+
function sessionPath(vaultPath) {
|
|
81
|
+
return join(boardDir(vaultPath), "session.json");
|
|
82
|
+
}
|
|
83
|
+
function historyPath(vaultPath) {
|
|
84
|
+
return join(boardDir(vaultPath), "history.jsonl");
|
|
85
|
+
}
|
|
86
|
+
function ensureDir(vaultPath) {
|
|
87
|
+
const dir = boardDir(vaultPath);
|
|
88
|
+
if (!existsSync(dir)) {
|
|
89
|
+
mkdirSync(dir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function loadSession(vaultPath) {
|
|
93
|
+
ensureDir(vaultPath);
|
|
94
|
+
const file = sessionPath(vaultPath);
|
|
95
|
+
if (!existsSync(file)) {
|
|
96
|
+
const now = new Date().toISOString();
|
|
97
|
+
return {
|
|
98
|
+
pendingReviews: {},
|
|
99
|
+
completedReviews: [],
|
|
100
|
+
startedAt: now,
|
|
101
|
+
lastActivityAt: now,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(readFileSync(file, "utf-8"));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
const now = new Date().toISOString();
|
|
109
|
+
return {
|
|
110
|
+
pendingReviews: {},
|
|
111
|
+
completedReviews: [],
|
|
112
|
+
startedAt: now,
|
|
113
|
+
lastActivityAt: now,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function saveSession(vaultPath, session) {
|
|
118
|
+
ensureDir(vaultPath);
|
|
119
|
+
session.lastActivityAt = new Date().toISOString();
|
|
120
|
+
writeFileSync(sessionPath(vaultPath), JSON.stringify(session, null, "\t"));
|
|
121
|
+
}
|
|
122
|
+
function appendHistory(vaultPath, result) {
|
|
123
|
+
ensureDir(vaultPath);
|
|
124
|
+
appendFileSync(historyPath(vaultPath), `${JSON.stringify(result)}\n`);
|
|
125
|
+
}
|
|
126
|
+
// ── Factory ──
|
|
127
|
+
/**
|
|
128
|
+
* Create a Board of Directors instance backed by a vault directory.
|
|
129
|
+
*
|
|
130
|
+
* @param vaultPath — absolute or relative path to `.usertools/` (or custom vault)
|
|
131
|
+
* @param opts — optional configuration
|
|
132
|
+
*/
|
|
133
|
+
export function createBoard(vaultPath, opts) {
|
|
134
|
+
const maxHistory = opts?.maxHistory ?? 100;
|
|
135
|
+
return {
|
|
136
|
+
reviewNow(decisionType, actor, description, options) {
|
|
137
|
+
const reviewId = trustId("BR");
|
|
138
|
+
const request = {
|
|
139
|
+
reviewId,
|
|
140
|
+
decisionType,
|
|
141
|
+
actor,
|
|
142
|
+
description,
|
|
143
|
+
scope: options?.scope,
|
|
144
|
+
context: options?.context ?? {},
|
|
145
|
+
requestedAt: new Date().toISOString(),
|
|
146
|
+
};
|
|
147
|
+
// Each Director reviews independently
|
|
148
|
+
const directors = listDirectors();
|
|
149
|
+
const reviews = [];
|
|
150
|
+
for (const director of directors) {
|
|
151
|
+
reviews.push(reviewDecision(director.id, request));
|
|
152
|
+
}
|
|
153
|
+
// Determine final decision
|
|
154
|
+
const { decision, requiresHumanEscalation, escalationReason } = determineDecision(reviews);
|
|
155
|
+
const reasoning = combineReasoning(reviews, decision);
|
|
156
|
+
const result = {
|
|
157
|
+
request,
|
|
158
|
+
reviews,
|
|
159
|
+
decision,
|
|
160
|
+
reasoning,
|
|
161
|
+
requiresHumanEscalation,
|
|
162
|
+
escalationReason,
|
|
163
|
+
decidedAt: new Date().toISOString(),
|
|
164
|
+
};
|
|
165
|
+
// Persist
|
|
166
|
+
const session = loadSession(vaultPath);
|
|
167
|
+
session.completedReviews.push(result);
|
|
168
|
+
if (session.completedReviews.length > maxHistory) {
|
|
169
|
+
session.completedReviews = session.completedReviews.slice(-maxHistory);
|
|
170
|
+
}
|
|
171
|
+
saveSession(vaultPath, session);
|
|
172
|
+
appendHistory(vaultPath, result);
|
|
173
|
+
return result;
|
|
174
|
+
},
|
|
175
|
+
getRecentReviews(limit = 10) {
|
|
176
|
+
const session = loadSession(vaultPath);
|
|
177
|
+
return session.completedReviews.slice(-limit);
|
|
178
|
+
},
|
|
179
|
+
getStats() {
|
|
180
|
+
const session = loadSession(vaultPath);
|
|
181
|
+
const completed = session.completedReviews;
|
|
182
|
+
return {
|
|
183
|
+
totalReviews: completed.length,
|
|
184
|
+
approved: completed.filter((r) => r.decision === "approved").length,
|
|
185
|
+
blocked: completed.filter((r) => r.decision === "blocked").length,
|
|
186
|
+
escalated: completed.filter((r) => r.decision === "escalated").length,
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/board/board.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAuD9D,uBAAuB;AAEvB;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB;IAK1D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAC3D,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAEjE,2BAA2B;IAC3B,IAAI,SAAS,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QAClC,OAAO;YACN,QAAQ,EAAE,SAAS;YACnB,uBAAuB,EAAE,IAAI;YAC7B,gBAAgB,EAAE,gEAAgE;SAClF,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,IAAI,SAAS,GAAG,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO;YACN,QAAQ,EAAE,WAAW;YACrB,uBAAuB,EAAE,IAAI;YAC7B,gBAAgB,EAAE,sDAAsD;SACxE,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,YAAY,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO;YACN,QAAQ,EAAE,WAAW;YACrB,uBAAuB,EAAE,IAAI;YAC7B,gBAAgB,EAAE,oDAAoD;SACtE,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO;YACN,QAAQ,EAAE,SAAS;YACnB,uBAAuB,EAAE,IAAI;YAC7B,gBAAgB,EAAE,+BAA+B;SACjD,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,OAAO;QACN,QAAQ,EAAE,UAAU;QACpB,uBAAuB,EAAE,KAAK;KAC9B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,OAAyB,EAAE,QAAuB;IAC3E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IACrE,MAAM,MAAM,GACX,QAAQ,KAAK,UAAU;QACtB,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,QAAQ,KAAK,SAAS;YACvB,CAAC,CAAC,gBAAgB;YAClB,CAAC,CAAC,kBAAkB,CAAC;IACxB,OAAO,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,4BAA4B;AAE5B,SAAS,QAAQ,CAAC,SAAiB;IAClC,OAAO,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB;IACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB;IACrC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,SAAS,CAAC,SAAiB;IACnC,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB;IACrC,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO;YACN,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,EAAE;YACpB,SAAS,EAAE,GAAG;YACd,cAAc,EAAE,GAAG;SACnB,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAiB,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO;YACN,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,EAAE;YACpB,SAAS,EAAE,GAAG;YACd,cAAc,EAAE,GAAG;SACnB,CAAC;IACH,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB,EAAE,OAAqB;IAC5D,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,OAAO,CAAC,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,aAAa,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,aAAa,CAAC,SAAiB,EAAE,MAAyB;IAClE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,cAAc,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,gBAAgB;AAEhB;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,IAAgB;IAC9D,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC;IAE3C,OAAO;QACN,SAAS,CAAC,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO;YAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,OAAO,GAAG;gBACf,QAAQ;gBACR,YAAY;gBACZ,KAAK;gBACL,WAAW;gBACX,KAAK,EAAE,OAAO,EAAE,KAAK;gBACrB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE;gBAC/B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC;YAEF,sCAAsC;YACtC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;YAClC,MAAM,OAAO,GAAqB,EAAE,CAAC;YACrC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;YACpD,CAAC;YAED,2BAA2B;YAC3B,MAAM,EAAE,QAAQ,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC3F,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEtD,MAAM,MAAM,GAAsB;gBACjC,OAAO;gBACP,OAAO;gBACP,QAAQ;gBACR,SAAS;gBACT,uBAAuB;gBACvB,gBAAgB;gBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACnC,CAAC;YAEF,UAAU;YACV,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YACvC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,OAAO,CAAC,gBAAgB,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBAClD,OAAO,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;YACxE,CAAC;YACD,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChC,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAEjC,OAAO,MAAM,CAAC;QACf,CAAC;QAED,gBAAgB,CAAC,KAAK,GAAG,EAAE;YAC1B,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YACvC,OAAO,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC;QAED,QAAQ;YACP,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAC3C,OAAO;gBACN,YAAY,EAAE,SAAS,CAAC,MAAM;gBAC9B,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM;gBACnE,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;gBACjE,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,MAAM;aACrE,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concern Detection Library
|
|
3
|
+
*
|
|
4
|
+
* 6 pure-function detectors for Board of Directors oversight.
|
|
5
|
+
* Each detector: (request) => Concern | null
|
|
6
|
+
*/
|
|
7
|
+
import type { ConcernType, PolicySeverity } from "../shared/types.js";
|
|
8
|
+
export interface Concern {
|
|
9
|
+
type: ConcernType;
|
|
10
|
+
severity: PolicySeverity;
|
|
11
|
+
description: string;
|
|
12
|
+
evidence: string;
|
|
13
|
+
}
|
|
14
|
+
export interface BoardRequest {
|
|
15
|
+
/** Type of decision under review */
|
|
16
|
+
decisionType: string;
|
|
17
|
+
/** Human-readable description of the action */
|
|
18
|
+
description: string;
|
|
19
|
+
/** File/resource scope affected */
|
|
20
|
+
scope?: string[] | undefined;
|
|
21
|
+
/** Arbitrary context for detection heuristics */
|
|
22
|
+
context: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Hallucination — absolute claims, factual assertions without evidence.
|
|
26
|
+
* Triggers on "always"/"never" overgeneralizations and policy overrides lacking justification.
|
|
27
|
+
*/
|
|
28
|
+
export declare function detectHallucination(request: BoardRequest): Concern | null;
|
|
29
|
+
/**
|
|
30
|
+
* Bias — preferential routing, demographic skew.
|
|
31
|
+
* Triggers when a preferred worker is specified during scope expansion.
|
|
32
|
+
*/
|
|
33
|
+
export declare function detectBias(request: BoardRequest): Concern | null;
|
|
34
|
+
/**
|
|
35
|
+
* Safety — credentials in scope, dangerous content.
|
|
36
|
+
* Scans scope paths and description for security-sensitive patterns.
|
|
37
|
+
*/
|
|
38
|
+
export declare function detectSafety(request: BoardRequest): Concern | null;
|
|
39
|
+
/**
|
|
40
|
+
* Scope creep — root wildcards, unbounded scope.
|
|
41
|
+
* Triggers on root-level ** wildcards or excessive scope breadth (>10 patterns).
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectScopeCreep(request: BoardRequest): Concern | null;
|
|
44
|
+
/**
|
|
45
|
+
* Resource abuse — cost exceeds threshold, excessive token usage.
|
|
46
|
+
* Triggers when estimated cost exceeds $100 on resource-intensive operations.
|
|
47
|
+
*/
|
|
48
|
+
export declare function detectResourceAbuse(request: BoardRequest): Concern | null;
|
|
49
|
+
/**
|
|
50
|
+
* Policy violation — explicit policy override attempts.
|
|
51
|
+
* Triggers on any policy_override decision type.
|
|
52
|
+
*/
|
|
53
|
+
export declare function detectPolicyViolation(request: BoardRequest): Concern | null;
|
|
54
|
+
/**
|
|
55
|
+
* Run all concern detectors against a request.
|
|
56
|
+
* Returns every concern found (zero or more).
|
|
57
|
+
*/
|
|
58
|
+
export declare function detectConcerns(request: BoardRequest): Concern[];
|
|
59
|
+
//# sourceMappingURL=concerns.d.ts.map
|