@agentcomms/events-daemon 0.17.0 → 0.18.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 +11 -5
- package/THIRD_PARTY_LICENSES +2 -2
- package/dist/{b3-contract-DFxcHY0I.mjs → b3-contract-B6UBBK7F.mjs} +4 -4
- package/dist/cli.mjs +417 -159
- package/dist/index.d.mts +119 -12
- package/dist/index.mjs +1 -1
- package/dist/{mcp-DXXb3Vv3-B0sHZfig.mjs → mcp-DIH4cS6P-YuKZfqTg.mjs} +181 -68
- package/dist/{stdio-CD7QQBAh.mjs → stdio-Dp1EE6ok.mjs} +28 -3
- package/package.json +11 -11
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as sourcesList, $t as assertControlSupported, A as normaliseWhatsAppSourceOptions, At as decideHeld, B as addTarget, Bt as CONTROL_PROTOCOL_VERSIONS, C as canonicalSseSubscriber, Ct as enableAll, D as normaliseResendSourceOptions, Dt as ACTIVATION_FAILURE, E as normaliseGmailSourceOptions, Et as doctor, F as canonicalJudgeBudget, Ft as catalogueList, G as addSubscriber, Gt as isControlRequest, H as targetsList, Ht as controlFailure, I as canonicalJudgeKindEnablement, It as catalogueShow, J as updateSubscriber, Jt as newInstanceRecord, K as removeSubscriber, Kt as negotiateVersion, L as judgeKindDefinition, Lt as approvalView, M as JUDGE_BUDGET_ID, Mt as dropDelivery, N as JUDGE_KIND_DEFINITIONS, Nt as heldList, O as normaliseSlackSourceOptions, Ot as isActivationFailureCode, P as canonicalJudge, Pt as retryDelivery, Q as sourceShow$1, Qt as writeInstance, R as createEventsMcpServer, Rt as EventControlClient, S as normaliseActivationDocument, St as updateJudge, T as classifySourceOptionChange, Tt as assertDoctorReportV2, U as updateTarget, Ut as encodeControlFrame, V as removeTarget$1, Vt as ControlFrameReader, W as targetTest, Wt as isControlHello, X as status, Xt as readInstance, Y as stop, Yt as processIsLive, Z as loadSqlite, Zt as removeInstance, _ as activationDocumentDigest, _t as judgeTest, an as ensureEventSocketDirectory, at as rulesList, b as canonicalTarget, bt as removeJudgeModel, cn as installErrorSink, ct as ruleTestRetained, d as B3_SECRET_TERMINAL_ORIGIN, dt as addJudge, en as assertSocketPathFits, et as createRule$1, f as isB3ControlOperation, ft as budgetShow, g as isOwnerControlWireOperation, gt as judgeModelStatus, h as OWNER_CONTROL_WIRES, ht as judgeKindsList, in as ensureEventPaths, it as ruleShow$1, j as APPROVED_TYPESAFE_MODELS, jt as deliveriesList, k as normaliseSourceOptions, kt as disableAll, lt as pause, m as renderB3ApprovalPreviewV1, mt as enableJudgeKind, nn as verifyControlSocket, nt as enableRule, on as ensureOwnerOnlyFile, ot as updateRule, p as isB3SecretOperation, pt as disableJudgeKind, q as subscribersList, qt as mayRecoverStaleInstance, rn as verifyPrivateSocketDirectory, rt as removeRule, sn as eventPaths, st as ruleTest, tn as controlEndpoint, tt as disableRule$1, ut as resume, v as canonicalFullRuleDocument, vt as judgesList, w as sseDeliveryTarget, wt as assertDoctorReportV1, x as disclosureBindingFor, xt as updateBudget, y as canonicalSubscriber, yt as removeJudge, z as VERSION, zt as probeControl } from "./b3-contract-B6UBBK7F.mjs";
|
|
3
3
|
import { a as EventDomainError, d as isJudgeKind, f as validateLocalEndpoint, g as parseIpLiteral, h as assertApprovedAddressSet, i as webhookDeliveryTarget, l as JUDGE_KIND_TYPESAFE, m as assertAddressAllowed, n as canonicalWebhookTarget, o as JUDGE_KINDS, p as AddressPolicyError, r as secretWebhookUrlDescriptor, s as JUDGE_KIND_LAYA, t as canonicalSecretWebhookUrl, u as assertJudgeKindEnabled } from "./webhook-target-DyDTwWhV.mjs";
|
|
4
4
|
import { a as WriterQuiescer, c as openEventSecretStore, o as withEventWriterLease, r as RecordStorageError, s as migrateEventSecrets, t as EventRecordCipher } from "./records-DsUxYBwb.mjs";
|
|
5
5
|
import process$1 from "node:process";
|
|
@@ -3365,6 +3365,7 @@ var ImmutableVersions = class {
|
|
|
3365
3365
|
assertEmbeddedVersions(rule) {
|
|
3366
3366
|
const embedded = [
|
|
3367
3367
|
...rule.targets.map((target) => ({
|
|
3368
|
+
kind: "target",
|
|
3368
3369
|
table: "target_versions",
|
|
3369
3370
|
column: "target_id",
|
|
3370
3371
|
id: target.targetId,
|
|
@@ -3372,6 +3373,7 @@ var ImmutableVersions = class {
|
|
|
3372
3373
|
document: target
|
|
3373
3374
|
})),
|
|
3374
3375
|
...rule.subscribers.map((subscriber) => ({
|
|
3376
|
+
kind: "subscriber",
|
|
3375
3377
|
table: "subscriber_versions",
|
|
3376
3378
|
column: "subscriber_id",
|
|
3377
3379
|
id: subscriber.subscriberId,
|
|
@@ -3379,6 +3381,7 @@ var ImmutableVersions = class {
|
|
|
3379
3381
|
document: subscriber
|
|
3380
3382
|
})),
|
|
3381
3383
|
...rule.agentic === void 0 ? [] : [{
|
|
3384
|
+
kind: "judge",
|
|
3382
3385
|
table: "judge_versions",
|
|
3383
3386
|
column: "judge_id",
|
|
3384
3387
|
id: rule.agentic.judge.judgeId,
|
|
@@ -3390,8 +3393,19 @@ var ImmutableVersions = class {
|
|
|
3390
3393
|
const row = this.#database.prepare(`SELECT document FROM ${entry.table} WHERE ${entry.column} = ? AND version = ?`).get(entry.id, entry.version);
|
|
3391
3394
|
if (row === void 0) throw new EventDomainError("VERSION_DOCUMENT_INVALID", `the rule names ${entry.id} version ${entry.version}, which is not a stored version`);
|
|
3392
3395
|
if (row.document !== canonicalJson(entry.document)) throw new EventDomainError("VERSION_DOCUMENT_INVALID", `the rule carries a copy of ${entry.id} version ${entry.version} that differs from the stored version`);
|
|
3396
|
+
if (entry.kind === "judge" && this.#embeddedJudgeIsRevoked(entry.id, entry.version)) throw new EventDomainError("VERSION_DOCUMENT_INVALID", `the rule names revoked judge ${entry.id} version ${entry.version}`);
|
|
3393
3397
|
}
|
|
3394
3398
|
}
|
|
3399
|
+
#embeddedJudgeIsRevoked(judgeId, version) {
|
|
3400
|
+
return this.#database.prepare(`SELECT 1 AS present
|
|
3401
|
+
FROM judge_versions AS stored
|
|
3402
|
+
LEFT JOIN object_revocations AS revoked
|
|
3403
|
+
ON revoked.kind = 'judge'
|
|
3404
|
+
AND revoked.object_id = stored.judge_id
|
|
3405
|
+
AND revoked.version = stored.version
|
|
3406
|
+
WHERE stored.judge_id = ? AND stored.version = ?
|
|
3407
|
+
AND (stored.revoked_at IS NOT NULL OR revoked.revoked_at IS NOT NULL)`).get(judgeId, version) !== void 0;
|
|
3408
|
+
}
|
|
3395
3409
|
insert(table, kind, objectId, version, document) {
|
|
3396
3410
|
const id = versionId(objectId, version);
|
|
3397
3411
|
const persisted = documentRecord(document);
|
|
@@ -7292,7 +7306,7 @@ function readReservation(database, id) {
|
|
|
7292
7306
|
function readReservationForSourceWork(database, workId, scope) {
|
|
7293
7307
|
return database.prepare(`SELECT * FROM judge_budget_reservations
|
|
7294
7308
|
WHERE work_id = ? AND work_scope = 'source-owned' AND source = ? AND account_id = ?
|
|
7295
|
-
AND event_id = ? AND rule_id = ? AND rule_version =
|
|
7309
|
+
AND event_id = ? AND rule_id = ? AND rule_version = ? AND state IN ('reserved', 'in-flight')`).get(workId, scope.source, scope.accountId, scope.eventId, scope.ruleId, scope.ruleVersion) ?? null;
|
|
7296
7310
|
}
|
|
7297
7311
|
function reservationView(row) {
|
|
7298
7312
|
const scope = sourceScope(row);
|
|
@@ -7399,8 +7413,7 @@ function reserveJudgeWork(input) {
|
|
|
7399
7413
|
activeKind(input.store.database, judge.kind);
|
|
7400
7414
|
const limits = ruleAuthority(input.store.database, input.scope, judge);
|
|
7401
7415
|
if (!sameCanonical(limits, input.limits)) refusal$2("JUDGE_AUTHORITY_CHANGED", "the supplied limits differ from the immutable rule authority");
|
|
7402
|
-
|
|
7403
|
-
if (prior?.state === "reserved" || prior?.state === "in-flight") refusal$2("JUDGE_WORK_OWNER_HELD", "a live judge reservation already owns this source work");
|
|
7416
|
+
if (readReservationForSourceWork(input.store.database, input.workId, input.scope) !== null) refusal$2("JUDGE_WORK_OWNER_HELD", "a live judge reservation already owns this source work");
|
|
7404
7417
|
assertReservationLimits(input.store.database, {
|
|
7405
7418
|
scope: input.scope,
|
|
7406
7419
|
budget,
|
|
@@ -7410,15 +7423,6 @@ function reserveJudgeWork(input) {
|
|
|
7410
7423
|
now: input.now,
|
|
7411
7424
|
adding: true
|
|
7412
7425
|
});
|
|
7413
|
-
if (prior?.state === "released") {
|
|
7414
|
-
input.store.database.prepare(`UPDATE judge_budget_reservations
|
|
7415
|
-
SET estimated_input_tokens = ?, actual_input_tokens = NULL, state = 'reserved', concurrency_owned = 1,
|
|
7416
|
-
reserved_at = ?, in_flight_at = NULL, settled_at = NULL, released_at = NULL, switch_generation = ?
|
|
7417
|
-
WHERE id = ? AND state = 'released' AND concurrency_owned = 0`).run(estimate, input.now, input.switchGeneration, prior.id);
|
|
7418
|
-
const reactivated = readReservation(input.store.database, prior.id);
|
|
7419
|
-
if (reactivated === null || reactivated.state !== "reserved") refusal$2("JUDGE_AUTHORITY_CHANGED", "the released judge work could not be re-reserved");
|
|
7420
|
-
return reservationView(reactivated);
|
|
7421
|
-
}
|
|
7422
7426
|
return insertReservation(input.store.database, {
|
|
7423
7427
|
...input,
|
|
7424
7428
|
judge,
|
|
@@ -7477,12 +7481,14 @@ function beginJudgeTransport(input) {
|
|
|
7477
7481
|
if (row === null || row.state !== "reserved") return false;
|
|
7478
7482
|
try {
|
|
7479
7483
|
const authority = assertReservationAuthority(input.store.database, row, input.now);
|
|
7480
|
-
const
|
|
7484
|
+
const source = sourceScope(row);
|
|
7485
|
+
const scope = source ?? {
|
|
7481
7486
|
scope: "synthetic-test",
|
|
7482
7487
|
testWorkId: row.test_work_id,
|
|
7483
7488
|
judgeId: row.judge_id,
|
|
7484
7489
|
judgeVersion: row.judge_version
|
|
7485
7490
|
};
|
|
7491
|
+
if (source !== null) assertSourceReservationBoundary(input.store.database, source, row.switch_generation);
|
|
7486
7492
|
assertReservationLimits(input.store.database, {
|
|
7487
7493
|
scope,
|
|
7488
7494
|
budget: authority.budget,
|
|
@@ -7492,6 +7498,8 @@ function beginJudgeTransport(input) {
|
|
|
7492
7498
|
now: input.now,
|
|
7493
7499
|
adding: false
|
|
7494
7500
|
});
|
|
7501
|
+
assertHostedKeyGeneration(input.store.database, row, input.hostedKey);
|
|
7502
|
+
input.assertBeforeTransition?.();
|
|
7495
7503
|
} catch (error) {
|
|
7496
7504
|
releaseReservationInTransaction(input.store.database, row.id, input.now);
|
|
7497
7505
|
refused = true;
|
|
@@ -7506,6 +7514,67 @@ function beginJudgeTransport(input) {
|
|
|
7506
7514
|
return began;
|
|
7507
7515
|
}
|
|
7508
7516
|
/**
|
|
7517
|
+
* Couples the durable I/O transition to the sealed transport's synchronous gate. Hosted work enters at DNS; a
|
|
7518
|
+
* literal-loopback judge has no DNS action and enters at TCP. Every later gate rechecks the complete live authority.
|
|
7519
|
+
*/
|
|
7520
|
+
var JudgeReservationIoGate = class {
|
|
7521
|
+
#store;
|
|
7522
|
+
#reservationId;
|
|
7523
|
+
#judgeKind;
|
|
7524
|
+
#now;
|
|
7525
|
+
#hostedKey;
|
|
7526
|
+
#entered = false;
|
|
7527
|
+
#firstGateError;
|
|
7528
|
+
constructor(input) {
|
|
7529
|
+
this.#store = input.store;
|
|
7530
|
+
this.#reservationId = input.reservationId;
|
|
7531
|
+
this.#judgeKind = input.judgeKind;
|
|
7532
|
+
this.#now = input.now;
|
|
7533
|
+
this.#hostedKey = input.hostedKey;
|
|
7534
|
+
}
|
|
7535
|
+
get firstGateError() {
|
|
7536
|
+
return this.#firstGateError;
|
|
7537
|
+
}
|
|
7538
|
+
finalGate = (phase, assertBeforeTransition) => {
|
|
7539
|
+
const firstPhysicalPhase = this.#judgeKind === "typesafe" ? "dns" : "tcp";
|
|
7540
|
+
if (!this.#entered) {
|
|
7541
|
+
if (phase !== firstPhysicalPhase) {
|
|
7542
|
+
assertBeforeTransition?.();
|
|
7543
|
+
return;
|
|
7544
|
+
}
|
|
7545
|
+
let deadlineRefused = false;
|
|
7546
|
+
try {
|
|
7547
|
+
if (!beginJudgeTransport({
|
|
7548
|
+
store: this.#store,
|
|
7549
|
+
reservationId: this.#reservationId,
|
|
7550
|
+
now: this.#now(),
|
|
7551
|
+
...this.#hostedKey === void 0 ? {} : { hostedKey: this.#hostedKey },
|
|
7552
|
+
assertBeforeTransition: () => {
|
|
7553
|
+
try {
|
|
7554
|
+
assertBeforeTransition?.();
|
|
7555
|
+
} catch (error) {
|
|
7556
|
+
deadlineRefused = true;
|
|
7557
|
+
throw error;
|
|
7558
|
+
}
|
|
7559
|
+
}
|
|
7560
|
+
})) refusal$2("JUDGE_AUTHORITY_CHANGED", "the judge reservation was lost before physical I/O");
|
|
7561
|
+
} catch (error) {
|
|
7562
|
+
if (!deadlineRefused) this.#firstGateError = error;
|
|
7563
|
+
throw error;
|
|
7564
|
+
}
|
|
7565
|
+
this.#entered = true;
|
|
7566
|
+
return;
|
|
7567
|
+
}
|
|
7568
|
+
assertJudgeReservationStillInFlight({
|
|
7569
|
+
store: this.#store,
|
|
7570
|
+
reservationId: this.#reservationId,
|
|
7571
|
+
now: this.#now(),
|
|
7572
|
+
...this.#hostedKey === void 0 ? {} : { hostedKey: this.#hostedKey }
|
|
7573
|
+
});
|
|
7574
|
+
assertBeforeTransition?.();
|
|
7575
|
+
};
|
|
7576
|
+
};
|
|
7577
|
+
/**
|
|
7509
7578
|
* The synchronous final transport/decision fence. It reuses the one reservation authority reader rather than
|
|
7510
7579
|
* manufacturing a second reservation path, and is safe to call immediately beside each Task-6 I/O action.
|
|
7511
7580
|
*/
|
|
@@ -7513,21 +7582,23 @@ function assertJudgeReservationInFlightInTransaction(database, reservationId, no
|
|
|
7513
7582
|
const row = readReservation(database, reservationId);
|
|
7514
7583
|
if (row === null || row.state !== "in-flight" || row.concurrency_owned !== 1) refusal$2("JUDGE_AUTHORITY_CHANGED", "the judge reservation is no longer in flight");
|
|
7515
7584
|
assertReservationAuthority(database, row, now);
|
|
7516
|
-
|
|
7517
|
-
if (row.judge_id !== hostedKey.judgeId || row.judge_version !== hostedKey.judgeVersion) refusal$2("JUDGE_AUTHORITY_CHANGED", "the hosted judge key does not belong to this reservation");
|
|
7518
|
-
if (database.prepare(`SELECT 1 AS present
|
|
7519
|
-
FROM event_secret_generations AS generation
|
|
7520
|
-
JOIN judge_versions AS judge
|
|
7521
|
-
ON judge.judge_id = generation.owner_id AND judge.version = generation.owner_version
|
|
7522
|
-
WHERE generation.owner_kind = 'judge' AND generation.purpose = 'judge-key'
|
|
7523
|
-
AND generation.owner_id = ? AND generation.owner_version = ? AND generation.generation = ?
|
|
7524
|
-
AND generation.lifecycle = 'current' AND generation.owner_digest = judge.digest
|
|
7525
|
-
AND judge.revoked_at IS NULL`).get(hostedKey.judgeId, hostedKey.judgeVersion, hostedKey.generation) === void 0) refusal$2("JUDGE_AUTHORITY_CHANGED", "the hosted judge key generation is no longer current");
|
|
7526
|
-
}
|
|
7585
|
+
assertHostedKeyGeneration(database, row, hostedKey);
|
|
7527
7586
|
const scope = sourceScope(row);
|
|
7528
7587
|
if (scope === null) return;
|
|
7529
7588
|
assertSourceReservationBoundary(database, scope, row.switch_generation);
|
|
7530
7589
|
}
|
|
7590
|
+
function assertHostedKeyGeneration(database, row, hostedKey) {
|
|
7591
|
+
if (hostedKey === void 0) return;
|
|
7592
|
+
if (row.judge_id !== hostedKey.judgeId || row.judge_version !== hostedKey.judgeVersion) refusal$2("JUDGE_AUTHORITY_CHANGED", "the hosted judge key does not belong to this reservation");
|
|
7593
|
+
if (database.prepare(`SELECT 1 AS present
|
|
7594
|
+
FROM event_secret_generations AS generation
|
|
7595
|
+
JOIN judge_versions AS judge
|
|
7596
|
+
ON judge.judge_id = generation.owner_id AND judge.version = generation.owner_version
|
|
7597
|
+
WHERE generation.owner_kind = 'judge' AND generation.purpose = 'judge-key'
|
|
7598
|
+
AND generation.owner_id = ? AND generation.owner_version = ? AND generation.generation = ?
|
|
7599
|
+
AND generation.lifecycle = 'current' AND generation.owner_digest = judge.digest
|
|
7600
|
+
AND judge.revoked_at IS NULL`).get(hostedKey.judgeId, hostedKey.judgeVersion, hostedKey.generation) === void 0) refusal$2("JUDGE_AUTHORITY_CHANGED", "the hosted judge key generation is no longer current");
|
|
7601
|
+
}
|
|
7531
7602
|
function assertSourceReservationBoundary(database, scope, switchGeneration) {
|
|
7532
7603
|
const settings = database.prepare("SELECT enabled, paused, switch_generation FROM event_settings WHERE singleton = 1").get();
|
|
7533
7604
|
if (settings?.paused === 1) refusal$2("JUDGE_PAUSED", "the event switch is paused before the judge boundary");
|
|
@@ -7540,20 +7611,10 @@ function assertJudgeReservationStillInFlight(input) {
|
|
|
7540
7611
|
assertJudgeReservationInFlightInTransaction(input.store.database, input.reservationId, input.now, input.hostedKey);
|
|
7541
7612
|
});
|
|
7542
7613
|
}
|
|
7543
|
-
function releaseReservationInTransaction(database, reservationId, now
|
|
7614
|
+
function releaseReservationInTransaction(database, reservationId, now) {
|
|
7544
7615
|
return database.prepare(`UPDATE judge_budget_reservations
|
|
7545
7616
|
SET state = 'released', concurrency_owned = 0, released_at = ?
|
|
7546
|
-
WHERE id = ? AND concurrency_owned = 1
|
|
7547
|
-
AND state != 'settled' AND state != 'released'
|
|
7548
|
-
AND state = CASE WHEN ? = 1 THEN state ELSE 'reserved' END`).run(now, reservationId, mayReleaseInFlight ? 1 : 0).changes === 1;
|
|
7549
|
-
}
|
|
7550
|
-
/**
|
|
7551
|
-
* Pre-I/O loss is free: a reserved call releases normally. `beforeIo` is an intentionally narrow transport proof
|
|
7552
|
-
* that lets a final fence refusal release the just-marked in-flight row too, because no DNS, TCP, TLS, or raw write
|
|
7553
|
-
* was entered and therefore there is no provider work to charge.
|
|
7554
|
-
*/
|
|
7555
|
-
function releaseJudgeWork(input) {
|
|
7556
|
-
return input.store.immediate(() => releaseReservationInTransaction(input.store.database, input.reservationId, input.now, input.beforeIo === true));
|
|
7617
|
+
WHERE id = ? AND concurrency_owned = 1 AND state = 'reserved'`).run(now, reservationId).changes === 1;
|
|
7557
7618
|
}
|
|
7558
7619
|
function terminalReason(result) {
|
|
7559
7620
|
if (result === "unknown" || result === "timeout" || result === "transport-failure") return "judge-io-unknown";
|
|
@@ -7607,6 +7668,24 @@ function settleJudgeWork(input) {
|
|
|
7607
7668
|
testFailpoint: input.testFailpoint
|
|
7608
7669
|
}));
|
|
7609
7670
|
}
|
|
7671
|
+
/**
|
|
7672
|
+
* Closes a refused transport from the durable boundary state, not from the transport's advisory `preIo` flag. A
|
|
7673
|
+
* refusal that reached the synchronous physical-I/O gate is already in flight and must settle pessimistically;
|
|
7674
|
+
* every earlier refusal is still reserved and releases without a rolling charge.
|
|
7675
|
+
*/
|
|
7676
|
+
function finalizeJudgeTransportRefusal(input) {
|
|
7677
|
+
return input.store.immediate(() => {
|
|
7678
|
+
const row = readReservation(input.store.database, input.reservationId);
|
|
7679
|
+
if (row === null) return null;
|
|
7680
|
+
if (row.state === "released" || row.state === "settled") return row.state;
|
|
7681
|
+
if (row.state === "reserved") return releaseReservationInTransaction(input.store.database, row.id, input.now) ? "released" : null;
|
|
7682
|
+
return settleReservationInTransaction(input.store.database, {
|
|
7683
|
+
reservationId: row.id,
|
|
7684
|
+
result: input.result,
|
|
7685
|
+
now: input.now
|
|
7686
|
+
}) ? "settled" : null;
|
|
7687
|
+
});
|
|
7688
|
+
}
|
|
7610
7689
|
/** Used only by the shared recovery closure; no other module may reimplement these state transitions. */
|
|
7611
7690
|
function recoverOneJudgeReservationInTransaction(database, reservationId, now) {
|
|
7612
7691
|
const row = readReservation(database, reservationId);
|
|
@@ -11468,6 +11547,119 @@ const EVENT_MIGRATIONS = [
|
|
|
11468
11547
|
"CREATE INDEX account_revocations_account_source ON account_revocations(account_id, source)",
|
|
11469
11548
|
"UPDATE meta SET value = '21' WHERE key = 'schema_version'"
|
|
11470
11549
|
]
|
|
11550
|
+
},
|
|
11551
|
+
{
|
|
11552
|
+
version: 22,
|
|
11553
|
+
name: "event-judge-budget-attempts-v1",
|
|
11554
|
+
statements: [
|
|
11555
|
+
`CREATE TABLE judge_budget_reservations_v22 (
|
|
11556
|
+
id TEXT PRIMARY KEY,
|
|
11557
|
+
work_id TEXT NOT NULL,
|
|
11558
|
+
work_scope TEXT NOT NULL CHECK (work_scope IN ('source-owned', 'synthetic-test')),
|
|
11559
|
+
source TEXT,
|
|
11560
|
+
account_id TEXT,
|
|
11561
|
+
event_id TEXT,
|
|
11562
|
+
rule_id TEXT,
|
|
11563
|
+
rule_version INTEGER CHECK (rule_version > 0),
|
|
11564
|
+
judge_id TEXT NOT NULL,
|
|
11565
|
+
judge_version INTEGER NOT NULL CHECK (judge_version > 0),
|
|
11566
|
+
judge_kind TEXT NOT NULL CHECK (judge_kind IN (${JUDGE_KIND_SQL_VALUES})),
|
|
11567
|
+
test_work_id TEXT,
|
|
11568
|
+
budget_version INTEGER NOT NULL REFERENCES judge_budget_versions(version),
|
|
11569
|
+
provider TEXT,
|
|
11570
|
+
global_ledger_key TEXT NOT NULL CHECK (global_ledger_key = 'installation'),
|
|
11571
|
+
state TEXT NOT NULL CHECK (state IN ('reserved', 'in-flight', 'settled', 'released')),
|
|
11572
|
+
estimated_input_tokens INTEGER NOT NULL CHECK (estimated_input_tokens >= 0),
|
|
11573
|
+
actual_input_tokens INTEGER CHECK (actual_input_tokens >= 0),
|
|
11574
|
+
concurrency_owned INTEGER NOT NULL CHECK (concurrency_owned IN (0, 1)),
|
|
11575
|
+
reserved_at INTEGER NOT NULL,
|
|
11576
|
+
in_flight_at INTEGER,
|
|
11577
|
+
settled_at INTEGER,
|
|
11578
|
+
released_at INTEGER,
|
|
11579
|
+
switch_generation INTEGER NOT NULL CHECK (switch_generation >= 0),
|
|
11580
|
+
test_authority_rule_id TEXT,
|
|
11581
|
+
test_authority_rule_version INTEGER CHECK (test_authority_rule_version > 0),
|
|
11582
|
+
test_authority_activation_id TEXT,
|
|
11583
|
+
test_authority_approval_id TEXT,
|
|
11584
|
+
test_authority_challenge_hash TEXT CHECK (
|
|
11585
|
+
test_authority_challenge_hash IS NULL
|
|
11586
|
+
OR (length(test_authority_challenge_hash) = 64
|
|
11587
|
+
AND test_authority_challenge_hash NOT GLOB '*[^0-9a-f]*')
|
|
11588
|
+
),
|
|
11589
|
+
test_authority_challenge_origin TEXT CHECK (test_authority_challenge_origin IN ('terminal', 'view')),
|
|
11590
|
+
test_authority_challenge_expires_at INTEGER,
|
|
11591
|
+
FOREIGN KEY (rule_id, rule_version) REFERENCES rule_versions(rule_id, version),
|
|
11592
|
+
FOREIGN KEY (judge_id, judge_version) REFERENCES judge_versions(judge_id, version),
|
|
11593
|
+
CHECK (
|
|
11594
|
+
(work_scope = 'source-owned'
|
|
11595
|
+
AND source IS NOT NULL
|
|
11596
|
+
AND source IN ('gmail', 'slack', 'resend', 'whatsapp')
|
|
11597
|
+
AND account_id IS NOT NULL
|
|
11598
|
+
AND event_id IS NOT NULL
|
|
11599
|
+
AND rule_id IS NOT NULL
|
|
11600
|
+
AND rule_version IS NOT NULL
|
|
11601
|
+
AND test_work_id IS NULL
|
|
11602
|
+
AND provider IS NOT NULL)
|
|
11603
|
+
OR
|
|
11604
|
+
(work_scope = 'synthetic-test'
|
|
11605
|
+
AND source IS NULL
|
|
11606
|
+
AND account_id IS NULL
|
|
11607
|
+
AND event_id IS NULL
|
|
11608
|
+
AND rule_id IS NULL
|
|
11609
|
+
AND rule_version IS NULL
|
|
11610
|
+
AND test_work_id IS NOT NULL
|
|
11611
|
+
AND provider IS NULL)
|
|
11612
|
+
)
|
|
11613
|
+
) STRICT`,
|
|
11614
|
+
`INSERT INTO judge_budget_reservations_v22
|
|
11615
|
+
(id, work_id, work_scope, source, account_id, event_id, rule_id, rule_version, judge_id, judge_version,
|
|
11616
|
+
judge_kind, test_work_id, budget_version, provider, global_ledger_key, state, estimated_input_tokens,
|
|
11617
|
+
actual_input_tokens, concurrency_owned, reserved_at, in_flight_at, settled_at, released_at, switch_generation,
|
|
11618
|
+
test_authority_rule_id, test_authority_rule_version, test_authority_activation_id, test_authority_approval_id,
|
|
11619
|
+
test_authority_challenge_hash, test_authority_challenge_origin, test_authority_challenge_expires_at)
|
|
11620
|
+
SELECT id, work_id, work_scope, source, account_id, event_id, rule_id, rule_version, judge_id, judge_version,
|
|
11621
|
+
judge_kind, test_work_id, budget_version, provider, global_ledger_key, state, estimated_input_tokens,
|
|
11622
|
+
actual_input_tokens, concurrency_owned, reserved_at, in_flight_at, settled_at, released_at,
|
|
11623
|
+
switch_generation, test_authority_rule_id, test_authority_rule_version, test_authority_activation_id,
|
|
11624
|
+
test_authority_approval_id, test_authority_challenge_hash, test_authority_challenge_origin,
|
|
11625
|
+
test_authority_challenge_expires_at
|
|
11626
|
+
FROM judge_budget_reservations`,
|
|
11627
|
+
"DROP TABLE judge_budget_reservations",
|
|
11628
|
+
"ALTER TABLE judge_budget_reservations_v22 RENAME TO judge_budget_reservations",
|
|
11629
|
+
`CREATE UNIQUE INDEX judge_budget_reservations_live_work_identity
|
|
11630
|
+
ON judge_budget_reservations(work_id)
|
|
11631
|
+
WHERE state IN ('reserved', 'in-flight')`,
|
|
11632
|
+
`CREATE INDEX judge_budget_reservations_rule_rolling
|
|
11633
|
+
ON judge_budget_reservations(rule_id, reserved_at)
|
|
11634
|
+
WHERE work_scope = 'source-owned'`,
|
|
11635
|
+
`CREATE INDEX judge_budget_reservations_provider_rolling
|
|
11636
|
+
ON judge_budget_reservations(provider, reserved_at)
|
|
11637
|
+
WHERE provider IS NOT NULL`,
|
|
11638
|
+
`CREATE INDEX judge_budget_reservations_global_rolling
|
|
11639
|
+
ON judge_budget_reservations(global_ledger_key, reserved_at)`,
|
|
11640
|
+
`CREATE UNIQUE INDEX judge_budget_reservations_source_scope
|
|
11641
|
+
ON judge_budget_reservations(source, account_id, event_id, rule_id, rule_version)
|
|
11642
|
+
WHERE work_scope = 'source-owned' AND state IN ('reserved', 'in-flight')`,
|
|
11643
|
+
`CREATE INDEX judge_budget_reservations_synthetic_scope
|
|
11644
|
+
ON judge_budget_reservations(test_work_id, judge_id, judge_version, state)
|
|
11645
|
+
WHERE work_scope = 'synthetic-test'`,
|
|
11646
|
+
`CREATE INDEX judge_budget_reservations_kind_scope
|
|
11647
|
+
ON judge_budget_reservations(judge_kind, work_scope, state)`,
|
|
11648
|
+
`CREATE INDEX judge_budget_reservations_synthetic_authority
|
|
11649
|
+
ON judge_budget_reservations(test_authority_rule_id, test_authority_rule_version, test_authority_activation_id,
|
|
11650
|
+
test_authority_approval_id, test_authority_challenge_hash)
|
|
11651
|
+
WHERE work_scope = 'synthetic-test'`,
|
|
11652
|
+
`CREATE TRIGGER judge_budget_reservations_state_machine
|
|
11653
|
+
BEFORE UPDATE OF state ON judge_budget_reservations
|
|
11654
|
+
WHEN NEW.state <> OLD.state AND NOT (
|
|
11655
|
+
(OLD.state = 'reserved' AND NEW.state IN ('in-flight', 'released'))
|
|
11656
|
+
OR (OLD.state = 'in-flight' AND NEW.state = 'settled')
|
|
11657
|
+
)
|
|
11658
|
+
BEGIN
|
|
11659
|
+
SELECT RAISE(ABORT, 'invalid judge reservation state transition');
|
|
11660
|
+
END`,
|
|
11661
|
+
"UPDATE meta SET value = '22' WHERE key = 'schema_version'"
|
|
11662
|
+
]
|
|
11471
11663
|
}
|
|
11472
11664
|
];
|
|
11473
11665
|
function initialiseLedger(database) {
|
|
@@ -11477,12 +11669,32 @@ function initialiseLedger(database) {
|
|
|
11477
11669
|
applied_at INTEGER NOT NULL
|
|
11478
11670
|
) STRICT`);
|
|
11479
11671
|
}
|
|
11672
|
+
/** The highest schema version a database's ledger records, or 0 when it has no ledger yet. It only reads. */
|
|
11673
|
+
function recordedSchemaVersion(database) {
|
|
11674
|
+
if (database.prepare("SELECT 1 AS found FROM sqlite_master WHERE type = 'table' AND name = 'schema_migrations'").get() === void 0) return 0;
|
|
11675
|
+
return database.prepare("SELECT MAX(version) AS version FROM schema_migrations").get().version ?? 0;
|
|
11676
|
+
}
|
|
11677
|
+
/** Refuses a recorded schema version newer than this binary's, naming both and nothing else. */
|
|
11678
|
+
function refuseNewerVersion(databaseVersion, migrations = EVENT_MIGRATIONS) {
|
|
11679
|
+
const binaryVersion = migrations.at(-1)?.version ?? 0;
|
|
11680
|
+
if (databaseVersion > binaryVersion) throw new Error(`event database schema version ${databaseVersion} is newer than this release's schema version ${binaryVersion}; only the newer release that migrated it can open it`);
|
|
11681
|
+
}
|
|
11682
|
+
/**
|
|
11683
|
+
* Refuses a database a newer agent-events has migrated, by reading its ledger and nothing else: no table is created and
|
|
11684
|
+
* nothing is written, so it runs before the opener sets a journal mode or this file creates its ledger. A database
|
|
11685
|
+
* with no ledger yet is new, and passes.
|
|
11686
|
+
*/
|
|
11687
|
+
function refuseNewerSchema(database, migrations = EVENT_MIGRATIONS) {
|
|
11688
|
+
refuseNewerVersion(recordedSchemaVersion(database), migrations);
|
|
11689
|
+
}
|
|
11480
11690
|
/** Applies ordered daemon-owned migrations, one BEGIN IMMEDIATE transaction per version. */
|
|
11481
11691
|
function applyMigrations(database, migrations = EVENT_MIGRATIONS, hooks = {}) {
|
|
11692
|
+
refuseNewerSchema(database, migrations);
|
|
11482
11693
|
initialiseLedger(database);
|
|
11694
|
+
for (const [index, migration] of migrations.entries()) if (migration.version !== index + 1) throw new Error("event migrations must have consecutive versions starting at 1");
|
|
11483
11695
|
const applied = database.prepare("SELECT version, name FROM schema_migrations ORDER BY version").all();
|
|
11484
|
-
|
|
11485
|
-
|
|
11696
|
+
refuseNewerVersion(applied.at(-1)?.version ?? 0, migrations);
|
|
11697
|
+
for (const migration of migrations) {
|
|
11486
11698
|
const recorded = applied.find((entry) => entry.version === migration.version);
|
|
11487
11699
|
if (recorded) {
|
|
11488
11700
|
if (recorded.name !== migration.name) throw new Error(`event migration ${migration.version} does not match its ledger name`);
|
|
@@ -11517,18 +11729,44 @@ function installationIdFor(database) {
|
|
|
11517
11729
|
database.prepare("INSERT INTO meta (key, value) VALUES (?, ?)").run("installation_id", created);
|
|
11518
11730
|
return created;
|
|
11519
11731
|
}
|
|
11732
|
+
/** SQLite's primary result code for a read that has to write first: recovering what a crash interrupted. */
|
|
11733
|
+
const SQLITE_READONLY = 8;
|
|
11734
|
+
/**
|
|
11735
|
+
* The schema version a database records, read through a read-only connection, so that a database a newer agent-events
|
|
11736
|
+
* migrated is refused without this release ever opening it for writing. It waits out a lock as the writable opener
|
|
11737
|
+
* would. Null only when SQLite must first recover an interrupted transaction, which takes a writable connection: the
|
|
11738
|
+
* opener checks again there. Any other failure, a lock held past the wait among them, refuses the open as it is.
|
|
11739
|
+
*/
|
|
11740
|
+
function recordedVersionReadOnly(Database, path, busyTimeoutMs = 5e3) {
|
|
11741
|
+
try {
|
|
11742
|
+
const probe = new Database(path, { readOnly: true });
|
|
11743
|
+
try {
|
|
11744
|
+
probe.exec(`PRAGMA busy_timeout = ${Math.trunc(busyTimeoutMs)}`);
|
|
11745
|
+
return recordedSchemaVersion(probe);
|
|
11746
|
+
} finally {
|
|
11747
|
+
probe.close();
|
|
11748
|
+
}
|
|
11749
|
+
} catch (error) {
|
|
11750
|
+
const code = error.errcode;
|
|
11751
|
+
if (typeof code === "number" && (code & 255) === SQLITE_READONLY) return null;
|
|
11752
|
+
throw error;
|
|
11753
|
+
}
|
|
11754
|
+
}
|
|
11520
11755
|
/** Opens the daemon’s one local authority after the Task 4 owner-only path checks have succeeded. */
|
|
11521
11756
|
async function openEventDatabase(options) {
|
|
11522
11757
|
const { DatabaseSync: Database } = await loadSqlite();
|
|
11523
11758
|
const paths = await ensureEventPaths(eventPaths(options.stateDir));
|
|
11524
11759
|
await ensureOwnerOnlyFile(paths.database);
|
|
11760
|
+
const recorded = recordedVersionReadOnly(Database, paths.database);
|
|
11761
|
+
if (recorded !== null) refuseNewerVersion(recorded);
|
|
11525
11762
|
const database = new Database(paths.database);
|
|
11526
11763
|
try {
|
|
11764
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
11765
|
+
refuseNewerSchema(database);
|
|
11527
11766
|
database.exec("PRAGMA foreign_keys = ON");
|
|
11528
11767
|
database.exec("PRAGMA journal_mode = WAL");
|
|
11529
11768
|
database.exec("PRAGMA synchronous = FULL");
|
|
11530
11769
|
database.exec("PRAGMA secure_delete = ON");
|
|
11531
|
-
database.exec("PRAGMA busy_timeout = 5000");
|
|
11532
11770
|
applyMigrations(database);
|
|
11533
11771
|
return {
|
|
11534
11772
|
database,
|
|
@@ -11841,16 +12079,20 @@ var ActivationRuntime = class {
|
|
|
11841
12079
|
}
|
|
11842
12080
|
/** A narrowing revocation is allowed to win over a claimed completion, but no other pointer mutation is. */
|
|
11843
12081
|
async cancelForRevocation(input) {
|
|
12082
|
+
this.#store.immediate(() => {
|
|
12083
|
+
this.cancelForRevocationInTransaction(input);
|
|
12084
|
+
});
|
|
12085
|
+
}
|
|
12086
|
+
/** A caller already holding the removal transaction cancels every matching intent before revocation commits. */
|
|
12087
|
+
cancelForRevocationInTransaction(input) {
|
|
11844
12088
|
const rows = this.#store.database.prepare("SELECT id, document FROM activation_intents WHERE status IN ('pending', 'pending-completion') ORDER BY id").all();
|
|
11845
|
-
|
|
12089
|
+
let cancelled = 0;
|
|
11846
12090
|
for (const row of rows) {
|
|
11847
12091
|
if (!this.#isRevokedBinding(JSON.parse(row.document), input)) continue;
|
|
11848
|
-
|
|
12092
|
+
this.#cancel(row.id, ACTIVATION_FAILURE.AUTHORIZATION_REVOKED);
|
|
12093
|
+
cancelled += 1;
|
|
11849
12094
|
}
|
|
11850
|
-
|
|
11851
|
-
this.#store.immediate(() => {
|
|
11852
|
-
for (const intentId of cancelled) this.#cancel(intentId, ACTIVATION_FAILURE.AUTHORIZATION_REVOKED);
|
|
11853
|
-
});
|
|
12095
|
+
return cancelled;
|
|
11854
12096
|
}
|
|
11855
12097
|
/** Called by the kind-disable transaction; no pending kind approval may recreate the pointer after disable wins. */
|
|
11856
12098
|
cancelForJudgeKindInTransaction(kind) {
|
|
@@ -11858,7 +12100,7 @@ var ActivationRuntime = class {
|
|
|
11858
12100
|
let cancelled = 0;
|
|
11859
12101
|
for (const row of rows) {
|
|
11860
12102
|
const document = JSON.parse(row.document);
|
|
11861
|
-
if (document.kind === "judge-kind" && document.enablement.kind === kind || document.kind === "rule" && document.rule.agentic?.judge.kind === kind) {
|
|
12103
|
+
if (document.kind === "judge-kind" && document.enablement.kind === kind || document.kind === "rule" && document.rule.agentic?.judge.kind === kind || document.kind === "enable-all" && this.#ruleVersionsBindJudgeKind(document.ruleVersions, kind)) {
|
|
11862
12104
|
this.#cancel(row.id, ACTIVATION_FAILURE.AUTHORIZATION_REVOKED);
|
|
11863
12105
|
cancelled += 1;
|
|
11864
12106
|
}
|
|
@@ -11976,6 +12218,8 @@ var ActivationRuntime = class {
|
|
|
11976
12218
|
const now = this.#now();
|
|
11977
12219
|
const plannedAccounts = [...new Map(points.map((point) => [`${point.source}\u0000${point.accountId}`, point])).values()];
|
|
11978
12220
|
this.#store.immediate(() => {
|
|
12221
|
+
this.#assertBoundRuleAuthority(document);
|
|
12222
|
+
this.#assertPreparationPlanLive(document, effect, replacementOfVersion);
|
|
11979
12223
|
this.#assertJudgeActivationLive(document, effect);
|
|
11980
12224
|
const latestRevocation = plannedAccounts.reduce((latest, point) => {
|
|
11981
12225
|
const row = this.#store.database.prepare(`SELECT MAX(revoked_at) AS revoked_at FROM account_revocations
|
|
@@ -11988,9 +12232,28 @@ var ActivationRuntime = class {
|
|
|
11988
12232
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)`).run(intentId, document.kind, canonicalJson(document), binding.digest, canonicalJson(effect), replacementOfVersion ?? null, canonicalJson(points), canonicalJson([...new Set(points.map((point) => `${point.accountId}:${point.positionScope}`))]), createdAt, createdAt);
|
|
11989
12233
|
});
|
|
11990
12234
|
const approval = await this.#approvals.createDisclosure(binding);
|
|
12235
|
+
let settled;
|
|
11991
12236
|
this.#store.immediate(() => {
|
|
11992
|
-
|
|
12237
|
+
const latest = this.#intent(intentId);
|
|
12238
|
+
const linkApproval = () => this.#store.database.prepare("UPDATE activation_intents SET approval_id = ?, updated_at = ? WHERE id = ? AND approval_id IS NULL").run(approval.approvalId, this.#now(), intentId).changes;
|
|
12239
|
+
if (latest.status !== "pending") {
|
|
12240
|
+
if (linkApproval() !== 1) throw new CommsError("APPROVAL_VOID", "the cancelled activation could not retain its disclosure link");
|
|
12241
|
+
settled = new CommsError("APPROVAL_VOID", "the activation was cancelled before its approval could be linked");
|
|
12242
|
+
return;
|
|
12243
|
+
}
|
|
12244
|
+
try {
|
|
12245
|
+
this.#assertBoundRuleAuthority(document);
|
|
12246
|
+
this.#assertPreparationPlanLive(document, effect, replacementOfVersion);
|
|
12247
|
+
this.#assertJudgeActivationLive(document, effect);
|
|
12248
|
+
} catch (error) {
|
|
12249
|
+
if (linkApproval() !== 1) throw new CommsError("APPROVAL_VOID", "the stale activation could not retain its disclosure link");
|
|
12250
|
+
this.#cancel(intentId, ACTIVATION_FAILURE.APPROVAL_BINDING_DRIFT);
|
|
12251
|
+
settled = error;
|
|
12252
|
+
return;
|
|
12253
|
+
}
|
|
12254
|
+
if (this.#store.database.prepare("UPDATE activation_intents SET approval_id = ?, updated_at = ? WHERE id = ? AND status = 'pending' AND approval_id IS NULL").run(approval.approvalId, this.#now(), intentId).changes !== 1) throw new CommsError("APPROVAL_VOID", "the activation approval link changed before it could be written");
|
|
11993
12255
|
});
|
|
12256
|
+
if (settled !== void 0) throw settled;
|
|
11994
12257
|
return {
|
|
11995
12258
|
intentId,
|
|
11996
12259
|
approvalId: approval.approvalId,
|
|
@@ -12013,7 +12276,7 @@ var ActivationRuntime = class {
|
|
|
12013
12276
|
if (allowIssuingChallengeResidue) this.#assertApprovalIssuingChallengeResidue(intent.approval_id);
|
|
12014
12277
|
if (row.status === "cancelled") throw new CommsError("APPROVAL_VOID", "the activation was cancelled before completion");
|
|
12015
12278
|
const document = this.#document(row);
|
|
12016
|
-
this.#
|
|
12279
|
+
this.#assertBoundRuleAuthority(document);
|
|
12017
12280
|
if (document.kind === "judge-budget" || document.kind === "judge-kind") try {
|
|
12018
12281
|
this.#assertJudgeActivationLive(document, JSON.parse(row.effect));
|
|
12019
12282
|
} catch (_error) {
|
|
@@ -12166,7 +12429,7 @@ var ActivationRuntime = class {
|
|
|
12166
12429
|
settled = new CommsError("APPROVAL_VOID", "the activation completion deadline has passed");
|
|
12167
12430
|
return;
|
|
12168
12431
|
}
|
|
12169
|
-
this.#
|
|
12432
|
+
this.#assertBoundRuleAuthority(document);
|
|
12170
12433
|
const effect = JSON.parse(latest.effect);
|
|
12171
12434
|
const settings = this.#switch();
|
|
12172
12435
|
if ((document.kind === "rule" || document.kind === "enable-all") && settings.generation !== effect.switchGeneration) {
|
|
@@ -12280,12 +12543,10 @@ var ActivationRuntime = class {
|
|
|
12280
12543
|
const document = this.#document(intent);
|
|
12281
12544
|
const binding = disclosureBindingFor(intent.id, document);
|
|
12282
12545
|
if (binding.digest !== intent.digest || activationDocumentDigest(document) !== intent.digest) throw new CommsError("APPROVAL_VOID", "the activation document changed after preparation");
|
|
12546
|
+
this.#assertBoundRuleAuthority(document);
|
|
12283
12547
|
if (document.kind === "rule") {
|
|
12284
|
-
const
|
|
12285
|
-
const active = versions.activeVersion("rule", document.rule.ruleId);
|
|
12548
|
+
const active = new ImmutableVersions(this.#store.database).activeVersion("rule", document.rule.ruleId);
|
|
12286
12549
|
if (active !== null && (intent.replacement_of_version === null || `${document.rule.ruleId}@${active.version}` !== intent.replacement_of_version)) throw new CommsError("APPROVAL_VOID", "the rule gained an active pointer after preparation");
|
|
12287
|
-
const live = versions.prepareRule(document.rule.ruleId, document.rule.version);
|
|
12288
|
-
if (canonicalJson(live) !== canonicalJson(document)) throw new CommsError("APPROVAL_VOID", "the rule changed after preparation");
|
|
12289
12550
|
} else if (document.kind === "enable-all") {
|
|
12290
12551
|
const current = this.#switch();
|
|
12291
12552
|
const live = this.#store.database.prepare("SELECT object_id, version, current_cutover_id FROM active_versions WHERE kind = 'rule' ORDER BY object_id, version").all();
|
|
@@ -12319,12 +12580,48 @@ var ActivationRuntime = class {
|
|
|
12319
12580
|
#judgeKindDisableGeneration(kind) {
|
|
12320
12581
|
return this.#store.database.prepare("SELECT generation FROM judge_kind_disable_generations WHERE kind = ?").get(kind)?.generation ?? 0;
|
|
12321
12582
|
}
|
|
12322
|
-
/**
|
|
12323
|
-
#
|
|
12324
|
-
if (document.kind !== "rule"
|
|
12325
|
-
const kind = document.rule.agentic.judge.kind;
|
|
12583
|
+
/** Re-read every exact bound rule, including its embedded judge revocation and kind pointer, at each authority gate. */
|
|
12584
|
+
#assertBoundRuleAuthority(document) {
|
|
12585
|
+
if (document.kind !== "rule" && document.kind !== "enable-all") return;
|
|
12326
12586
|
const versions = new ImmutableVersions(this.#store.database);
|
|
12327
|
-
|
|
12587
|
+
if (document.kind === "rule") {
|
|
12588
|
+
const live = versions.prepareRule(document.rule.ruleId, document.rule.version);
|
|
12589
|
+
if (canonicalJson(live) !== canonicalJson(document)) throw new CommsError("APPROVAL_VOID", "the rule changed after preparation");
|
|
12590
|
+
return;
|
|
12591
|
+
}
|
|
12592
|
+
for (const entry of document.ruleVersions) versions.prepareRule(entry.ruleId, entry.ruleVersion);
|
|
12593
|
+
}
|
|
12594
|
+
/** Preparation may await local stores; the exact pointer plan captured before those awaits must still be current. */
|
|
12595
|
+
#assertPreparationPlanLive(document, effect, replacementOfVersion) {
|
|
12596
|
+
if (document.kind === "rule") {
|
|
12597
|
+
const active = new ImmutableVersions(this.#store.database).activeVersion("rule", document.rule.ruleId);
|
|
12598
|
+
if ((active === null ? null : `${document.rule.ruleId}@${active.version}`) !== (replacementOfVersion ?? null) || this.#switch().generation !== effect.switchGeneration) throw new CommsError("APPROVAL_VOID", "the rule activation pointer plan changed during preparation");
|
|
12599
|
+
return;
|
|
12600
|
+
}
|
|
12601
|
+
if (document.kind !== "enable-all") return;
|
|
12602
|
+
const settings = this.#switch();
|
|
12603
|
+
const live = this.#store.database.prepare("SELECT object_id, version, current_cutover_id FROM active_versions WHERE kind = 'rule' ORDER BY object_id, version").all();
|
|
12604
|
+
if (settings.enabled || settings.generation !== document.switchGeneration || settings.generation !== effect.switchGeneration || canonicalJson(live.map((row) => ({
|
|
12605
|
+
ruleId: row.object_id,
|
|
12606
|
+
ruleVersion: row.version
|
|
12607
|
+
}))) !== canonicalJson(document.ruleVersions) || canonicalJson(live.map((row) => ({
|
|
12608
|
+
ruleId: row.object_id,
|
|
12609
|
+
ruleVersion: row.version,
|
|
12610
|
+
cutoverId: row.current_cutover_id
|
|
12611
|
+
}))) !== canonicalJson(effect.currentCutovers ?? [])) throw new CommsError("APPROVAL_VOID", "the global enablement pointer plan changed during preparation");
|
|
12612
|
+
}
|
|
12613
|
+
/** A damaged captured rule row cannot prove that a kind disable is unrelated, so cancellation is fail-closed. */
|
|
12614
|
+
#ruleVersionsBindJudgeKind(entries, kind) {
|
|
12615
|
+
for (const entry of entries) {
|
|
12616
|
+
const row = this.#store.database.prepare("SELECT document FROM rule_versions WHERE rule_id = ? AND version = ?").get(entry.ruleId, entry.ruleVersion);
|
|
12617
|
+
if (row === void 0) return true;
|
|
12618
|
+
try {
|
|
12619
|
+
if (canonicalFullRuleDocument(JSON.parse(row.document)).agentic?.judge.kind === kind) return true;
|
|
12620
|
+
} catch {
|
|
12621
|
+
return true;
|
|
12622
|
+
}
|
|
12623
|
+
}
|
|
12624
|
+
return false;
|
|
12328
12625
|
}
|
|
12329
12626
|
#document(intent) {
|
|
12330
12627
|
return JSON.parse(intent.document);
|
|
@@ -13583,10 +13880,10 @@ var B3OperatorControl = class {
|
|
|
13583
13880
|
}).disable(kind);
|
|
13584
13881
|
}
|
|
13585
13882
|
async removeJudge(judgeId) {
|
|
13586
|
-
await this.#activations?.cancelForRevocation({ judgeId });
|
|
13587
13883
|
return this.#store.immediate(() => {
|
|
13588
13884
|
const rows = this.#store.database.prepare("SELECT version FROM judge_versions WHERE judge_id = ? AND revoked_at IS NULL ORDER BY version").all(judgeId);
|
|
13589
13885
|
if (rows.length === 0) throw new CommsError("NOT_FOUND", "the judge has no live version to remove");
|
|
13886
|
+
this.#activations?.cancelForRevocationInTransaction({ judgeId });
|
|
13590
13887
|
const revokedAt = this.#now();
|
|
13591
13888
|
const removedVersions = new Set(rows.map((row) => row.version));
|
|
13592
13889
|
for (const row of rows) {
|
|
@@ -15547,9 +15844,9 @@ var JudgeTransport = class {
|
|
|
15547
15844
|
let enteredIo = false;
|
|
15548
15845
|
try {
|
|
15549
15846
|
await this.#beforeGate(hooks, "dns");
|
|
15550
|
-
this.#finalGate(hooks, "dns");
|
|
15551
|
-
assertBeforeDeadline(deadline, this.#clock);
|
|
15847
|
+
this.#finalGate(hooks, "dns", deadline);
|
|
15552
15848
|
enteredIo = call.judge.kind === JUDGE_KIND_TYPESAFE;
|
|
15849
|
+
assertBeforeDeadline(deadline, this.#clock);
|
|
15553
15850
|
const connection = await beforeDeadline$1(preparePinnedConnection(call.judge.kind === "typesafe" ? {
|
|
15554
15851
|
url: endpoint,
|
|
15555
15852
|
addressMode: "global-only",
|
|
@@ -15562,9 +15859,9 @@ var JudgeTransport = class {
|
|
|
15562
15859
|
}), deadline, this.#clock);
|
|
15563
15860
|
assertBeforeDeadline(deadline, this.#clock);
|
|
15564
15861
|
await this.#beforeGate(hooks, "tcp");
|
|
15565
|
-
this.#finalGate(hooks, "tcp");
|
|
15566
|
-
assertBeforeDeadline(deadline, this.#clock);
|
|
15862
|
+
this.#finalGate(hooks, "tcp", deadline);
|
|
15567
15863
|
enteredIo = true;
|
|
15864
|
+
assertBeforeDeadline(deadline, this.#clock);
|
|
15568
15865
|
const tcp = await beforeDeadline$1(this.#tcpConnect({
|
|
15569
15866
|
host: connection.address,
|
|
15570
15867
|
port: connection.port
|
|
@@ -15573,7 +15870,7 @@ var JudgeTransport = class {
|
|
|
15573
15870
|
socket = tcp;
|
|
15574
15871
|
if (connection.useTls) {
|
|
15575
15872
|
await this.#beforeGate(hooks, "tls");
|
|
15576
|
-
this.#finalGate(hooks, "tls");
|
|
15873
|
+
this.#finalGate(hooks, "tls", deadline);
|
|
15577
15874
|
assertBeforeDeadline(deadline, this.#clock);
|
|
15578
15875
|
socket = await beforeDeadline$1(this.#tlsConnect({
|
|
15579
15876
|
socket: tcp,
|
|
@@ -15582,7 +15879,7 @@ var JudgeTransport = class {
|
|
|
15582
15879
|
assertBeforeDeadline(deadline, this.#clock);
|
|
15583
15880
|
}
|
|
15584
15881
|
await this.#beforeGate(hooks, "write");
|
|
15585
|
-
this.#finalGate(hooks, "write");
|
|
15882
|
+
this.#finalGate(hooks, "write", deadline);
|
|
15586
15883
|
assertBeforeDeadline(deadline, this.#clock);
|
|
15587
15884
|
socket.write(request);
|
|
15588
15885
|
const body = await beforeDeadline$1(boundedResponse(socket), deadline, this.#clock);
|
|
@@ -15613,14 +15910,16 @@ var JudgeTransport = class {
|
|
|
15613
15910
|
}
|
|
15614
15911
|
}
|
|
15615
15912
|
/**
|
|
15616
|
-
*
|
|
15617
|
-
*
|
|
15913
|
+
* The deadline is checked after the awaited preparation and again inside the durable production gate immediately
|
|
15914
|
+
* before its state transition. No await may be inserted between this gate and the physical B2 network action.
|
|
15618
15915
|
*/
|
|
15619
|
-
#finalGate(hooks, phase) {
|
|
15916
|
+
#finalGate(hooks, phase, deadline) {
|
|
15917
|
+
assertBeforeDeadline(deadline, this.#clock);
|
|
15620
15918
|
let decision;
|
|
15621
15919
|
try {
|
|
15622
|
-
decision = hooks.finalGate(phase);
|
|
15623
|
-
} catch {
|
|
15920
|
+
decision = hooks.finalGate(phase, () => assertBeforeDeadline(deadline, this.#clock));
|
|
15921
|
+
} catch (error) {
|
|
15922
|
+
if (error instanceof DeadlineExceeded) throw error;
|
|
15624
15923
|
throw new FenceRefused();
|
|
15625
15924
|
}
|
|
15626
15925
|
if (decision !== void 0) {
|
|
@@ -15798,33 +16097,19 @@ var JudgeTestControl = class {
|
|
|
15798
16097
|
} catch (error) {
|
|
15799
16098
|
return refusal(input.judgeId, input.version, error);
|
|
15800
16099
|
}
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
}
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
} catch (error) {
|
|
15813
|
-
return refusal(input.judgeId, input.version, error);
|
|
15814
|
-
}
|
|
16100
|
+
const ioGate = new JudgeReservationIoGate({
|
|
16101
|
+
store: this.#store,
|
|
16102
|
+
reservationId: reservation.id,
|
|
16103
|
+
judgeKind: authority.judge.kind,
|
|
16104
|
+
now: this.#now,
|
|
16105
|
+
...prepared.hostedKeyGeneration === null ? {} : { hostedKey: {
|
|
16106
|
+
judgeId: authority.judge.judgeId,
|
|
16107
|
+
judgeVersion: authority.judge.version,
|
|
16108
|
+
generation: prepared.hostedKeyGeneration
|
|
16109
|
+
} }
|
|
16110
|
+
});
|
|
15815
16111
|
const result = await this.#transport.execute(call, {
|
|
15816
|
-
finalGate:
|
|
15817
|
-
assertJudgeReservationStillInFlight({
|
|
15818
|
-
store: this.#store,
|
|
15819
|
-
reservationId: reservation.id,
|
|
15820
|
-
now: this.#now(),
|
|
15821
|
-
...prepared.hostedKeyGeneration === null ? {} : { hostedKey: {
|
|
15822
|
-
judgeId: authority.judge.judgeId,
|
|
15823
|
-
judgeVersion: authority.judge.version,
|
|
15824
|
-
generation: prepared.hostedKeyGeneration
|
|
15825
|
-
} }
|
|
15826
|
-
});
|
|
15827
|
-
},
|
|
16112
|
+
finalGate: ioGate.finalGate,
|
|
15828
16113
|
preparedRequest: prepared
|
|
15829
16114
|
});
|
|
15830
16115
|
if (result.kind === "answer") {
|
|
@@ -15844,27 +16129,13 @@ var JudgeTestControl = class {
|
|
|
15844
16129
|
reservationId: reservation.id
|
|
15845
16130
|
};
|
|
15846
16131
|
}
|
|
15847
|
-
|
|
15848
|
-
releaseJudgeWork({
|
|
15849
|
-
store: this.#store,
|
|
15850
|
-
reservationId: reservation.id,
|
|
15851
|
-
now: this.#now(),
|
|
15852
|
-
beforeIo: true
|
|
15853
|
-
});
|
|
15854
|
-
return {
|
|
15855
|
-
kind: "deferred",
|
|
15856
|
-
judgeId: input.judgeId,
|
|
15857
|
-
version: input.version,
|
|
15858
|
-
code: result.code,
|
|
15859
|
-
reservationId: reservation.id
|
|
15860
|
-
};
|
|
15861
|
-
}
|
|
15862
|
-
settleJudgeWork({
|
|
16132
|
+
finalizeJudgeTransportRefusal({
|
|
15863
16133
|
store: this.#store,
|
|
15864
16134
|
reservationId: reservation.id,
|
|
15865
16135
|
result: result.code === "OUTPUT_TOKEN_LIMIT_EXCEEDED" ? "output-token-limit" : result.code === "NETWORK_DEADLINE_EXCEEDED" ? "timeout" : "transport-failure",
|
|
15866
16136
|
now: this.#now()
|
|
15867
16137
|
});
|
|
16138
|
+
if (ioGate.firstGateError !== void 0) return refusal(input.judgeId, input.version, ioGate.firstGateError);
|
|
15868
16139
|
return {
|
|
15869
16140
|
kind: "deferred",
|
|
15870
16141
|
judgeId: input.judgeId,
|
|
@@ -16586,61 +16857,44 @@ var JudgeCoordinator = class {
|
|
|
16586
16857
|
reservationId: null
|
|
16587
16858
|
};
|
|
16588
16859
|
}
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
}
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
}
|
|
16599
|
-
}
|
|
16600
|
-
if (error instanceof JudgeBudgetError && error.code === "JUDGE_PAUSED") return {
|
|
16601
|
-
kind: "deferred",
|
|
16602
|
-
reservationId: reservation.id
|
|
16603
|
-
};
|
|
16604
|
-
return {
|
|
16605
|
-
kind: "closed",
|
|
16606
|
-
reason: error instanceof Error && "code" in error ? String(error.code) : "authority-changed",
|
|
16607
|
-
reservationId: reservation.id
|
|
16608
|
-
};
|
|
16609
|
-
}
|
|
16860
|
+
const ioGate = new JudgeReservationIoGate({
|
|
16861
|
+
store: this.#store,
|
|
16862
|
+
reservationId: reservation.id,
|
|
16863
|
+
judgeKind: agentic.judge.kind,
|
|
16864
|
+
now: this.#now,
|
|
16865
|
+
...prepared.hostedKeyGeneration === null ? {} : { hostedKey: {
|
|
16866
|
+
judgeId: agentic.judge.judgeId,
|
|
16867
|
+
judgeVersion: agentic.judge.version,
|
|
16868
|
+
generation: prepared.hostedKeyGeneration
|
|
16869
|
+
} }
|
|
16870
|
+
});
|
|
16610
16871
|
const result = await this.#transport.execute(call, {
|
|
16611
|
-
finalGate:
|
|
16612
|
-
assertJudgeReservationStillInFlight({
|
|
16613
|
-
store: this.#store,
|
|
16614
|
-
reservationId: reservation.id,
|
|
16615
|
-
...prepared.hostedKeyGeneration === null ? {} : { hostedKey: {
|
|
16616
|
-
judgeId: agentic.judge.judgeId,
|
|
16617
|
-
judgeVersion: agentic.judge.version,
|
|
16618
|
-
generation: prepared.hostedKeyGeneration
|
|
16619
|
-
} }
|
|
16620
|
-
});
|
|
16621
|
-
},
|
|
16872
|
+
finalGate: ioGate.finalGate,
|
|
16622
16873
|
preparedRequest: prepared
|
|
16623
16874
|
});
|
|
16624
16875
|
if (result.kind !== "answer") {
|
|
16625
|
-
if (result.preIo === true) {
|
|
16626
|
-
releaseJudgeWork({
|
|
16627
|
-
store: this.#store,
|
|
16628
|
-
reservationId: reservation.id,
|
|
16629
|
-
now: this.#now(),
|
|
16630
|
-
beforeIo: true
|
|
16631
|
-
});
|
|
16632
|
-
return {
|
|
16633
|
-
kind: "deferred",
|
|
16634
|
-
reservationId: reservation.id
|
|
16635
|
-
};
|
|
16636
|
-
}
|
|
16637
16876
|
const settlement = result.code === "OUTPUT_TOKEN_LIMIT_EXCEEDED" ? "output-token-limit" : result.code === "NETWORK_DEADLINE_EXCEEDED" ? "timeout" : "unknown";
|
|
16638
|
-
|
|
16877
|
+
const disposition = finalizeJudgeTransportRefusal({
|
|
16639
16878
|
store: this.#store,
|
|
16640
16879
|
reservationId: reservation.id,
|
|
16641
16880
|
result: settlement,
|
|
16642
16881
|
now: this.#now()
|
|
16643
16882
|
});
|
|
16883
|
+
if (ioGate.firstGateError !== void 0) {
|
|
16884
|
+
if (ioGate.firstGateError instanceof JudgeBudgetError && ioGate.firstGateError.code === "JUDGE_PAUSED") return {
|
|
16885
|
+
kind: "deferred",
|
|
16886
|
+
reservationId: reservation.id
|
|
16887
|
+
};
|
|
16888
|
+
return {
|
|
16889
|
+
kind: "closed",
|
|
16890
|
+
reason: ioGate.firstGateError instanceof Error && "code" in ioGate.firstGateError ? String(ioGate.firstGateError.code) : "authority-changed",
|
|
16891
|
+
reservationId: reservation.id
|
|
16892
|
+
};
|
|
16893
|
+
}
|
|
16894
|
+
if (disposition === "released") return {
|
|
16895
|
+
kind: "deferred",
|
|
16896
|
+
reservationId: reservation.id
|
|
16897
|
+
};
|
|
16644
16898
|
return {
|
|
16645
16899
|
kind: "closed",
|
|
16646
16900
|
reason: closedReason(result),
|
|
@@ -19851,7 +20105,7 @@ function sourceOfDeliveryRule(document) {
|
|
|
19851
20105
|
/** Composes every Task 3/4 control behind the authenticated owner; public adapters never reach a runtime class. */
|
|
19852
20106
|
function createOwnerB3ControlService(options) {
|
|
19853
20107
|
const now = options.now ?? Date.now;
|
|
19854
|
-
const judgeActivations = typeof options.activations.prepareJudgeBudget === "function" && typeof options.activations.prepareJudgeKind === "function" && typeof options.activations.cancelForJudgeKindInTransaction === "function" && typeof options.activations.
|
|
20108
|
+
const judgeActivations = typeof options.activations.prepareJudgeBudget === "function" && typeof options.activations.prepareJudgeKind === "function" && typeof options.activations.cancelForJudgeKindInTransaction === "function" && typeof options.activations.cancelForRevocationInTransaction === "function" ? options.activations : void 0;
|
|
19855
20109
|
const operator = new B3OperatorControl({
|
|
19856
20110
|
store: options.store,
|
|
19857
20111
|
ports: options.ports,
|
|
@@ -21176,6 +21430,10 @@ async function run(argv, deps = {}) {
|
|
|
21176
21430
|
stdout: process.stdout,
|
|
21177
21431
|
stderr: process.stderr
|
|
21178
21432
|
};
|
|
21433
|
+
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-V")) {
|
|
21434
|
+
streams.stdout.write(`${VERSION}\n`);
|
|
21435
|
+
return 0;
|
|
21436
|
+
}
|
|
21179
21437
|
const env = deps.env ?? process.env;
|
|
21180
21438
|
const program = new Command();
|
|
21181
21439
|
let ran = false;
|