sibyl-system 1.2.2 → 1.3.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/README.md +32 -2
- package/dist/cli.js +356 -187
- package/dist/index.js +568 -174
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,35 @@ import { copyFile as copyFile2, mkdir as mkdir6, readFile as readFile6 } from "n
|
|
|
12
12
|
import { basename, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, resolve as resolve2 } from "node:path";
|
|
13
13
|
|
|
14
14
|
// src/state/record.ts
|
|
15
|
+
var INDEPENDENCE_STATUSES = ["INDEPENDENT", "NOT-INDEPENDENT", "UNVERIFIABLE"];
|
|
16
|
+
function isIndependenceShape(v) {
|
|
17
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
|
|
18
|
+
const o = v;
|
|
19
|
+
if (!INDEPENDENCE_STATUSES.includes(o["status"])) return false;
|
|
20
|
+
if (!Array.isArray(o["convenerChain"]) || !o["convenerChain"].every((s) => typeof s === "string" && s.length > 0)) return false;
|
|
21
|
+
return typeof o["evidence"] === "string";
|
|
22
|
+
}
|
|
23
|
+
function rebuildIndependence(v) {
|
|
24
|
+
return { status: v.status, convenerChain: [...v.convenerChain], evidence: v.evidence };
|
|
25
|
+
}
|
|
26
|
+
var INSTRUMENT_NAME = /^[a-z0-9-]{1,40}$/;
|
|
27
|
+
var HEX64 = /^[0-9a-f]{64}$/;
|
|
28
|
+
function isInstrumentShape(v) {
|
|
29
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
|
|
30
|
+
const o = v;
|
|
31
|
+
if (typeof o["rulesHash"] !== "string" || !HEX64.test(o["rulesHash"])) return false;
|
|
32
|
+
const comps = o["components"];
|
|
33
|
+
if (typeof comps !== "object" || comps === null || Array.isArray(comps)) return false;
|
|
34
|
+
return Object.entries(comps).every(
|
|
35
|
+
([name, hash2]) => INSTRUMENT_NAME.test(name) && typeof hash2 === "string" && HEX64.test(hash2)
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
function rebuildInstrument(v) {
|
|
39
|
+
return {
|
|
40
|
+
rulesHash: v.rulesHash,
|
|
41
|
+
components: Object.fromEntries(Object.entries(v.components).map(([name, hash2]) => [name, hash2]))
|
|
42
|
+
};
|
|
43
|
+
}
|
|
15
44
|
function isNonEmptyString(v) {
|
|
16
45
|
return typeof v === "string" && v.length > 0;
|
|
17
46
|
}
|
|
@@ -19,8 +48,142 @@ function compactIso(now) {
|
|
|
19
48
|
return now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
20
49
|
}
|
|
21
50
|
|
|
22
|
-
// src/
|
|
51
|
+
// src/instrument.ts
|
|
52
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
53
|
+
|
|
54
|
+
// src/council/index.ts
|
|
55
|
+
var COUNCILORS = ["MELCHIOR", "BALTHASAR", "CASPER"];
|
|
56
|
+
var OUTPUT_CONTRACT = 'Respond with EXACTLY one JSON object and nothing else - no prose, no markdown fences, no extra keys - matching: {"verdict":"APPROVE"|"REJECT","confidence":<number between 0 and 1>,"reasons":[<strings>],"must_fix":[<strings>]}. "verdict" is your final ballot, "confidence" your certainty (0..1), "reasons" the justification, "must_fix" the concrete defects that block approval (empty array if none).';
|
|
57
|
+
var COUNCILOR_PERSONAS = {
|
|
58
|
+
MELCHIOR: {
|
|
59
|
+
title: "correctness & safety skeptic",
|
|
60
|
+
system: "You are MELCHIOR, the correctness-and-safety skeptic on the SIBYL council. Audit the artifact for logical errors, unproven assumptions, correctness bugs, safety hazards, and irreversible side effects. Approve only if it survives strict technical scrutiny; default to REJECT when doubt remains. " + OUTPUT_CONTRACT
|
|
61
|
+
},
|
|
62
|
+
BALTHASAR: {
|
|
63
|
+
title: "adversarial red-teamer",
|
|
64
|
+
system: "You are BALTHASAR, the adversarial red-teamer on the SIBYL council. Attack the artifact as an adversary: probe abuse cases, exploits, race conditions, input-boundary failures, and ways it breaks under hostile use. If you can name a concrete attack or failure mode, REJECT and put it in must_fix. " + OUTPUT_CONTRACT
|
|
65
|
+
},
|
|
66
|
+
CASPER: {
|
|
67
|
+
title: "pragmatic utilist",
|
|
68
|
+
system: "You are CASPER, the pragmatic utilist on the SIBYL council. Judge the artifact by real-world utility: does it solve the stated problem, is it maintainable, worth the complexity, and shippable? Weigh benefit against cost, but REJECT when the defects outweigh the value. " + OUTPUT_CONTRACT
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var COUNCIL_SIZE = COUNCILORS.length;
|
|
72
|
+
var KNOWN_IDS = new Set(COUNCILORS);
|
|
73
|
+
|
|
74
|
+
// src/chamber/protocol.ts
|
|
75
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
76
|
+
import { join as join2 } from "node:path";
|
|
77
|
+
|
|
78
|
+
// src/lane/seating.ts
|
|
23
79
|
import { createHash } from "node:crypto";
|
|
80
|
+
function toModelId(model) {
|
|
81
|
+
return `${model.providerID}/${model.modelID}`;
|
|
82
|
+
}
|
|
83
|
+
function policyAllows(modelId, policy) {
|
|
84
|
+
return policy.allowedPrefixes.some((prefix) => prefix.length > 0 && modelId.startsWith(prefix));
|
|
85
|
+
}
|
|
86
|
+
function resolveSeat(role, requestedSlot, pool, policy) {
|
|
87
|
+
const found = pool[requestedSlot] ?? pool["default"];
|
|
88
|
+
if (found === void 0) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
role,
|
|
92
|
+
deny: `seat denied: slot "${requestedSlot}" (and fallback "default") absent from pool`
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const modelId = toModelId(found);
|
|
96
|
+
if (found.providerID.length === 0 || found.modelID.length === 0) {
|
|
97
|
+
return { ok: false, role, deny: `seat denied: slot "${requestedSlot}" is an empty placeholder (${modelId})` };
|
|
98
|
+
}
|
|
99
|
+
if (!policyAllows(modelId, policy)) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
role,
|
|
103
|
+
deny: `seat denied by modelPolicy (E4/F1): "${modelId}" is not under any allowed prefix [${policy.allowedPrefixes.join(", ")}] \u2014 launch must not be attempted`
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return { ok: true, role, slot: requestedSlot, modelId };
|
|
107
|
+
}
|
|
108
|
+
var SEP = "";
|
|
109
|
+
function sha256Hex(text) {
|
|
110
|
+
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
111
|
+
}
|
|
112
|
+
function computeDrawCommit(poolIds, seed) {
|
|
113
|
+
return sha256Hex(`sibyl-draw-v1${SEP}${poolIds.join(SEP)}${SEP}${seed}`);
|
|
114
|
+
}
|
|
115
|
+
function drawJudge(poolIds, seed, salt) {
|
|
116
|
+
if (poolIds.length === 0) {
|
|
117
|
+
return { ok: false, deny: "judge draw denied: empty judge pool" };
|
|
118
|
+
}
|
|
119
|
+
const drawCommit = computeDrawCommit(poolIds, seed);
|
|
120
|
+
const digest = sha256Hex(`${drawCommit}${SEP}${salt}`);
|
|
121
|
+
const uint = Number.parseInt(digest.slice(0, 8), 16);
|
|
122
|
+
const index = uint % poolIds.length;
|
|
123
|
+
const modelId = poolIds[index];
|
|
124
|
+
return { ok: true, draw: { index, modelId, drawCommit } };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/verdict/index.ts
|
|
128
|
+
var OPEN_BRACE = 123;
|
|
129
|
+
var CLOSE_BRACE = 125;
|
|
130
|
+
var QUOTE = 34;
|
|
131
|
+
var BACKSLASH = 92;
|
|
132
|
+
var FENCE_RE = /```(?:json)?[ \t]*\r?\n?([\s\S]*?)```/gi;
|
|
133
|
+
function findBalancedObject(text, start) {
|
|
134
|
+
if (text.charCodeAt(start) !== OPEN_BRACE) return null;
|
|
135
|
+
let depth = 0;
|
|
136
|
+
let inString = false;
|
|
137
|
+
let escaped = false;
|
|
138
|
+
for (let i = start; i < text.length; i++) {
|
|
139
|
+
const c = text.charCodeAt(i);
|
|
140
|
+
if (inString) {
|
|
141
|
+
if (escaped) escaped = false;
|
|
142
|
+
else if (c === BACKSLASH) escaped = true;
|
|
143
|
+
else if (c === QUOTE) inString = false;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (c === QUOTE) inString = true;
|
|
147
|
+
else if (c === OPEN_BRACE) depth++;
|
|
148
|
+
else if (c === CLOSE_BRACE) {
|
|
149
|
+
depth--;
|
|
150
|
+
if (depth === 0) return text.slice(start, i + 1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function firstParseableObject(text) {
|
|
156
|
+
for (let i = 0; i < text.length; i++) {
|
|
157
|
+
if (text.charCodeAt(i) !== OPEN_BRACE) continue;
|
|
158
|
+
const candidate = findBalancedObject(text, i);
|
|
159
|
+
if (candidate === null) continue;
|
|
160
|
+
try {
|
|
161
|
+
JSON.parse(candidate);
|
|
162
|
+
return candidate;
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function extractVerdictJson(text) {
|
|
169
|
+
for (const m of text.matchAll(FENCE_RE)) {
|
|
170
|
+
const fenced = firstParseableObject(m[1] ?? "");
|
|
171
|
+
if (fenced !== null) return fenced;
|
|
172
|
+
}
|
|
173
|
+
return firstParseableObject(text);
|
|
174
|
+
}
|
|
175
|
+
function rejectVerdict(reason) {
|
|
176
|
+
return {
|
|
177
|
+
verdict: "REJECT",
|
|
178
|
+
confidence: 0,
|
|
179
|
+
reasons: [`verdict-unparseable: ${reason}`],
|
|
180
|
+
must_fix: []
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
var FAIL_CLOSED_REJECT = rejectVerdict("no-parse-performed");
|
|
184
|
+
|
|
185
|
+
// src/state/chamber.ts
|
|
186
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24
187
|
import { mkdir, readFile, readdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
25
188
|
import { homedir } from "node:os";
|
|
26
189
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
@@ -29,7 +192,7 @@ var TERMINAL_STATES = ["CONVERGED", "NEEDS_ROUND", "MEMBER_LOST", "TIMEOUT"];
|
|
|
29
192
|
var RUN_PROFILES = ["review", "exam"];
|
|
30
193
|
var RECORD_SCHEMA = 1;
|
|
31
194
|
function sha256Text(text) {
|
|
32
|
-
return
|
|
195
|
+
return createHash2("sha256").update(text, "utf8").digest("hex");
|
|
33
196
|
}
|
|
34
197
|
async function sha256File(path) {
|
|
35
198
|
let buf;
|
|
@@ -39,7 +202,7 @@ async function sha256File(path) {
|
|
|
39
202
|
const code = typeof err === "object" && err !== null ? String(Reflect.get(err, "code")) : "unknown";
|
|
40
203
|
return { ok: false, reason: `read failed (${code})` };
|
|
41
204
|
}
|
|
42
|
-
return { ok: true, sha256:
|
|
205
|
+
return { ok: true, sha256: createHash2("sha256").update(buf).digest("hex"), bytes: buf.byteLength };
|
|
43
206
|
}
|
|
44
207
|
async function assertOnDisk(path, claim2) {
|
|
45
208
|
const now = await sha256File(path);
|
|
@@ -85,6 +248,12 @@ function validateChamberRecord(raw) {
|
|
|
85
248
|
if (!Array.isArray(o["artifacts"]) || !o["artifacts"].every(isArtifactRef)) return { ok: false, reason: "artifacts must be an array of ArtifactRef" };
|
|
86
249
|
if (typeof o["evidenceRows"] !== "number" || !Number.isInteger(o["evidenceRows"]) || o["evidenceRows"] < 0) return { ok: false, reason: "evidenceRows must be a non-negative integer" };
|
|
87
250
|
if (o["notes"] !== void 0 && typeof o["notes"] !== "string") return { ok: false, reason: "notes must be a string when present" };
|
|
251
|
+
if (o["instrument"] !== void 0 && !isInstrumentShape(o["instrument"])) {
|
|
252
|
+
return { ok: false, reason: "instrument must be {rulesHash: 64-hex, components: name->64-hex} when present" };
|
|
253
|
+
}
|
|
254
|
+
if (o["independence"] !== void 0 && !isIndependenceShape(o["independence"])) {
|
|
255
|
+
return { ok: false, reason: "independence must be {status: INDEPENDENT|NOT-INDEPENDENT|UNVERIFIABLE, convenerChain: string[], evidence: string} when present" };
|
|
256
|
+
}
|
|
88
257
|
const record2 = {
|
|
89
258
|
schema: RECORD_SCHEMA,
|
|
90
259
|
runId: o["runId"],
|
|
@@ -106,6 +275,8 @@ function validateChamberRecord(raw) {
|
|
|
106
275
|
evidenceRows: o["evidenceRows"]
|
|
107
276
|
};
|
|
108
277
|
if (typeof o["notes"] === "string") record2.notes = o["notes"];
|
|
278
|
+
if (o["instrument"] !== void 0) record2.instrument = rebuildInstrument(o["instrument"]);
|
|
279
|
+
if (o["independence"] !== void 0) record2.independence = rebuildIndependence(o["independence"]);
|
|
109
280
|
return { ok: true, record: record2 };
|
|
110
281
|
}
|
|
111
282
|
async function appendLedgerRow(ledgerPath, record2) {
|
|
@@ -245,176 +416,6 @@ function spotcheckCommand(runDir) {
|
|
|
245
416
|
return `cd ${runDir} && sha256sum -c ${CHECKSUMS_FILE}`;
|
|
246
417
|
}
|
|
247
418
|
|
|
248
|
-
// src/chamber/synthesis.ts
|
|
249
|
-
var PERFORMANCE_ONLY_IN_LOOP = "PERFORMANCE-ONLY-IN-LOOP";
|
|
250
|
-
var MAX_RATIONALE = 6;
|
|
251
|
-
function conclude(result) {
|
|
252
|
-
const { terminal, judge, gaps } = result;
|
|
253
|
-
if (gaps.length > 0 && (terminal === "MEMBER_LOST" || terminal === "TIMEOUT")) {
|
|
254
|
-
return { conclusion: "NEEDS_HUMAN", confidence: 0 };
|
|
255
|
-
}
|
|
256
|
-
if (terminal === "CONVERGED" && judge !== null) {
|
|
257
|
-
const base = judge.conclusion;
|
|
258
|
-
const conclusion = base === "NEEDS_HUMAN" ? "NEEDS_HUMAN" : gaps.length > 0 ? "NEEDS_HUMAN" : base;
|
|
259
|
-
return { conclusion, confidence: conclusion === "NEEDS_HUMAN" ? Math.min(judge.confidence, 0.5) : judge.confidence };
|
|
260
|
-
}
|
|
261
|
-
if (judge !== null && judge.convergence === "NEEDS_ROUND") {
|
|
262
|
-
return { conclusion: "NEEDS_HUMAN", confidence: Math.min(judge.confidence, 0.5) };
|
|
263
|
-
}
|
|
264
|
-
return { conclusion: "NEEDS_HUMAN", confidence: 0 };
|
|
265
|
-
}
|
|
266
|
-
function buildVoice(result) {
|
|
267
|
-
const { record: record2, judge, terminal, gaps } = result;
|
|
268
|
-
const { conclusion, confidence } = conclude(result);
|
|
269
|
-
const rationale = judge !== null && conclusion !== "NEEDS_HUMAN" ? judge.reasons.slice(0, MAX_RATIONALE) : (judge?.reasons ?? []).slice(0, MAX_RATIONALE).concat(gaps).slice(0, MAX_RATIONALE);
|
|
270
|
-
const sealed = [
|
|
271
|
-
"DISAGREEMENT-LOG.md",
|
|
272
|
-
...new Set(record2.artifacts.map((a) => a.relPath))
|
|
273
|
-
];
|
|
274
|
-
return {
|
|
275
|
-
label: "SIBYL-ONE-VOICE",
|
|
276
|
-
honesty: PERFORMANCE_ONLY_IN_LOOP,
|
|
277
|
-
conclusion,
|
|
278
|
-
confidence: conclusion === "NEEDS_HUMAN" ? Number(confidence.toFixed(2)) : confidence,
|
|
279
|
-
rationale,
|
|
280
|
-
must_fix: judge?.must_fix ?? [],
|
|
281
|
-
open_charges: judge?.charges.length ?? 0,
|
|
282
|
-
dissent_sealed_in: sealed,
|
|
283
|
-
terminal,
|
|
284
|
-
run_id: record2.runId,
|
|
285
|
-
serial: record2.serial,
|
|
286
|
-
spotcheck: spotcheckCommand(record2.runDir)
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
function renderVoice(voice) {
|
|
290
|
-
const lines = [
|
|
291
|
-
`SIBYL \u2014 ONE CONCLUSION, ONE VOICE [${voice.label}]`,
|
|
292
|
-
`conclusion: ${voice.conclusion} confidence: ${String(voice.confidence)} terminal: ${voice.terminal}`,
|
|
293
|
-
`run: ${voice.run_id} (serial ${String(voice.serial)}) open charges: ${String(voice.open_charges)}`,
|
|
294
|
-
`honesty: ${voice.honesty} (until C-09/C-14 containment rulings \u2014 see docs/isolation-laws.md)`,
|
|
295
|
-
"rationale:",
|
|
296
|
-
...voice.rationale.map((r, i) => ` ${String(i + 1)}. ${r}`)
|
|
297
|
-
];
|
|
298
|
-
if (voice.must_fix.length > 0) {
|
|
299
|
-
lines.push("must_fix:");
|
|
300
|
-
lines.push(...voice.must_fix.map((m) => ` - ${m}`));
|
|
301
|
-
}
|
|
302
|
-
lines.push(`internal debate sealed in run dir: ${voice.dissent_sealed_in.length} artifacts + DISAGREEMENT-LOG.md (hashes in CHECKSUMS.txt)`);
|
|
303
|
-
lines.push(`verify every recorded byte: ${voice.spotcheck}`);
|
|
304
|
-
return lines.join("\n");
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// src/chamber/protocol.ts
|
|
308
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
309
|
-
import { join as join2 } from "node:path";
|
|
310
|
-
|
|
311
|
-
// src/lane/seating.ts
|
|
312
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
313
|
-
function toModelId(model) {
|
|
314
|
-
return `${model.providerID}/${model.modelID}`;
|
|
315
|
-
}
|
|
316
|
-
function policyAllows(modelId, policy) {
|
|
317
|
-
return policy.allowedPrefixes.some((prefix) => prefix.length > 0 && modelId.startsWith(prefix));
|
|
318
|
-
}
|
|
319
|
-
function resolveSeat(role, requestedSlot, pool, policy) {
|
|
320
|
-
const found = pool[requestedSlot] ?? pool["default"];
|
|
321
|
-
if (found === void 0) {
|
|
322
|
-
return {
|
|
323
|
-
ok: false,
|
|
324
|
-
role,
|
|
325
|
-
deny: `seat denied: slot "${requestedSlot}" (and fallback "default") absent from pool`
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
const modelId = toModelId(found);
|
|
329
|
-
if (found.providerID.length === 0 || found.modelID.length === 0) {
|
|
330
|
-
return { ok: false, role, deny: `seat denied: slot "${requestedSlot}" is an empty placeholder (${modelId})` };
|
|
331
|
-
}
|
|
332
|
-
if (!policyAllows(modelId, policy)) {
|
|
333
|
-
return {
|
|
334
|
-
ok: false,
|
|
335
|
-
role,
|
|
336
|
-
deny: `seat denied by modelPolicy (E4/F1): "${modelId}" is not under any allowed prefix [${policy.allowedPrefixes.join(", ")}] \u2014 launch must not be attempted`
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
return { ok: true, role, slot: requestedSlot, modelId };
|
|
340
|
-
}
|
|
341
|
-
var SEP = "";
|
|
342
|
-
function sha256Hex(text) {
|
|
343
|
-
return createHash2("sha256").update(text, "utf8").digest("hex");
|
|
344
|
-
}
|
|
345
|
-
function computeDrawCommit(poolIds, seed) {
|
|
346
|
-
return sha256Hex(`sibyl-draw-v1${SEP}${poolIds.join(SEP)}${SEP}${seed}`);
|
|
347
|
-
}
|
|
348
|
-
function drawJudge(poolIds, seed, salt) {
|
|
349
|
-
if (poolIds.length === 0) {
|
|
350
|
-
return { ok: false, deny: "judge draw denied: empty judge pool" };
|
|
351
|
-
}
|
|
352
|
-
const drawCommit = computeDrawCommit(poolIds, seed);
|
|
353
|
-
const digest = sha256Hex(`${drawCommit}${SEP}${salt}`);
|
|
354
|
-
const uint = Number.parseInt(digest.slice(0, 8), 16);
|
|
355
|
-
const index = uint % poolIds.length;
|
|
356
|
-
const modelId = poolIds[index];
|
|
357
|
-
return { ok: true, draw: { index, modelId, drawCommit } };
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// src/verdict/index.ts
|
|
361
|
-
var OPEN_BRACE = 123;
|
|
362
|
-
var CLOSE_BRACE = 125;
|
|
363
|
-
var QUOTE = 34;
|
|
364
|
-
var BACKSLASH = 92;
|
|
365
|
-
var FENCE_RE = /```(?:json)?[ \t]*\r?\n?([\s\S]*?)```/gi;
|
|
366
|
-
function findBalancedObject(text, start) {
|
|
367
|
-
if (text.charCodeAt(start) !== OPEN_BRACE) return null;
|
|
368
|
-
let depth = 0;
|
|
369
|
-
let inString = false;
|
|
370
|
-
let escaped = false;
|
|
371
|
-
for (let i = start; i < text.length; i++) {
|
|
372
|
-
const c = text.charCodeAt(i);
|
|
373
|
-
if (inString) {
|
|
374
|
-
if (escaped) escaped = false;
|
|
375
|
-
else if (c === BACKSLASH) escaped = true;
|
|
376
|
-
else if (c === QUOTE) inString = false;
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
if (c === QUOTE) inString = true;
|
|
380
|
-
else if (c === OPEN_BRACE) depth++;
|
|
381
|
-
else if (c === CLOSE_BRACE) {
|
|
382
|
-
depth--;
|
|
383
|
-
if (depth === 0) return text.slice(start, i + 1);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
function firstParseableObject(text) {
|
|
389
|
-
for (let i = 0; i < text.length; i++) {
|
|
390
|
-
if (text.charCodeAt(i) !== OPEN_BRACE) continue;
|
|
391
|
-
const candidate = findBalancedObject(text, i);
|
|
392
|
-
if (candidate === null) continue;
|
|
393
|
-
try {
|
|
394
|
-
JSON.parse(candidate);
|
|
395
|
-
return candidate;
|
|
396
|
-
} catch {
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
return null;
|
|
400
|
-
}
|
|
401
|
-
function extractVerdictJson(text) {
|
|
402
|
-
for (const m of text.matchAll(FENCE_RE)) {
|
|
403
|
-
const fenced = firstParseableObject(m[1] ?? "");
|
|
404
|
-
if (fenced !== null) return fenced;
|
|
405
|
-
}
|
|
406
|
-
return firstParseableObject(text);
|
|
407
|
-
}
|
|
408
|
-
function rejectVerdict(reason) {
|
|
409
|
-
return {
|
|
410
|
-
verdict: "REJECT",
|
|
411
|
-
confidence: 0,
|
|
412
|
-
reasons: [`verdict-unparseable: ${reason}`],
|
|
413
|
-
must_fix: []
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
var FAIL_CLOSED_REJECT = rejectVerdict("no-parse-performed");
|
|
417
|
-
|
|
418
419
|
// src/chamber/protocol.ts
|
|
419
420
|
var CHAMBER_ROLES = ["evidence", "pro", "con", "judge"];
|
|
420
421
|
function artifactRel(role, round, kind) {
|
|
@@ -679,11 +680,167 @@ async function startRecord(cfg, roster, drawCommit) {
|
|
|
679
680
|
artifacts: [],
|
|
680
681
|
evidenceRows: 0
|
|
681
682
|
};
|
|
683
|
+
if (cfg.instrument !== void 0) base.instrument = cfg.instrument;
|
|
684
|
+
if (cfg.independence !== void 0) base.independence = cfg.independence;
|
|
682
685
|
const first = await finalizeRecord(base);
|
|
683
686
|
if (!first.ok) throw new Error(`START record refused: ${first.drift.join("; ")}`);
|
|
684
687
|
return first.record;
|
|
685
688
|
}
|
|
686
689
|
|
|
690
|
+
// src/personas.ts
|
|
691
|
+
var ARCHITECT_OUTPUT_CONTRACT = 'Respond with EXACTLY one JSON object and nothing else - no prose, no markdown fences, no extra keys - matching: {"tasks":[{"id":<string>,"title":<string>,"instructions":<string>,"dependsOn":[<task id strings>]}],"concurrency":<integer >= 1>,"notes":<string>}. "tasks" are the units of work decomposing the goal, "dependsOn" lists task ids that must finish first, "concurrency" is the maximum number of tasks safe to run in parallel, "notes" carries planning remarks (empty string if none).';
|
|
692
|
+
var ARCHITECT_SYSTEM = "You are ARCHITECT, the SIBYL planning persona. Decompose the given artifact-production goal into a dependency-ordered workflow of minimal, independently executable tasks. " + ARCHITECT_OUTPUT_CONTRACT;
|
|
693
|
+
var ARCHITECT_PERSONA = {
|
|
694
|
+
id: "ARCHITECT",
|
|
695
|
+
title: "workflow architect (planner)",
|
|
696
|
+
system: ARCHITECT_SYSTEM,
|
|
697
|
+
modelSlot: "architect"
|
|
698
|
+
};
|
|
699
|
+
function repairDemand(why) {
|
|
700
|
+
return `Your previous reply was not a valid verdict JSON (${why}). Reply again with EXACTLY one JSON object and nothing else - no prose, no markdown fences: {"verdict":"APPROVE"|"REJECT","confidence":<number between 0 and 1>,"reasons":[<strings>],"must_fix":[<strings>]}`;
|
|
701
|
+
}
|
|
702
|
+
var SWARM_JUDGE_SYSTEM = "You are the SIBYL swarm judge. You rule on pipeline reports with exactly one word: APPROVE, REJECT, or EXHAUSTED.";
|
|
703
|
+
var SWARM_JUDGE_WORD_CONTRACT = "Respond with EXACTLY one word and nothing else: APPROVE, REJECT, or EXHAUSTED.";
|
|
704
|
+
var PERSONAS = {
|
|
705
|
+
MELCHIOR: {
|
|
706
|
+
id: "MELCHIOR",
|
|
707
|
+
title: COUNCILOR_PERSONAS.MELCHIOR.title,
|
|
708
|
+
system: COUNCILOR_PERSONAS.MELCHIOR.system,
|
|
709
|
+
modelSlot: "melchior"
|
|
710
|
+
},
|
|
711
|
+
BALTHASAR: {
|
|
712
|
+
id: "BALTHASAR",
|
|
713
|
+
title: COUNCILOR_PERSONAS.BALTHASAR.title,
|
|
714
|
+
system: COUNCILOR_PERSONAS.BALTHASAR.system,
|
|
715
|
+
modelSlot: "balthasar"
|
|
716
|
+
},
|
|
717
|
+
CASPER: {
|
|
718
|
+
id: "CASPER",
|
|
719
|
+
title: COUNCILOR_PERSONAS.CASPER.title,
|
|
720
|
+
system: COUNCILOR_PERSONAS.CASPER.system,
|
|
721
|
+
modelSlot: "casper"
|
|
722
|
+
},
|
|
723
|
+
ARCHITECT: ARCHITECT_PERSONA
|
|
724
|
+
};
|
|
725
|
+
var PERSONA_IDS = [...COUNCILORS, "ARCHITECT"];
|
|
726
|
+
var BY_ID = new Map(
|
|
727
|
+
PERSONA_IDS.map((id) => [id, PERSONAS[id]])
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
// src/instrument.ts
|
|
731
|
+
function sha256Hex2(text) {
|
|
732
|
+
return createHash3("sha256").update(text, "utf8").digest("hex");
|
|
733
|
+
}
|
|
734
|
+
var REPAIR_SENTINEL = "<parse-failure-why>";
|
|
735
|
+
var SENTINEL_CFG = {
|
|
736
|
+
runId: "sibyl-sentinel",
|
|
737
|
+
runDir: "/sentinel/run",
|
|
738
|
+
goal: "<goal>",
|
|
739
|
+
targetPath: "/sentinel/target.md",
|
|
740
|
+
ledgerPath: "/sentinel/ledger.jsonl",
|
|
741
|
+
seed: "<seed>",
|
|
742
|
+
maxRounds: 1,
|
|
743
|
+
pool: { default: { providerID: "", modelID: "" } },
|
|
744
|
+
policy: null,
|
|
745
|
+
slots: { evidence: "default", pro: "default", con: "default", judge: "default" },
|
|
746
|
+
judgePoolIds: [],
|
|
747
|
+
lane: null
|
|
748
|
+
};
|
|
749
|
+
function chamberRoleTexts() {
|
|
750
|
+
return {
|
|
751
|
+
"chamber-evidence-prompt": evidencePrompt(SENTINEL_CFG, "/sentinel/evidence.jsonl"),
|
|
752
|
+
"chamber-pro-prompt": proPrompt(SENTINEL_CFG, 1, "/sentinel/pro.md", []),
|
|
753
|
+
"chamber-con-prompt": conPrompt(SENTINEL_CFG, 1, "/sentinel/con.md", []),
|
|
754
|
+
"chamber-rebuttal-prompt": rebuttalPrompt(SENTINEL_CFG, "pro", 1, "/sentinel/con.md", "/sentinel/pro-rebuttal.md"),
|
|
755
|
+
"chamber-judge-prompt": judgePrompt(SENTINEL_CFG, 1, ["/sentinel/pro.md", "/sentinel/con.md"], "/sentinel/judge.json")
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function componentTexts() {
|
|
759
|
+
const texts = {
|
|
760
|
+
"repair-grammar": repairDemand(REPAIR_SENTINEL),
|
|
761
|
+
"swarm-judge-system": SWARM_JUDGE_SYSTEM,
|
|
762
|
+
"swarm-judge-word-contract": SWARM_JUDGE_WORD_CONTRACT,
|
|
763
|
+
...chamberRoleTexts()
|
|
764
|
+
};
|
|
765
|
+
for (const id of COUNCILORS) {
|
|
766
|
+
texts[`councilor-${id.toLowerCase()}`] = COUNCILOR_PERSONAS[id].system;
|
|
767
|
+
}
|
|
768
|
+
texts["architect-system"] = ARCHITECT_SYSTEM;
|
|
769
|
+
return texts;
|
|
770
|
+
}
|
|
771
|
+
var cached = null;
|
|
772
|
+
function instrumentFace() {
|
|
773
|
+
if (cached !== null) return cached;
|
|
774
|
+
const components = {};
|
|
775
|
+
for (const [name, text] of Object.entries(componentTexts())) {
|
|
776
|
+
components[name] = sha256Hex2(text);
|
|
777
|
+
}
|
|
778
|
+
const canonical = JSON.stringify(
|
|
779
|
+
Object.keys(components).sort().map((name) => [name, components[name]])
|
|
780
|
+
);
|
|
781
|
+
cached = { rulesHash: sha256Hex2(canonical), components };
|
|
782
|
+
return cached;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/chamber/synthesis.ts
|
|
786
|
+
var PERFORMANCE_ONLY_IN_LOOP = "PERFORMANCE-ONLY-IN-LOOP";
|
|
787
|
+
var MAX_RATIONALE = 6;
|
|
788
|
+
function conclude(result) {
|
|
789
|
+
const { terminal, judge, gaps } = result;
|
|
790
|
+
if (gaps.length > 0 && (terminal === "MEMBER_LOST" || terminal === "TIMEOUT")) {
|
|
791
|
+
return { conclusion: "NEEDS_HUMAN", confidence: 0 };
|
|
792
|
+
}
|
|
793
|
+
if (terminal === "CONVERGED" && judge !== null) {
|
|
794
|
+
const base = judge.conclusion;
|
|
795
|
+
const conclusion = base === "NEEDS_HUMAN" ? "NEEDS_HUMAN" : gaps.length > 0 ? "NEEDS_HUMAN" : base;
|
|
796
|
+
return { conclusion, confidence: conclusion === "NEEDS_HUMAN" ? Math.min(judge.confidence, 0.5) : judge.confidence };
|
|
797
|
+
}
|
|
798
|
+
if (judge !== null && judge.convergence === "NEEDS_ROUND") {
|
|
799
|
+
return { conclusion: "NEEDS_HUMAN", confidence: Math.min(judge.confidence, 0.5) };
|
|
800
|
+
}
|
|
801
|
+
return { conclusion: "NEEDS_HUMAN", confidence: 0 };
|
|
802
|
+
}
|
|
803
|
+
function buildVoice(result) {
|
|
804
|
+
const { record: record2, judge, terminal, gaps } = result;
|
|
805
|
+
const { conclusion, confidence } = conclude(result);
|
|
806
|
+
const rationale = judge !== null && conclusion !== "NEEDS_HUMAN" ? judge.reasons.slice(0, MAX_RATIONALE) : (judge?.reasons ?? []).slice(0, MAX_RATIONALE).concat(gaps).slice(0, MAX_RATIONALE);
|
|
807
|
+
const sealed = [
|
|
808
|
+
"DISAGREEMENT-LOG.md",
|
|
809
|
+
...new Set(record2.artifacts.map((a) => a.relPath))
|
|
810
|
+
];
|
|
811
|
+
return {
|
|
812
|
+
label: "SIBYL-ONE-VOICE",
|
|
813
|
+
honesty: PERFORMANCE_ONLY_IN_LOOP,
|
|
814
|
+
conclusion,
|
|
815
|
+
confidence: conclusion === "NEEDS_HUMAN" ? Number(confidence.toFixed(2)) : confidence,
|
|
816
|
+
rationale,
|
|
817
|
+
must_fix: judge?.must_fix ?? [],
|
|
818
|
+
open_charges: judge?.charges.length ?? 0,
|
|
819
|
+
dissent_sealed_in: sealed,
|
|
820
|
+
terminal,
|
|
821
|
+
run_id: record2.runId,
|
|
822
|
+
serial: record2.serial,
|
|
823
|
+
spotcheck: spotcheckCommand(record2.runDir)
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
function renderVoice(voice) {
|
|
827
|
+
const lines = [
|
|
828
|
+
`SIBYL \u2014 ONE CONCLUSION, ONE VOICE [${voice.label}]`,
|
|
829
|
+
`conclusion: ${voice.conclusion} confidence: ${String(voice.confidence)} terminal: ${voice.terminal}`,
|
|
830
|
+
`run: ${voice.run_id} (serial ${String(voice.serial)}) open charges: ${String(voice.open_charges)}`,
|
|
831
|
+
`honesty: ${voice.honesty} (until C-09/C-14 containment rulings \u2014 see docs/isolation-laws.md)`,
|
|
832
|
+
"rationale:",
|
|
833
|
+
...voice.rationale.map((r, i) => ` ${String(i + 1)}. ${r}`)
|
|
834
|
+
];
|
|
835
|
+
if (voice.must_fix.length > 0) {
|
|
836
|
+
lines.push("must_fix:");
|
|
837
|
+
lines.push(...voice.must_fix.map((m) => ` - ${m}`));
|
|
838
|
+
}
|
|
839
|
+
lines.push(`internal debate sealed in run dir: ${voice.dissent_sealed_in.length} artifacts + DISAGREEMENT-LOG.md (hashes in CHECKSUMS.txt)`);
|
|
840
|
+
lines.push(`verify every recorded byte: ${voice.spotcheck}`);
|
|
841
|
+
return lines.join("\n");
|
|
842
|
+
}
|
|
843
|
+
|
|
687
844
|
// src/lane/isolated.ts
|
|
688
845
|
import { spawn } from "node:child_process";
|
|
689
846
|
import { createWriteStream, existsSync } from "node:fs";
|
|
@@ -1737,7 +1894,7 @@ __export(util_exports, {
|
|
|
1737
1894
|
attachSchema: () => attachSchema,
|
|
1738
1895
|
base64ToUint8Array: () => base64ToUint8Array,
|
|
1739
1896
|
base64urlToUint8Array: () => base64urlToUint8Array,
|
|
1740
|
-
cached: () =>
|
|
1897
|
+
cached: () => cached2,
|
|
1741
1898
|
captureStackTrace: () => captureStackTrace,
|
|
1742
1899
|
cleanEnum: () => cleanEnum,
|
|
1743
1900
|
cleanRegex: () => cleanRegex,
|
|
@@ -1825,7 +1982,7 @@ function jsonStringifyReplacer(_, value) {
|
|
|
1825
1982
|
return value.toString();
|
|
1826
1983
|
return value;
|
|
1827
1984
|
}
|
|
1828
|
-
function
|
|
1985
|
+
function cached2(getter) {
|
|
1829
1986
|
const set2 = false;
|
|
1830
1987
|
return {
|
|
1831
1988
|
get value() {
|
|
@@ -1934,7 +2091,7 @@ var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace :
|
|
|
1934
2091
|
function isObject(data) {
|
|
1935
2092
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
1936
2093
|
}
|
|
1937
|
-
var allowsEval = /* @__PURE__ */
|
|
2094
|
+
var allowsEval = /* @__PURE__ */ cached2(() => {
|
|
1938
2095
|
if (globalConfig.jitless) {
|
|
1939
2096
|
return false;
|
|
1940
2097
|
}
|
|
@@ -4628,7 +4785,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
4628
4785
|
}
|
|
4629
4786
|
});
|
|
4630
4787
|
}
|
|
4631
|
-
const _normalized =
|
|
4788
|
+
const _normalized = cached2(() => normalizeDef(def));
|
|
4632
4789
|
defineLazyInternal(inst, "propValues", (zod) => {
|
|
4633
4790
|
const shape = zod.def.shape;
|
|
4634
4791
|
const propValues = {};
|
|
@@ -4688,7 +4845,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
4688
4845
|
var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => {
|
|
4689
4846
|
$ZodObject.init(inst, def);
|
|
4690
4847
|
const superParse = inst._zod.parse;
|
|
4691
|
-
const _normalized =
|
|
4848
|
+
const _normalized = cached2(() => normalizeDef(def));
|
|
4692
4849
|
const memo2 = globalConfig.memoizer;
|
|
4693
4850
|
const generateFastpass = (shape) => {
|
|
4694
4851
|
const normalized = _normalized.value;
|
|
@@ -4967,7 +5124,7 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
|
|
|
4967
5124
|
throw new Error(`Invalid discriminated union option at index "${i}"`);
|
|
4968
5125
|
}
|
|
4969
5126
|
});
|
|
4970
|
-
const disc =
|
|
5127
|
+
const disc = cached2(() => {
|
|
4971
5128
|
const opts = def.options;
|
|
4972
5129
|
const map2 = /* @__PURE__ */ new Map();
|
|
4973
5130
|
for (const o of opts) {
|
|
@@ -6050,9 +6207,9 @@ function cloneIssues(issues) {
|
|
|
6050
6207
|
}
|
|
6051
6208
|
var recursive = /* @__PURE__ */ new WeakMap();
|
|
6052
6209
|
function isRecursive(inst, stack) {
|
|
6053
|
-
const
|
|
6054
|
-
if (
|
|
6055
|
-
return
|
|
6210
|
+
const cached3 = recursive.get(inst);
|
|
6211
|
+
if (cached3 !== void 0)
|
|
6212
|
+
return cached3;
|
|
6056
6213
|
if (stack.has(inst))
|
|
6057
6214
|
return true;
|
|
6058
6215
|
stack.add(inst);
|
|
@@ -19808,15 +19965,15 @@ function visit(schema, fnOrHandlers) {
|
|
|
19808
19965
|
};
|
|
19809
19966
|
const cache = /* @__PURE__ */ new Map();
|
|
19810
19967
|
function run(s) {
|
|
19811
|
-
const
|
|
19812
|
-
if (
|
|
19968
|
+
const cached3 = cache.get(s);
|
|
19969
|
+
if (cached3 === RESOLVING) {
|
|
19813
19970
|
return new $ZodLazy({
|
|
19814
19971
|
type: "lazy",
|
|
19815
19972
|
getter: () => cache.get(s)
|
|
19816
19973
|
});
|
|
19817
19974
|
}
|
|
19818
|
-
if (
|
|
19819
|
-
return
|
|
19975
|
+
if (cached3 !== void 0)
|
|
19976
|
+
return cached3;
|
|
19820
19977
|
cache.set(s, RESOLVING);
|
|
19821
19978
|
const inner = mapInner(s);
|
|
19822
19979
|
const mapped = fn(inner, inner !== s);
|
|
@@ -20192,9 +20349,19 @@ async function resolveRun(flags) {
|
|
|
20192
20349
|
judgePoolIds.push(...flags["judge-pool"].split(",").map((s) => s.trim()).filter((s) => s.length > 0));
|
|
20193
20350
|
}
|
|
20194
20351
|
const now = /* @__PURE__ */ new Date();
|
|
20195
|
-
const
|
|
20352
|
+
const flagRunId = typeof flags["run-id"] === "string" ? flags["run-id"] : null;
|
|
20353
|
+
if (flagRunId !== null && !/^sibyl-[A-Za-z0-9-]+$/.test(flagRunId)) {
|
|
20354
|
+
return { ok: false, error: `--run-id must be a bare sibyl run id, got "${flagRunId}"` };
|
|
20355
|
+
}
|
|
20356
|
+
const runId = flagRunId ?? `sibyl-${compactIso(now)}-${randomBytes(2).toString("hex")}`;
|
|
20196
20357
|
const runDir = join7(laneCfg.runRoot, `sibyl-run-${runId}`);
|
|
20197
20358
|
await mkdir6(runDir, { recursive: true });
|
|
20359
|
+
let launchIndependence;
|
|
20360
|
+
try {
|
|
20361
|
+
const lc = JSON.parse(await readFile6(join7(runDir, "launch-context.json"), "utf8"));
|
|
20362
|
+
if (isIndependenceShape(lc["independence"])) launchIndependence = lc["independence"];
|
|
20363
|
+
} catch {
|
|
20364
|
+
}
|
|
20198
20365
|
let targetPath = targetRaw;
|
|
20199
20366
|
if (targetRaw !== "-") {
|
|
20200
20367
|
const abs = isAbsolute2(targetRaw) ? targetRaw : resolve2(process.cwd(), targetRaw);
|
|
@@ -20252,6 +20419,8 @@ async function resolveRun(flags) {
|
|
|
20252
20419
|
maxRounds,
|
|
20253
20420
|
pool: effectivePool,
|
|
20254
20421
|
policy,
|
|
20422
|
+
instrument: instrumentFace(),
|
|
20423
|
+
independence: launchIndependence,
|
|
20255
20424
|
slots,
|
|
20256
20425
|
judgePoolIds: judgePoolIds.length > 0 ? judgePoolIds : [...new Set(judgeSlotNames.map((s) => slotToId(s, effectivePool)).filter((x) => x !== null))],
|
|
20257
20426
|
lane: null
|