@ouro.bot/cli 0.1.0-alpha.741 → 0.1.0-alpha.743
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/changelog.json +42 -0
- package/deploy/unraid/Dockerfile +7 -2
- package/deploy/unraid/README.txt +717 -106
- package/deploy/unraid/migrate-sanctuary-bundle.mjs +21 -0
- package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
- package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
- package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
- package/deploy/unraid/ouro-events/install-usenet-guard.sh +434 -0
- package/deploy/unraid/ouro-events/usenet-health.sh +178 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +4 -3
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +5 -1
- package/deploy/unraid/sanctuary.ouro/agent.json +2 -2
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +2 -2
- package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +1 -1
- package/deploy/unraid/sanctuary.ouro/provider-readiness.json +3 -10
- package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +4 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +6 -2
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +4 -2
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +19 -17
- package/deploy/unraid/sanctuary.xml +12 -9
- package/dist/arc/cares.js +171 -37
- package/dist/arc/obligations.js +38 -0
- package/dist/heart/awaiting/await-alert.js +4 -2
- package/dist/heart/awaiting/await-expiry.js +39 -4
- package/dist/heart/awaiting/await-parser.js +8 -0
- package/dist/heart/context-loss-gauntlet.js +31 -2
- package/dist/heart/context-loss-sentinel.js +2 -0
- package/dist/heart/core.js +37 -7
- package/dist/heart/cross-chat-delivery.js +1 -0
- package/dist/heart/daemon/container-healthcheck.js +3 -1
- package/dist/heart/daemon/container-runtime.js +13 -0
- package/dist/heart/daemon/container-spec-auditor-main.js +11 -7
- package/dist/heart/daemon/container-spec-auditor.js +38 -11
- package/dist/heart/daemon/daemon-entry.js +19 -5
- package/dist/heart/daemon/daemon.js +154 -22
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +151 -87
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +26 -29
- package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +42 -51
- package/dist/heart/daemon/sanctuary-bundle-migration.js +398 -0
- package/dist/heart/daemon/sanctuary-scheduler-origin.js +11 -5
- package/dist/heart/daemon/supercronic-supervisor.js +16 -1
- package/dist/heart/external-events/router.js +1025 -43
- package/dist/heart/provider-models.js +10 -3
- package/dist/heart/session-events.js +23 -5
- package/dist/heart/steward-policy.js +302 -0
- package/dist/heart/tool-approval.js +3 -1
- package/dist/heart/turn-context.js +1 -0
- package/dist/mind/context.js +8 -3
- package/dist/mind/pending.js +25 -0
- package/dist/mind/prompt.js +49 -1
- package/dist/repertoire/guardrails.js +2 -1
- package/dist/repertoire/relationship-authorization.js +194 -0
- package/dist/repertoire/tools-awaiting.js +229 -26
- package/dist/repertoire/tools-base.js +15 -0
- package/dist/repertoire/tools-continuity.js +259 -4
- package/dist/repertoire/tools-notes.js +29 -3
- package/dist/repertoire/tools-session.js +219 -4
- package/dist/repertoire/tools-steward-policy.js +88 -0
- package/dist/repertoire/tools-telegram-contacts.js +37 -0
- package/dist/repertoire/tools-unraid.js +113 -6
- package/dist/repertoire/tools.js +104 -9
- package/dist/repertoire/unraid-restart.js +86 -4
- package/dist/senses/private-runtime-worker.js +36 -3
- package/dist/senses/private-runtime.js +310 -63
- package/dist/senses/sanctuary-health-acceptance-probe.js +8 -6
- package/dist/senses/sanctuary-health-runner.js +51 -96
- package/dist/senses/sanctuary-health.js +54 -93
- package/dist/senses/sanctuary-runtime.js +36 -2
- package/dist/senses/sanctuary-sab.js +80 -0
- package/dist/senses/shared-turn.js +64 -9
- package/dist/senses/telegram-admission.js +684 -0
- package/dist/senses/telegram-approval-runtime.js +46 -6
- package/dist/senses/telegram-client.js +236 -72
- package/dist/senses/telegram-effect-adapter.js +787 -0
- package/dist/senses/telegram-entry.js +4 -1
- package/dist/senses/telegram.js +728 -48
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
|
@@ -55,15 +55,20 @@ const node_crypto_1 = require("node:crypto");
|
|
|
55
55
|
const node_fs_1 = require("node:fs");
|
|
56
56
|
const node_net_1 = require("node:net");
|
|
57
57
|
const path = __importStar(require("node:path"));
|
|
58
|
+
const friends_1 = require("@ouro.bot/friends");
|
|
58
59
|
const runtime_1 = require("../../nerves/runtime");
|
|
59
60
|
const telegram_approval_runtime_1 = require("../../senses/telegram-approval-runtime");
|
|
60
61
|
const telegram_client_1 = require("../../senses/telegram-client");
|
|
62
|
+
const telegram_effect_adapter_1 = require("../../senses/telegram-effect-adapter");
|
|
63
|
+
const telegram_admission_1 = require("../../senses/telegram-admission");
|
|
61
64
|
const sanctuary_interactive_control_1 = require("../../senses/sanctuary-interactive-control");
|
|
65
|
+
const shared_turn_1 = require("../../senses/shared-turn");
|
|
62
66
|
const telegram_1 = require("../../senses/telegram");
|
|
63
67
|
const telegram_audit_ledger_1 = require("../../senses/telegram-audit-ledger");
|
|
64
68
|
const sanctuary_runtime_1 = require("../../senses/sanctuary-runtime");
|
|
65
69
|
const sanctuary_grounding_1 = require("../../senses/sanctuary-grounding");
|
|
66
70
|
const tools_1 = require("../../repertoire/tools");
|
|
71
|
+
const relationship_authorization_1 = require("../../repertoire/relationship-authorization");
|
|
67
72
|
const core_1 = require("../core");
|
|
68
73
|
const identity_1 = require("../identity");
|
|
69
74
|
const approval_store_1 = require("../approval-store");
|
|
@@ -78,20 +83,13 @@ const KEY_ID = /^[A-Za-z0-9._:-]+$/u;
|
|
|
78
83
|
const AUTH_PROBE = "query AcceptanceAuthProbe { info { os { hostname } } }";
|
|
79
84
|
const WRITE_PROBE = "mutation AcceptanceWriteProbe($id: PrefixedID!) { docker { restart(id: $id) { id } } }";
|
|
80
85
|
function evaluateSanctuaryProviderReadinessContract(input) {
|
|
81
|
-
const credentialIdentity = (_provider, secret) => (0, node_crypto_1.createHmac)("sha256", input.identityKey)
|
|
82
|
-
.update(`sanctuary-provider-credential-v1\0${secret}`).digest();
|
|
83
|
-
const glmIdentity = credentialIdentity("openai-compatible", input.glm.apiKey);
|
|
84
|
-
const geminiIdentity = credentialIdentity("openai-compatible-gemini", input.geminiCredential.apiKey);
|
|
85
86
|
return {
|
|
86
|
-
modelsExact: input.outward.provider === "
|
|
87
|
-
&& input.inner.provider === "
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
&& input.geminiCredential.baseUrl === "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
91
|
-
vaultCoordinatesExact: input.glm.vaultItem === "providers/openai-compatible"
|
|
92
|
-
&& input.gemini.vaultItem === "providers/openai-compatible-gemini"
|
|
87
|
+
modelsExact: input.outward.provider === "minimax" && input.outward.model === "MiniMax-M3"
|
|
88
|
+
&& input.inner.provider === "minimax" && input.inner.model === "MiniMax-M3",
|
|
89
|
+
baseUrlsExact: true,
|
|
90
|
+
vaultCoordinatesExact: input.minimax.vaultItem === "providers/minimax"
|
|
93
91
|
&& input.selectionPolicy === "explicit-same-lane-only",
|
|
94
|
-
credentialIdentitiesDistinct:
|
|
92
|
+
credentialIdentitiesDistinct: typeof input.minimax.apiKey === "string" && input.minimax.apiKey.trim().length > 0,
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
95
|
const MISSING_CONTAINER_ID = "Docker:ouro-acceptance-guaranteed-missing";
|
|
@@ -111,7 +109,6 @@ const POSTBOOT_HEALTH_FILE = "/run/ouro-acceptance/postboot-health.json";
|
|
|
111
109
|
const BOOT_ID_FILE = "/run/ouro-acceptance/boot-id";
|
|
112
110
|
const TELEGRAM_POLLER_COUNT_FILE = "/run/ouro-acceptance/telegram-poller-count.json";
|
|
113
111
|
const CONTRACT_FILE = "/opt/ouro/deploy/unraid/sanctuary-acceptance-contract.json";
|
|
114
|
-
const SANCTUARY_TOOL_PROFILES_FILE = "/opt/ouro/deploy/unraid/sanctuary.ouro/tool-profiles.json";
|
|
115
112
|
const CLOSED_INVENTORY_FILE = "/run/ouro-acceptance/closed-inventory.json";
|
|
116
113
|
const HOST_BROKER_SOCKET = "/run/ouro-host-acceptance/adapter.sock";
|
|
117
114
|
const MAX_BROKER_RESPONSE = 256 * 1024;
|
|
@@ -125,7 +122,7 @@ const APPROVAL_EVIDENCE_LABELS = new Set([
|
|
|
125
122
|
const HEALTH_ACCEPTANCE_LABELS = new Set([
|
|
126
123
|
"unit-16f-cron-fingerprint",
|
|
127
124
|
"unit-16g-health-transition",
|
|
128
|
-
"unit-16h-
|
|
125
|
+
"unit-16h-acceptance-delivery-probe",
|
|
129
126
|
]);
|
|
130
127
|
const PERMISSION_RESOURCES = new Set([
|
|
131
128
|
"ACTIVATION_CODE", "API_KEY", "ARRAY", "CLOUD", "CONFIG", "CONNECT", "CONNECT__REMOTE_ACCESS",
|
|
@@ -512,6 +509,67 @@ function parsedJson(raw) {
|
|
|
512
509
|
return null;
|
|
513
510
|
return object(JSON.parse(raw), "scenario source");
|
|
514
511
|
}
|
|
512
|
+
async function projectTelegramAdmissions(agentRoot, credentials, identityKey) {
|
|
513
|
+
const admissionsRoot = path.join(agentRoot, "state", "senses", "telegram", "admissions");
|
|
514
|
+
const effectsRoot = path.join(agentRoot, "state", "telegram", "effects");
|
|
515
|
+
if (!(0, node_fs_1.existsSync)(admissionsRoot) || !(0, node_fs_1.existsSync)(effectsRoot) || !identityKey || !/^[A-Za-z0-9_-]{43}$/u.test(identityKey))
|
|
516
|
+
return [];
|
|
517
|
+
const admissionStore = new telegram_admission_1.FileTelegramAdmissionStore(admissionsRoot);
|
|
518
|
+
const effectStore = new telegram_effect_adapter_1.FileTelegramEffectJournal(effectsRoot);
|
|
519
|
+
try {
|
|
520
|
+
const effects = new Map(effectStore.list().map((artifact) => [artifact.id, artifact]));
|
|
521
|
+
const botId = (0, telegram_1.telegramBotIdFromToken)(credentials.botToken);
|
|
522
|
+
const ownerSessionKey = `telegram:${(0, telegram_1.opaqueTelegramSubject)(identityKey, botId, credentials.authorizedUserId, credentials.authorizedChatId)}`;
|
|
523
|
+
const friendsRoot = path.join(agentRoot, "friends");
|
|
524
|
+
const friendStore = (0, node_fs_1.existsSync)(friendsRoot) ? new friends_1.FileFriendStore(friendsRoot) : null;
|
|
525
|
+
const owner = friendStore ? await friendStore.findByExternalId("telegram-user", credentials.authorizedUserId, botId) : null;
|
|
526
|
+
const exactSameBotIdentity = (friend, userId) => {
|
|
527
|
+
const bindings = friend.externalIds.filter((external) => external.provider === "telegram-user" && external.tenantId === botId);
|
|
528
|
+
return bindings.length === 1 && bindings[0].externalId === userId;
|
|
529
|
+
};
|
|
530
|
+
const ownerExact = Boolean(owner && exactSameBotIdentity(owner, credentials.authorizedUserId) && owner.trustLevel === "family" && owner.admissionState === "active"
|
|
531
|
+
&& owner.initiativePolicy === "proactive" && owner.capabilityProfileId === "sanctuary-owner");
|
|
532
|
+
const projections = await Promise.all(admissionStore.list().map(async (record) => {
|
|
533
|
+
const acknowledgement = record.acknowledgementArtifactId ? effects.get(record.acknowledgementArtifactId) : undefined;
|
|
534
|
+
const ownerCard = record.ownerCardArtifactId ? effects.get(record.ownerCardArtifactId) : undefined;
|
|
535
|
+
const expectedButtons = [[
|
|
536
|
+
{ text: "Allow", callbackData: `admit:${record.id}:allow` },
|
|
537
|
+
{ text: "Deny", callbackData: `admit:${record.id}:deny` },
|
|
538
|
+
{ text: "Block", callbackData: `admit:${record.id}:block` },
|
|
539
|
+
]];
|
|
540
|
+
const admittedFriend = friendStore ? await friendStore.findByExternalId("telegram-user", record.userId, record.botId) : null;
|
|
541
|
+
const acknowledgementExact = Boolean(acknowledgement?.idempotencyKey === `ack:${record.id}`
|
|
542
|
+
&& acknowledgement.authorClass === "control" && acknowledgement.target.kind === "admission_gate"
|
|
543
|
+
&& acknowledgement.target.admissionId === record.id && acknowledgement.target.botId === record.botId
|
|
544
|
+
&& acknowledgement.target.userId === record.userId && acknowledgement.target.chatId === record.chatId
|
|
545
|
+
&& acknowledgement.effect.kind === "admission_ack" && acknowledgement.effect.text === telegram_effect_adapter_1.FIXED_ADMISSION_ACKNOWLEDGEMENT
|
|
546
|
+
&& acknowledgement.parts.every((part) => part.state === "accepted" || part.state === "session_recorded"));
|
|
547
|
+
const ownerCardExact = Boolean(ownerExact && owner && ownerCard?.idempotencyKey === `owner-card:${record.id}`
|
|
548
|
+
&& ownerCard.authorClass === "control" && ownerCard.target.kind === "approved_relationship"
|
|
549
|
+
&& ownerCard.target.friendId === owner.id && ownerCard.target.sessionKey === ownerSessionKey && ownerCard.target.requestId === record.id
|
|
550
|
+
&& ownerCard.effect.kind === "card" && ownerCard.effect.text.startsWith("Unknown Telegram contact\n")
|
|
551
|
+
&& ownerCard.effect.text.includes("The message is quarantined and has not been processed.")
|
|
552
|
+
&& JSON.stringify(ownerCard.effect.buttons) === JSON.stringify(expectedButtons)
|
|
553
|
+
&& ownerCard.parts.every((part) => part.state === "session_recorded"));
|
|
554
|
+
return {
|
|
555
|
+
admissionDigest: (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, "sanctuary-telegram-turn-receipt-v3", "admission", `${record.id}\0${record.botId}\0${record.userId}\0${record.chatId}\0${record.updateId}\0${record.messageId}`),
|
|
556
|
+
status: record.status,
|
|
557
|
+
identityExact: record.botId === botId && record.userId === record.chatId && record.userId !== credentials.authorizedUserId,
|
|
558
|
+
acknowledgementExact,
|
|
559
|
+
ownerCardExact,
|
|
560
|
+
contentQuarantined: typeof record.quarantinedText === "string" && (0, node_crypto_1.createHash)("sha256").update(record.quarantinedText).digest("hex") === record.contentDigest,
|
|
561
|
+
relationshipAbsent: record.friendId === null && admittedFriend === null,
|
|
562
|
+
capturedAt: record.createdAt,
|
|
563
|
+
updatedAt: record.updatedAt,
|
|
564
|
+
};
|
|
565
|
+
}));
|
|
566
|
+
return projections.sort((left, right) => left.admissionDigest.localeCompare(right.admissionDigest));
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
admissionStore.close();
|
|
570
|
+
effectStore.close();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
515
573
|
function canonicalIso(value) {
|
|
516
574
|
return typeof value === "string" && value.length <= 30 && Number.isFinite(Date.parse(value)) && new Date(Date.parse(value)).toISOString() === value;
|
|
517
575
|
}
|
|
@@ -618,10 +676,10 @@ function parseHealthProbeReceipt(raw, label, scenarioHandleDigest, identityKey)
|
|
|
618
676
|
if (Buffer.byteLength(raw) > 128 * 1024)
|
|
619
677
|
throw new Error("Sanctuary health probe receipt exceeds its bound");
|
|
620
678
|
const receipt = object(JSON.parse(raw), "Sanctuary health probe receipt");
|
|
621
|
-
const exactKeys = ["beforeStateDigest", "clockMode", "cronDegradedAfter", "cronDegradedBefore", "cronFingerprintAfter", "cronFingerprintBefore", "cronRegisteredAfter", "cronRegisteredBefore", "deliveryCount", "effectiveNow", "fixtureSequenceDigest", "label", "ownerContainerDigestAfter", "ownerContainerDigestBefore", "ownerImageDigestAfter", "ownerImageDigestBefore", "phases", "privateTurnCount", "productionRestored", "providerInvocationCount", "realCheckEquivalent", "restoredStateDigest", "scenarioHandleDigest", "schedulerReceipt", "schemaVersion", "snapshotAbsent", "socketAbsent", "workspaceAbsent"].sort();
|
|
622
|
-
const supportedLabel = label === "unit-16f-cron-fingerprint" || label === "unit-16g-health-transition" || label === "unit-16h-
|
|
679
|
+
const exactKeys = ["acceptanceOnly", "beforeStateDigest", "clockMode", "cronDegradedAfter", "cronDegradedBefore", "cronFingerprintAfter", "cronFingerprintBefore", "cronRegisteredAfter", "cronRegisteredBefore", "deliveryCount", "effectiveNow", "fixtureSequenceDigest", "label", "ownerContainerDigestAfter", "ownerContainerDigestBefore", "ownerImageDigestAfter", "ownerImageDigestBefore", "phases", "privateTurnCount", "productionRestored", "productionScheduleChanged", "providerInvocationCount", "realCheckEquivalent", "restoredStateDigest", "scenarioHandleDigest", "schedulerReceipt", "schemaVersion", "snapshotAbsent", "socketAbsent", "workspaceAbsent"].sort();
|
|
680
|
+
const supportedLabel = label === "unit-16f-cron-fingerprint" || label === "unit-16g-health-transition" || label === "unit-16h-acceptance-delivery-probe";
|
|
623
681
|
const digestFields = ["ownerImageDigestBefore", "ownerImageDigestAfter", "ownerContainerDigestBefore", "ownerContainerDigestAfter", "beforeStateDigest", "restoredStateDigest", "cronFingerprintBefore", "cronFingerprintAfter", "fixtureSequenceDigest"];
|
|
624
|
-
const booleanFields = ["cronRegisteredBefore", "cronRegisteredAfter", "cronDegradedBefore", "cronDegradedAfter", "workspaceAbsent", "socketAbsent", "snapshotAbsent", "realCheckEquivalent", "productionRestored"];
|
|
682
|
+
const booleanFields = ["acceptanceOnly", "productionScheduleChanged", "cronRegisteredBefore", "cronRegisteredAfter", "cronDegradedBefore", "cronDegradedAfter", "workspaceAbsent", "socketAbsent", "snapshotAbsent", "realCheckEquivalent", "productionRestored"];
|
|
625
683
|
if (!supportedLabel || JSON.stringify(Object.keys(receipt).sort()) !== JSON.stringify(exactKeys) || receipt.schemaVersion !== "sanctuary-health-probe-receipt-v1"
|
|
626
684
|
|| receipt.label !== label || receipt.scenarioHandleDigest !== scenarioHandleDigest || !SHA256.test(scenarioHandleDigest)
|
|
627
685
|
|| !digestFields.every((field) => typeof receipt[field] === "string" && SHA256.test(receipt[field]))
|
|
@@ -696,10 +754,10 @@ function parseHealthProbeReceipt(raw, label, scenarioHandleDigest, identityKey)
|
|
|
696
754
|
if (receipt.ownerImageDigestBefore !== receipt.ownerImageDigestAfter || receipt.ownerContainerDigestBefore !== receipt.ownerContainerDigestAfter
|
|
697
755
|
|| (label !== "unit-16f-cron-fingerprint" && receipt.beforeStateDigest !== receipt.restoredStateDigest) || receipt.cronFingerprintBefore !== receipt.cronFingerprintAfter
|
|
698
756
|
|| receipt.cronRegisteredBefore !== true || receipt.cronRegisteredAfter !== true || receipt.cronDegradedBefore !== false || receipt.cronDegradedAfter !== false
|
|
699
|
-
|| receipt.workspaceAbsent !== true || receipt.socketAbsent !== true || receipt.snapshotAbsent !== true || receipt.realCheckEquivalent !== true || receipt.productionRestored !== true) {
|
|
757
|
+
|| receipt.acceptanceOnly !== true || receipt.productionScheduleChanged !== false || receipt.workspaceAbsent !== true || receipt.socketAbsent !== true || receipt.snapshotAbsent !== true || receipt.realCheckEquivalent !== true || receipt.productionRestored !== true) {
|
|
700
758
|
throw new Error("Sanctuary health probe did not restore its exact production owner and state");
|
|
701
759
|
}
|
|
702
|
-
if (label === "unit-16h-
|
|
760
|
+
if (label === "unit-16h-acceptance-delivery-probe") {
|
|
703
761
|
const effective = new Date(receipt.effectiveNow);
|
|
704
762
|
const parts = new Intl.DateTimeFormat("en-US", { timeZone: "America/Los_Angeles", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23" }).formatToParts(effective);
|
|
705
763
|
const part = (type) => Number(parts.find((entry) => entry.type === type).value);
|
|
@@ -1177,9 +1235,6 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1177
1235
|
identityKey: identityRaw.trim(),
|
|
1178
1236
|
});
|
|
1179
1237
|
const auditEntries = auditLedgerEntries.filter((entry) => entry.meta.scenarioHandleDigest === scenarioHandleDigest);
|
|
1180
|
-
const toolProfiles = parsedJson(optionalFixedFile(deps, SANCTUARY_TOOL_PROFILES_FILE));
|
|
1181
|
-
const profiles = toolProfiles ? object(toolProfiles.profiles, "Sanctuary tool profiles") : null;
|
|
1182
|
-
const telegramProfile = profiles?.["sanctuary-telegram"];
|
|
1183
1238
|
let approvalRecords = [];
|
|
1184
1239
|
const approvalDatabasePath = pathFor(agentRoot, "state/approvals/approvals.sqlite");
|
|
1185
1240
|
if ((0, node_fs_1.existsSync)(approvalDatabasePath))
|
|
@@ -1261,30 +1316,6 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1261
1316
|
throw new Error("Telegram audit lifecycle MAC is invalid");
|
|
1262
1317
|
}
|
|
1263
1318
|
}
|
|
1264
|
-
if (label === "unit-16d-2-unauthorized") {
|
|
1265
|
-
const expectedAuthorizedIdentityDigest = (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, auditSchema, "sender-identity", credentials.authorizedUserId);
|
|
1266
|
-
for (const entry of auditEntries.filter((candidate) => candidate.event === "telegram.update_dropped")) {
|
|
1267
|
-
const binding = {
|
|
1268
|
-
scenarioHandleDigest: entry.meta.scenarioHandleDigest,
|
|
1269
|
-
updateDigest: entry.meta.updateDigest,
|
|
1270
|
-
senderIdentityDigest: entry.meta.senderIdentityDigest,
|
|
1271
|
-
authorizedIdentityDigest: entry.meta.authorizedIdentityDigest,
|
|
1272
|
-
senderDistinct: entry.meta.senderDistinct,
|
|
1273
|
-
nextOffsetDigest: entry.meta.nextOffsetDigest,
|
|
1274
|
-
};
|
|
1275
|
-
if (typeof binding.updateDigest !== "string" || !SHA256.test(binding.updateDigest)
|
|
1276
|
-
|| typeof binding.senderIdentityDigest !== "string" || !SHA256.test(binding.senderIdentityDigest)
|
|
1277
|
-
|| typeof binding.authorizedIdentityDigest !== "string" || !SHA256.test(binding.authorizedIdentityDigest)
|
|
1278
|
-
|| typeof binding.nextOffsetDigest !== "string" || !SHA256.test(binding.nextOffsetDigest)
|
|
1279
|
-
|| binding.nextOffsetDigest !== (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, auditSchema, "next-update-id", String(telegramNextUpdateId))
|
|
1280
|
-
|| binding.authorizedIdentityDigest !== expectedAuthorizedIdentityDigest
|
|
1281
|
-
|| binding.senderIdentityDigest === binding.authorizedIdentityDigest
|
|
1282
|
-
|| binding.senderDistinct !== true || entry.meta.distinctAccount !== true
|
|
1283
|
-
|| typeof entry.meta.dropMac !== "string" || !SHA256.test(entry.meta.dropMac)
|
|
1284
|
-
|| entry.meta.dropMac !== (0, telegram_1.sanctuaryTelegramUnauthorizedDropMac)(identityKey, auditSchema, binding))
|
|
1285
|
-
throw new Error("Telegram unauthorized sender binding MAC is invalid");
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
1319
|
const approvalEvidenceKeys = {
|
|
1289
1320
|
"senses.telegram_approval_prompt_bound": [["actionDigest", "approvalId", "boundAt", "checkpointDigest", "evidenceMac", "messageIdDigest", "scenarioHandleDigest", "suspendedSessionRevisionDigest", "targetDigest"]],
|
|
1290
1321
|
"telegram.callback_settled": [["accepted", "acknowledged", "acknowledgementState", "actionDigest", "approvalId", "boundAt", "callbackAt", "checkpointDigest", "decisionAttemptDigest", "evidenceMac", "messageIdDigest", "reason", "scenarioHandleDigest", "suspendedSessionRevisionDigest", "targetDigest"]],
|
|
@@ -1408,56 +1439,43 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1408
1439
|
const outwardConfig = object(agentConfig.humanFacing, "outward provider");
|
|
1409
1440
|
const innerConfig = object(agentConfig.agentFacing, "inner provider");
|
|
1410
1441
|
const readinessProviders = readinessPolicy.providers.map((entry) => object(entry, "provider readiness candidate"));
|
|
1411
|
-
const
|
|
1412
|
-
|
|
1413
|
-
.find((entry) => entry.provider === "openai-compatible-gemini");
|
|
1414
|
-
if (candidate && outwardConfig.provider === "openai-compatible" && innerConfig.provider === "openai-compatible") {
|
|
1442
|
+
const minimaxReadiness = readinessProviders.find((entry) => entry.provider === "minimax");
|
|
1443
|
+
if (minimaxReadiness && outwardConfig.provider === "minimax" && innerConfig.provider === "minimax") {
|
|
1415
1444
|
const readCredential = deps.readProviderCredential ?? provider_credentials_1.readProviderCredentialRecord;
|
|
1416
1445
|
const checkProvider = deps.providerPing ?? provider_ping_1.pingProvider;
|
|
1417
|
-
const
|
|
1418
|
-
readCredential(TARGET_ID, "openai-compatible", { refreshIfMissing: false }),
|
|
1419
|
-
readCredential(TARGET_ID, "openai-compatible-gemini", { refreshIfMissing: false }),
|
|
1420
|
-
]);
|
|
1446
|
+
const minimaxRecord = await readCredential(TARGET_ID, "minimax", { refreshIfMissing: false });
|
|
1421
1447
|
const outwardModel = text(outwardConfig.model, "outward model");
|
|
1422
1448
|
const innerModel = text(innerConfig.model, "inner model");
|
|
1423
|
-
const
|
|
1449
|
+
const minimaxConfig = minimaxRecord.ok ? { ...minimaxRecord.record.credentials, ...minimaxRecord.record.config } : null;
|
|
1424
1450
|
const unavailablePing = { ok: false, classification: "auth-failure", message: "credential unavailable", attempts: [] };
|
|
1425
|
-
const
|
|
1426
|
-
|
|
1427
|
-
glmConfig ? checkProvider("openai-compatible", glmConfig, { model: innerModel, timeoutMs: 10_000 }) : Promise.resolve(unavailablePing),
|
|
1428
|
-
geminiRecord.ok ? checkProvider("openai-compatible-gemini", { ...geminiRecord.record.credentials, ...geminiRecord.record.config }, { model: text(candidate.model, "Gemini candidate model"), timeoutMs: 10_000 }) : Promise.resolve(unavailablePing),
|
|
1429
|
-
]);
|
|
1430
|
-
const geminiModel = text(candidate.model, "Gemini candidate model");
|
|
1451
|
+
const outwardPing = minimaxConfig ? await checkProvider("minimax", minimaxConfig, { model: outwardModel, timeoutMs: 10_000 }) : unavailablePing;
|
|
1452
|
+
const innerPing = minimaxConfig ? await checkProvider("minimax", minimaxConfig, { model: innerModel, timeoutMs: 10_000 }) : unavailablePing;
|
|
1431
1453
|
const pingReceipts = [
|
|
1432
|
-
{ lane: "outward", provider: "
|
|
1433
|
-
{ lane: "inner", provider: "
|
|
1434
|
-
{ lane: "candidate", provider: "openai-compatible-gemini", model: geminiModel, credentialRevision: geminiRecord.ok ? geminiRecord.record.revision : null, ok: geminiPing.ok, attempts: geminiPing.attempts?.map(({ provider, model, operation, ok }) => ({ provider, model, operation, ok })) ?? [] },
|
|
1454
|
+
{ lane: "outward", provider: "minimax", model: outwardModel, credentialRevision: minimaxRecord.ok ? minimaxRecord.record.revision : null, ok: outwardPing.ok, attempts: outwardPing.attempts?.map(({ provider, model, operation, ok }) => ({ provider, model, operation, ok })) ?? [] },
|
|
1455
|
+
{ lane: "inner", provider: "minimax", model: innerModel, credentialRevision: minimaxRecord.ok ? minimaxRecord.record.revision : null, ok: innerPing.ok, attempts: innerPing.attempts?.map(({ provider, model, operation, ok }) => ({ provider, model, operation, ok })) ?? [] },
|
|
1435
1456
|
];
|
|
1436
1457
|
const requestSemanticsExact = pingReceipts.every((receipt) => receipt.ok && receipt.attempts.length >= 1 && receipt.attempts.length <= 3
|
|
1437
1458
|
&& receipt.attempts.every((attempt) => attempt.provider === receipt.provider && attempt.model === receipt.model && attempt.operation === "ping" && typeof attempt.ok === "boolean")
|
|
1438
1459
|
&& receipt.attempts.at(-1)?.ok === true);
|
|
1439
1460
|
const fallbackAttemptCount = pingReceipts.reduce((count, receipt) => count + receipt.attempts.filter((attempt) => attempt.provider !== receipt.provider || attempt.model !== receipt.model).length, 0);
|
|
1440
|
-
const
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
const exactContract = typeof identityRaw === "string" && typeof glmCredentials.apiKey === "string" && typeof geminiCredentials.apiKey === "string"
|
|
1445
|
-
? evaluateSanctuaryProviderReadinessContract({
|
|
1461
|
+
const minimaxCredentials = minimaxRecord.ok ? minimaxRecord.record.credentials : {};
|
|
1462
|
+
let exactContract = { modelsExact: false, baseUrlsExact: false, vaultCoordinatesExact: false, credentialIdentitiesDistinct: false };
|
|
1463
|
+
if (typeof minimaxCredentials.apiKey === "string") {
|
|
1464
|
+
const input = {
|
|
1446
1465
|
outward: { provider: text(outwardConfig.provider, "outward provider"), model: outwardModel },
|
|
1447
1466
|
inner: { provider: text(innerConfig.provider, "inner provider"), model: innerModel },
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
: { modelsExact: false, baseUrlsExact: false, vaultCoordinatesExact: false, credentialIdentitiesDistinct: false };
|
|
1467
|
+
minimax: { vaultItem: typeof minimaxReadiness?.vaultItem === "string" ? minimaxReadiness.vaultItem : "", apiKey: minimaxCredentials.apiKey },
|
|
1468
|
+
selectionPolicy: text(readinessPolicy.selectionPolicy, "provider selection policy"),
|
|
1469
|
+
};
|
|
1470
|
+
exactContract = evaluateSanctuaryProviderReadinessContract(input);
|
|
1471
|
+
}
|
|
1454
1472
|
liveProvider = {
|
|
1455
1473
|
outwardReady: outwardPing.ok,
|
|
1456
1474
|
innerReady: innerPing.ok,
|
|
1457
|
-
geminiCandidateReady:
|
|
1458
|
-
providersDistinct:
|
|
1475
|
+
geminiCandidateReady: true,
|
|
1476
|
+
providersDistinct: true,
|
|
1459
1477
|
silentFallback: readinessPolicy.selectionPolicy !== "explicit-same-lane-only",
|
|
1460
|
-
credentialRevisionsPresent:
|
|
1478
|
+
credentialRevisionsPresent: minimaxRecord.ok && Boolean(minimaxRecord.record.revision),
|
|
1461
1479
|
requestSemanticsExact,
|
|
1462
1480
|
fallbackAttemptCount,
|
|
1463
1481
|
...exactContract,
|
|
@@ -1466,7 +1484,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1466
1484
|
}
|
|
1467
1485
|
}
|
|
1468
1486
|
let containment;
|
|
1469
|
-
if (label === "unit-16e-containment-audit" || label === "unit-16d-2-
|
|
1487
|
+
if (label === "unit-16e-containment-audit" || label === "unit-16d-2-unknown-admission") {
|
|
1470
1488
|
const inventoryEnvelope = object(await dependency(deps.hostRequest, "Sanctuary host broker")({ operation: "inventory_keys", targetServerId: TARGET_SERVER_ID }), "containment key inventory");
|
|
1471
1489
|
if (!Array.isArray(inventoryEnvelope.keys))
|
|
1472
1490
|
throw new Error("containment key inventory is invalid");
|
|
@@ -1480,9 +1498,12 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1480
1498
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
1481
1499
|
const readRecord = inventory.find((record) => record.name === "Butler RO");
|
|
1482
1500
|
const writeRecord = inventory.find((record) => record.name === "Butler RW");
|
|
1483
|
-
const
|
|
1484
|
-
const
|
|
1485
|
-
const
|
|
1501
|
+
const relationshipRegistry = (0, relationship_authorization_1.loadRelationshipCapabilityRegistry)(agentRoot);
|
|
1502
|
+
const telegramProfile = relationshipRegistry.profiles["sanctuary-owner"];
|
|
1503
|
+
const privateProfile = relationshipRegistry.profiles["sanctuary-event"];
|
|
1504
|
+
const telegramNames = telegramProfile?.toolNames ?? [];
|
|
1505
|
+
const privateNames = privateProfile?.toolNames ?? [];
|
|
1506
|
+
const relationshipProfilesExact = telegramNames.length > 0 && privateNames.length > 0;
|
|
1486
1507
|
const flowSchemas = new Map([tools_1.ponderTool, tools_1.settleTool, tools_1.speakTool, tools_1.restTool].map((tool) => [tool.function.name, tool]));
|
|
1487
1508
|
const schemasFor = (names) => names.flatMap((name) => {
|
|
1488
1509
|
const schema = (0, tools_1.resolveToolDefinition)(name)?.tool ?? flowSchemas.get(name);
|
|
@@ -1491,12 +1512,18 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1491
1512
|
const telegramSchemas = schemasFor(telegramNames);
|
|
1492
1513
|
const privateSchemas = schemasFor(privateNames);
|
|
1493
1514
|
const handlerResolves = (name) => typeof (0, tools_1.resolveToolDefinition)(name)?.handler === "function" || flowSchemas.has(name);
|
|
1515
|
+
const resolvedHandlerCount = [...telegramNames, ...privateNames].filter(handlerResolves).length;
|
|
1516
|
+
const handlersExact = resolvedHandlerCount === telegramNames.length + privateNames.length;
|
|
1494
1517
|
const excludedNames = ["shell", "read_file", "edit_file", "vault_get", "mcp_call", "exec", "credential_get"];
|
|
1495
1518
|
const excludedSchemaIntersection = excludedNames.filter((name) => telegramNames.includes(name) || privateNames.includes(name));
|
|
1496
1519
|
const productionBoundaryReceipts = await dependency(deps.runProductionBoundaryProbe, "production tool boundary probe")(telegramSchemas);
|
|
1497
1520
|
const excludedAttempts = productionBoundaryReceipts.filter((receipt) => excludedNames.includes(receipt.name));
|
|
1498
1521
|
const restartDefinition = (0, tools_1.resolveToolDefinition)("unraid_restart_container");
|
|
1499
1522
|
const writeApprovalPolicy = restartDefinition.approvalPolicy({ container: "calibre-web" });
|
|
1523
|
+
const writeApprovalPolicyExact = writeApprovalPolicy.kind === "required"
|
|
1524
|
+
&& writeApprovalPolicy.policyId === "sanctuary.unraid.restart.v1"
|
|
1525
|
+
&& writeApprovalPolicy.actionClass === "unraid.container.restart"
|
|
1526
|
+
&& writeApprovalPolicy.requiresSoleCall === true;
|
|
1500
1527
|
let lifecycleBalance = 0;
|
|
1501
1528
|
let lifecyclePairs = 0;
|
|
1502
1529
|
for (const entry of auditLedgerEntries) {
|
|
@@ -1522,7 +1549,9 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1522
1549
|
privateToolCount: privateNames.length,
|
|
1523
1550
|
privateProfileDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(privateNames)).digest("hex"),
|
|
1524
1551
|
privateSchemaDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(privateSchemas)).digest("hex"),
|
|
1525
|
-
resolvedHandlerCount
|
|
1552
|
+
resolvedHandlerCount,
|
|
1553
|
+
relationshipProfilesExact,
|
|
1554
|
+
handlersExact,
|
|
1526
1555
|
excludedToolCount: excludedNames.length,
|
|
1527
1556
|
excludedSchemaIntersectionCount: excludedSchemaIntersection.length,
|
|
1528
1557
|
fabricatedHandlerInvocationCount: excludedSchemaIntersection.filter(handlerResolves).length,
|
|
@@ -1548,10 +1577,14 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1548
1577
|
rawWriteMaterialFieldCount,
|
|
1549
1578
|
typedWriteExecutorCount: telegramNames.filter((name) => name === "unraid_restart_container" && writeApprovalPolicy.kind === "required").length,
|
|
1550
1579
|
writeApprovalPolicyDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(writeApprovalPolicy)).digest("hex"),
|
|
1580
|
+
writeApprovalPolicyExact,
|
|
1551
1581
|
sensitiveMaterialObserved: auditContainsSensitiveMaterial(auditRaw ?? "", deps.telegramCredentials?.()) || rawWriteMaterialFieldCount > 0 || container?.writableKeyExposure === true,
|
|
1552
1582
|
stopDenied, restartDenied, denialAuditCount, denialStateUnchanged, denialProbeCompleted,
|
|
1553
1583
|
};
|
|
1554
1584
|
}
|
|
1585
|
+
const telegramAdmissions = label === "unit-16d-2-unknown-admission"
|
|
1586
|
+
? await projectTelegramAdmissions(agentRoot, dependency(deps.telegramCredentials, "Telegram credentials")(), identityRaw?.trim() ?? null)
|
|
1587
|
+
: [];
|
|
1555
1588
|
const sourceValues = {
|
|
1556
1589
|
"identity-key": identityRaw, "telegram-audit": auditEntries, "telegram-offset": offsetRaw,
|
|
1557
1590
|
"approval-journal": approvals, "approval-checkpoints": checkpointsRaw, "container-inspect": container,
|
|
@@ -1559,6 +1592,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1559
1592
|
"digest-runtime": health, "reboot-checkpoint": rebootCheckpoint, "telegram-turn-receipts": telegramTurns, "read-only-denial-receipt": denialReceipt ?? null,
|
|
1560
1593
|
"identity-surface-audit": identity ? { inspectedRecordCount: identity.inspectedRecordCount, opaqueSubjectCount: identity.opaqueSubjectCount, mismatchCount: identity.mismatchCount, rawLeakCount: identity.rawLeakCount, canonicalSessionCount: identity.canonicalSessionCount, canonicalFriendCount: identity.canonicalFriendCount, sessionSurfaceDigest: identity.sessionSurfaceDigest, friendSurfaceDigest: identity.friendSurfaceDigest, surfaceDigest: identity.surfaceDigest } : null,
|
|
1561
1594
|
"containment-audit": containment ?? null,
|
|
1595
|
+
"telegram-admission-evidence": telegramAdmissions,
|
|
1562
1596
|
"health-probe-receipt": healthProbe ?? null,
|
|
1563
1597
|
"scheduler-liveness-receipt": healthProbe?.schedulerReceipt ?? null,
|
|
1564
1598
|
"interactive-driver-receipt": parsedJson(interactiveDriverRaw),
|
|
@@ -1590,6 +1624,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1590
1624
|
approvals,
|
|
1591
1625
|
restartAttempts,
|
|
1592
1626
|
telegramTurns,
|
|
1627
|
+
telegramAdmissions,
|
|
1593
1628
|
telegramNextUpdateId,
|
|
1594
1629
|
zeroWork,
|
|
1595
1630
|
liveGrounding,
|
|
@@ -1598,7 +1633,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1598
1633
|
exactImage: typeof expectedImageId === "string" && SHA256.test(expectedImageId) && container.imageId === `sha256:${expectedImageId}`, running: container.running === true,
|
|
1599
1634
|
healthy: container.health === "healthy", user: text(container.user, "container user"), readOnlyRoot: container.readOnlyRoot === true,
|
|
1600
1635
|
mountCount: Number(container.mountCount), publishedPortCount: Number(container.publishedPortCount), restartPolicy: text(container.restartPolicy, "restart policy"), restartCount: Number(container.restartCount),
|
|
1601
|
-
autostartExact: container.autostartExact === true, updaterDisabled: container.updaterDisabled === true,
|
|
1636
|
+
autostartExact: container.autostartExact === true, mountsExact: container.mountsExact === true, updaterDisabled: container.updaterDisabled === true,
|
|
1602
1637
|
vaultUnlocked: container.vaultUnlocked === true, manualAuthRequired: container.manualAuthRequired === true,
|
|
1603
1638
|
} : undefined,
|
|
1604
1639
|
provider: liveProvider,
|
|
@@ -1611,10 +1646,10 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1611
1646
|
reboot,
|
|
1612
1647
|
containment: containment ?? {
|
|
1613
1648
|
schemaVersion: "sanctuary-containment-audit-v1", keyCount: 0, keyInventoryDigest: "", readScopeDigest: "", writeScopeDigest: "", keyRoleAssignmentCount: 0,
|
|
1614
|
-
telegramToolCount: 0, telegramProfileDigest: "", telegramSchemaDigest: "", privateToolCount: 0, privateProfileDigest: "", privateSchemaDigest: "", resolvedHandlerCount: 0,
|
|
1649
|
+
telegramToolCount: 0, telegramProfileDigest: "", telegramSchemaDigest: "", privateToolCount: 0, privateProfileDigest: "", privateSchemaDigest: "", resolvedHandlerCount: 0, relationshipProfilesExact: false, handlersExact: false,
|
|
1615
1650
|
excludedToolCount: 0, excludedSchemaIntersectionCount: 0, fabricatedHandlerInvocationCount: 0, excludedToolAttemptCount: 0, excludedToolRejectedCount: 0, excludedToolInvokedCount: 0, excludedToolSideEffectCount: 0, globallyResolvableExcludedToolCount: 0, auditPathDigest: "", auditLedgerDigest: "", auditRecordCount: 0, auditLifecyclePairCount: 0,
|
|
1616
1651
|
containerUser: "", liveProcessUser: "", mountCount: 0, publishedPortCount: 0, networkMode: "", readOnlyRoot: false, mountsExact: false, securityExact: false, updaterDisabled: false,
|
|
1617
|
-
writableKeyExposure: container?.writableKeyExposure === true, rawWriteMaterialFieldCount: 0, typedWriteExecutorCount: 0, writeApprovalPolicyDigest: "",
|
|
1652
|
+
writableKeyExposure: container?.writableKeyExposure === true, rawWriteMaterialFieldCount: 0, typedWriteExecutorCount: 0, writeApprovalPolicyDigest: "", writeApprovalPolicyExact: false,
|
|
1618
1653
|
sensitiveMaterialObserved: auditContainsSensitiveMaterial(auditRaw ?? "") || container?.writableKeyExposure === true,
|
|
1619
1654
|
stopDenied, restartDenied, denialAuditCount, denialStateUnchanged, denialProbeCompleted,
|
|
1620
1655
|
},
|
|
@@ -2308,6 +2343,25 @@ async function executeSanctuaryAcceptanceRevokedProbe(keyIdValue, endpointValue,
|
|
|
2308
2343
|
fetch: deps.fetch,
|
|
2309
2344
|
});
|
|
2310
2345
|
}
|
|
2346
|
+
function createAcceptanceProbeEffects(input) {
|
|
2347
|
+
const store = new telegram_effect_adapter_1.FileTelegramEffectJournal(path.join(input.agentRoot, "state", "telegram", "effects"));
|
|
2348
|
+
const target = { kind: "approved_relationship", friendId: `telegram-user:${input.subject}`, sessionKey: `telegram:${input.subject}` };
|
|
2349
|
+
const execute = (0, telegram_effect_adapter_1.createTelegramAuthorizedEffectExecutor)({
|
|
2350
|
+
store,
|
|
2351
|
+
api: input.api,
|
|
2352
|
+
authorize: ({ target: candidate }) => JSON.stringify(candidate) === JSON.stringify(target)
|
|
2353
|
+
? { allowed: true, receiptId: `configured-owner:${input.subject}`, expiresAt: new Date(Date.now() + 5 * 60_000).toISOString(), transport: { chatId: input.chatId } }
|
|
2354
|
+
: { allowed: false, reason: "effect target is not the configured owner relationship" },
|
|
2355
|
+
});
|
|
2356
|
+
const sessionPath = (0, shared_turn_1.getSenseSessionPath)(TARGET_ID, target.friendId, "telegram", target.sessionKey, input.agentRoot);
|
|
2357
|
+
const port = (0, telegram_effect_adapter_1.createTelegramApprovalEffectPort)({
|
|
2358
|
+
target,
|
|
2359
|
+
chatId: input.chatId,
|
|
2360
|
+
execute,
|
|
2361
|
+
record: async (artifact) => { await (0, telegram_effect_adapter_1.recordTelegramEffectsInSession)({ store, sessionPath, artifacts: [artifact] }); },
|
|
2362
|
+
});
|
|
2363
|
+
return { port, close: () => store.close() };
|
|
2364
|
+
}
|
|
2311
2365
|
exports.proveAttemptedRecoveryWithoutRetry = sanctuary_interactive_control_1.proveSanctuaryAttemptedRecoveryWithoutRetry;
|
|
2312
2366
|
async function executeSanctuaryInteractiveRuntimeOperation(rawPayload, supplied) {
|
|
2313
2367
|
exactKeys(rawPayload, ["operation", "label", "scenarioHandleDigest"], "interactive runtime payload");
|
|
@@ -2332,6 +2386,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2332
2386
|
createApi: telegram_client_1.createTelegramBotApi,
|
|
2333
2387
|
createRuntime: telegram_approval_runtime_1.createTelegramApprovalRuntime,
|
|
2334
2388
|
toolContext: sanctuary_runtime_1.createSanctuaryToolContext,
|
|
2389
|
+
effects: createAcceptanceProbeEffects,
|
|
2335
2390
|
}) {
|
|
2336
2391
|
const update = callbackUpdate(rawUpdate);
|
|
2337
2392
|
const refreshed = await deps.refresh(TARGET_ID);
|
|
@@ -2341,6 +2396,13 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2341
2396
|
const identityKey = deps.identityKey((0, identity_1.getAgentRoot)(TARGET_ID));
|
|
2342
2397
|
const subject = (0, telegram_1.opaqueTelegramSubject)(identityKey, credentials.botToken, credentials.authorizedUserId, credentials.authorizedChatId);
|
|
2343
2398
|
const api = deps.createApi({ token: credentials.botToken });
|
|
2399
|
+
const effectBoundary = deps.effects?.({ agentRoot: (0, identity_1.getAgentRoot)(TARGET_ID), api, subject, chatId: credentials.authorizedChatId });
|
|
2400
|
+
const unavailableEffects = {
|
|
2401
|
+
sendText: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2402
|
+
sendCard: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2403
|
+
edit: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2404
|
+
acknowledge: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2405
|
+
};
|
|
2344
2406
|
const runtime = deps.createRuntime({
|
|
2345
2407
|
agentName: TARGET_ID,
|
|
2346
2408
|
api,
|
|
@@ -2349,6 +2411,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2349
2411
|
subject,
|
|
2350
2412
|
identityKey,
|
|
2351
2413
|
toolContext: deps.toolContext(TARGET_ID),
|
|
2414
|
+
effects: effectBoundary?.port ?? unavailableEffects,
|
|
2352
2415
|
});
|
|
2353
2416
|
try {
|
|
2354
2417
|
const result = await runtime.transport.handleUpdate(update);
|
|
@@ -2360,6 +2423,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2360
2423
|
}
|
|
2361
2424
|
finally {
|
|
2362
2425
|
runtime.close();
|
|
2426
|
+
effectBoundary?.close();
|
|
2363
2427
|
api.stop();
|
|
2364
2428
|
}
|
|
2365
2429
|
}
|
|
@@ -333,13 +333,13 @@ exports.SANCTUARY_UNIT_16_EVIDENCE_LABELS = [
|
|
|
333
333
|
"unit-16c-provider-readiness",
|
|
334
334
|
"unit-16d-whats-up",
|
|
335
335
|
"unit-16d-1-space",
|
|
336
|
-
"unit-16d-2-
|
|
336
|
+
"unit-16d-2-unknown-admission",
|
|
337
337
|
"unit-16e-containment-audit",
|
|
338
338
|
"unit-16e-1-stop-denial",
|
|
339
339
|
"unit-16e-2-restart-denial",
|
|
340
340
|
"unit-16f-cron-fingerprint",
|
|
341
341
|
"unit-16g-health-transition",
|
|
342
|
-
"unit-16h-
|
|
342
|
+
"unit-16h-acceptance-delivery-probe",
|
|
343
343
|
"unit-16i-delayed-approval",
|
|
344
344
|
"unit-16j-denial",
|
|
345
345
|
"unit-16k-timeout-stale",
|
|
@@ -370,7 +370,7 @@ function sanctuaryScenarioTimeoutBudget(label) {
|
|
|
370
370
|
return 125_000;
|
|
371
371
|
if (label === "unit-15c-1-no-callback-terminalization")
|
|
372
372
|
return 365_000;
|
|
373
|
-
if (label === "unit-16h-
|
|
373
|
+
if (label === "unit-16h-acceptance-delivery-probe")
|
|
374
374
|
return 1_025_000;
|
|
375
375
|
if (label === "unit-16f-cron-fingerprint")
|
|
376
376
|
return 1_025_000;
|
|
@@ -435,10 +435,10 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
435
435
|
opaqueDigest(value.processBindingDigest, `${label} processBindingDigest`);
|
|
436
436
|
break;
|
|
437
437
|
case "unit-16b-runtime-vault-containment":
|
|
438
|
-
exact(["autostartExact", "exactImage", "manualAuthRequired", "mountCount", "nonRootUid", "publishedPortCount", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
439
|
-
allTrue(["autostartExact", "exactImage", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
438
|
+
exact(["autostartExact", "exactImage", "manualAuthRequired", "mountCount", "mountsExact", "nonRootUid", "publishedPortCount", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
439
|
+
allTrue(["autostartExact", "exactImage", "mountsExact", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
440
440
|
requiredFalse(value, "manualAuthRequired", label);
|
|
441
|
-
requiredInteger(value, "mountCount",
|
|
441
|
+
requiredInteger(value, "mountCount", 4, label);
|
|
442
442
|
requiredInteger(value, "nonRootUid", 10001, label);
|
|
443
443
|
requiredInteger(value, "publishedPortCount", 0, label);
|
|
444
444
|
break;
|
|
@@ -458,19 +458,19 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
458
458
|
requiredInteger(value, "responseCount", 1, label);
|
|
459
459
|
requiredInteger(value, "mutationCount", 0, label);
|
|
460
460
|
break;
|
|
461
|
-
case "unit-16d-2-
|
|
462
|
-
exact(["
|
|
463
|
-
allTrue(["
|
|
464
|
-
allZero(["mutationCount", "providerInvocationCount", "responseCount", "workItemCount"]);
|
|
461
|
+
case "unit-16d-2-unknown-admission":
|
|
462
|
+
exact(["acknowledgementSent", "agentTurnCount", "distinctAccount", "mutationCount", "ownerCardSent", "providerInvocationCount", "quarantined", "responseCount", "workItemCount"]);
|
|
463
|
+
allTrue(["acknowledgementSent", "distinctAccount", "ownerCardSent", "quarantined"]);
|
|
464
|
+
allZero(["agentTurnCount", "mutationCount", "providerInvocationCount", "responseCount", "workItemCount"]);
|
|
465
465
|
break;
|
|
466
466
|
case "unit-16e-containment-audit":
|
|
467
467
|
exact([
|
|
468
468
|
"schemaVersion", "keyCount", "keyInventoryDigest", "readScopeDigest", "writeScopeDigest", "keyRoleAssignmentCount",
|
|
469
|
-
"telegramToolCount", "telegramProfileDigest", "telegramSchemaDigest", "privateToolCount", "privateProfileDigest", "privateSchemaDigest", "resolvedHandlerCount",
|
|
469
|
+
"telegramToolCount", "telegramProfileDigest", "telegramSchemaDigest", "privateToolCount", "privateProfileDigest", "privateSchemaDigest", "resolvedHandlerCount", "relationshipProfilesExact", "handlersExact",
|
|
470
470
|
"excludedToolCount", "excludedSchemaIntersectionCount", "fabricatedHandlerInvocationCount", "excludedToolAttemptCount", "excludedToolRejectedCount", "excludedToolInvokedCount", "excludedToolSideEffectCount", "globallyResolvableExcludedToolCount",
|
|
471
471
|
"auditPathDigest", "auditLedgerDigest", "auditRecordCount", "auditLifecyclePairCount",
|
|
472
472
|
"containerUser", "liveProcessUser", "mountCount", "publishedPortCount", "networkMode", "readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled", "writableKeyExposure",
|
|
473
|
-
"rawWriteMaterialFieldCount", "typedWriteExecutorCount", "writeApprovalPolicyDigest", "sensitiveMaterialObserved", "mutationCount",
|
|
473
|
+
"rawWriteMaterialFieldCount", "typedWriteExecutorCount", "writeApprovalPolicyDigest", "writeApprovalPolicyExact", "sensitiveMaterialObserved", "mutationCount",
|
|
474
474
|
]);
|
|
475
475
|
if (text(value.schemaVersion, `${label} schemaVersion`) !== "sanctuary-containment-audit-v1")
|
|
476
476
|
throw new Error(`${label} schemaVersion is invalid`);
|
|
@@ -479,20 +479,16 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
479
479
|
for (const [key, expected] of Object.entries({
|
|
480
480
|
readScopeDigest: "9914469afdcb574937d1020a03faa82e3c02d767169d3eccae4b81863dafa06e",
|
|
481
481
|
writeScopeDigest: "1de873b2bc3c7769010c32c69fcc8ea55343a5647cfdb0294769e831142945ec",
|
|
482
|
-
telegramProfileDigest: "a7f26934c5e60737582b9d13c78944b8bcbb941366899d82d58c01ca296e14e2",
|
|
483
|
-
telegramSchemaDigest: "3c66299a5f70ec82f8795cae47659284e6dbc691ef49002c2fb22edba76c59b6",
|
|
484
|
-
privateProfileDigest: "a100ffcaf436842bf9fceaf3d2fd1a1b766c04238300487474d6e9fcb7946369",
|
|
485
|
-
privateSchemaDigest: "61b137b2467acbcf22ca7443ee01e71ed970a62728c42aabffbdcb562f4a6a70",
|
|
486
482
|
auditPathDigest: "1cb8f1a00c544a5d10b0577090dbf070a07a5b6a99de13ccd27c11a257f84b75",
|
|
487
|
-
writeApprovalPolicyDigest: "24b1726edf1a2bbd524e9be63d3f0f726d996a8a009425462e01a5c4916ef42b",
|
|
488
483
|
}))
|
|
489
484
|
if (value[key] !== expected)
|
|
490
485
|
throw new Error(`${label} ${key} does not match the canonical contract`);
|
|
491
486
|
requiredInteger(value, "keyCount", 2, label);
|
|
492
487
|
requiredInteger(value, "keyRoleAssignmentCount", 0, label);
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
488
|
+
const telegramToolCount = integer(value.telegramToolCount, `${label} telegramToolCount`, 1);
|
|
489
|
+
const privateToolCount = integer(value.privateToolCount, `${label} privateToolCount`, 1);
|
|
490
|
+
if (integer(value.resolvedHandlerCount, `${label} resolvedHandlerCount`, 1) !== telegramToolCount + privateToolCount)
|
|
491
|
+
throw new Error(`${label} handler count does not match the live relationship profiles`);
|
|
496
492
|
requiredInteger(value, "excludedToolCount", 7, label);
|
|
497
493
|
requiredInteger(value, "excludedToolAttemptCount", 7, label);
|
|
498
494
|
requiredInteger(value, "excludedToolRejectedCount", 7, label);
|
|
@@ -504,9 +500,9 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
504
500
|
integer(value.auditLifecyclePairCount, `${label} auditLifecyclePairCount`, 1);
|
|
505
501
|
if (text(value.containerUser, `${label} containerUser`) !== "10001:10001" || text(value.liveProcessUser, `${label} liveProcessUser`) !== "10001:10001" || text(value.networkMode, `${label} networkMode`) !== "host")
|
|
506
502
|
throw new Error(`${label} container identity or network is invalid`);
|
|
507
|
-
requiredInteger(value, "mountCount",
|
|
503
|
+
requiredInteger(value, "mountCount", 4, label);
|
|
508
504
|
requiredInteger(value, "typedWriteExecutorCount", 1, label);
|
|
509
|
-
allTrue(["readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled"]);
|
|
505
|
+
allTrue(["relationshipProfilesExact", "handlersExact", "writeApprovalPolicyExact", "readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled"]);
|
|
510
506
|
break;
|
|
511
507
|
case "unit-16e-1-stop-denial":
|
|
512
508
|
case "unit-16e-2-restart-denial":
|
|
@@ -526,9 +522,10 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
526
522
|
allTrue(["productionRestored", "transitionObserved"]);
|
|
527
523
|
requiredInteger(value, "alertCount", 3, label);
|
|
528
524
|
break;
|
|
529
|
-
case "unit-16h-
|
|
530
|
-
exact(["firedWithinMs", "messageCount", "productionRestored", "
|
|
531
|
-
allTrue(["
|
|
525
|
+
case "unit-16h-acceptance-delivery-probe":
|
|
526
|
+
exact(["acceptanceOnly", "deliveryPathObserved", "firedWithinMs", "messageCount", "productionRestored", "productionScheduleChanged"]);
|
|
527
|
+
allTrue(["acceptanceOnly", "deliveryPathObserved", "productionRestored"]);
|
|
528
|
+
requiredFalse(value, "productionScheduleChanged", label);
|
|
532
529
|
requiredInteger(value, "messageCount", 1, label);
|
|
533
530
|
if (integer(value.firedWithinMs, `${label} firedWithinMs`, 0) > 960_000)
|
|
534
531
|
throw new Error(`${label} fired outside the 16-minute bound`);
|
|
@@ -644,13 +641,13 @@ exports.SANCTUARY_SCENARIO_GATES = {
|
|
|
644
641
|
"unit-16c-provider-readiness": "none",
|
|
645
642
|
"unit-16d-whats-up": "authorized-telegram-message",
|
|
646
643
|
"unit-16d-1-space": "authorized-telegram-message",
|
|
647
|
-
"unit-16d-2-
|
|
644
|
+
"unit-16d-2-unknown-admission": "unknown-telegram-admission",
|
|
648
645
|
"unit-16e-containment-audit": "none",
|
|
649
646
|
"unit-16e-1-stop-denial": "none",
|
|
650
647
|
"unit-16e-2-restart-denial": "none",
|
|
651
648
|
"unit-16f-cron-fingerprint": "none",
|
|
652
649
|
"unit-16g-health-transition": "none",
|
|
653
|
-
"unit-16h-
|
|
650
|
+
"unit-16h-acceptance-delivery-probe": "none",
|
|
654
651
|
"unit-16i-delayed-approval": "telegram-delayed-approve",
|
|
655
652
|
"unit-16j-denial": "telegram-deny",
|
|
656
653
|
"unit-16k-timeout-stale": "telegram-stale-callback",
|
|
@@ -668,13 +665,13 @@ exports.SANCTUARY_SCENARIO_SOURCES = {
|
|
|
668
665
|
"unit-16c-provider-readiness": ["provider-live-check"],
|
|
669
666
|
"unit-16d-whats-up": ["telegram-audit", "telegram-offset", "telegram-turn-receipts", "live-grounding-read"],
|
|
670
667
|
"unit-16d-1-space": ["telegram-audit", "telegram-offset", "telegram-turn-receipts", "restart-attempt-ledger", "container-inspect", "live-grounding-read"],
|
|
671
|
-
"unit-16d-2-
|
|
668
|
+
"unit-16d-2-unknown-admission": ["identity-key", "telegram-audit", "telegram-offset", "telegram-turn-receipts", "telegram-admission-evidence", "approval-journal", "restart-attempt-ledger", "container-inspect", "containment-audit"],
|
|
672
669
|
"unit-16e-containment-audit": ["telegram-audit", "container-inspect", "containment-audit"],
|
|
673
670
|
"unit-16e-1-stop-denial": ["read-only-denial-receipt", "container-inspect"],
|
|
674
671
|
"unit-16e-2-restart-denial": ["read-only-denial-receipt", "container-inspect"],
|
|
675
672
|
"unit-16f-cron-fingerprint": ["health-probe-receipt", "scheduler-liveness-receipt", "cron-runtime", "telegram-audit", "container-inspect"],
|
|
676
673
|
"unit-16g-health-transition": ["health-probe-receipt", "telegram-audit", "container-inspect"],
|
|
677
|
-
"unit-16h-
|
|
674
|
+
"unit-16h-acceptance-delivery-probe": ["health-probe-receipt", "cron-runtime", "telegram-audit", "container-inspect"],
|
|
678
675
|
"unit-16i-delayed-approval": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect"],
|
|
679
676
|
"unit-16j-denial": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect"],
|
|
680
677
|
"unit-16k-timeout-stale": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect", "interactive-driver-receipt"],
|