@cotal-ai/manager 0.71.0 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +170 -148
- package/dist/manager.js.map +1 -1
- package/dist/static-lifecycle.d.ts +13 -2
- package/dist/static-lifecycle.d.ts.map +1 -1
- package/dist/static-lifecycle.js +21 -25
- package/dist/static-lifecycle.js.map +1 -1
- package/package.json +12 -12
package/dist/manager.js
CHANGED
|
@@ -4,7 +4,7 @@ import { credsAuthenticator } from "@nats-io/transport-node";
|
|
|
4
4
|
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
5
5
|
import { isAbsolute, join, dirname, resolve } from "node:path";
|
|
6
6
|
import Headless from "@xterm/headless";
|
|
7
|
-
import { CotalEndpoint, MANAGED_HANDOFF_KIND, accountFromCreds, credsClaims, DEFAULT_SERVER, DEV_OWNER, MANAGER_LEASE_RENEW_MS, STANDING_RENEWABLE_TTL_SEC, assertLifecycleToken, discardLaunchArtifacts, divergentSecretStoreNotice, parseDaemonStoreAnswer, parseSecretStoreIdentity, sameSecretStoreIdentity, agentFilePath, clearSpaceHistory, dialerFor, connectorServers, spawnEnvAllow, deprovisionAgent, DeprovisionError, isConcreteChannel, deprovisionTargetPrincipal, firstFreeName, spawnNameError, idFromCreds, inspectCredHealth, credsRenewalDelayMs, composeWirePersona, loadAgentFile, listPersonaCatalog, personaCatalogDescription, personaCatalogReadable, loadCotalConfig, modelPolicyRefusal, mintCreds, mintGeneration, mintAcceptedToken, openIssuedStore, acceptedBucket, issuedBucket, mintLifecycleUid, managedRetirementOpId, mkSecretDir, newIdentity, actionContext, parsePrincipalKey, principalKey, probeConnect, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer, saveAgentFile, subjectMatches, AUTH_ENDPOINT, EP_CMD_RETIRE_LIFECYCLE, controlServiceSubject, eventChannelPrincipal, resolveService, invokeCommand, } from "@cotal-ai/core";
|
|
7
|
+
import { CotalEndpoint, canonicalJson, MANAGED_HANDOFF_KIND, accountFromCreds, credsClaims, DEFAULT_SERVER, DEV_OWNER, MANAGER_LEASE_RENEW_MS, STANDING_RENEWABLE_TTL_SEC, assertLifecycleToken, discardLaunchArtifacts, divergentSecretStoreNotice, parseDaemonStoreAnswer, parseSecretStoreIdentity, sameSecretStoreIdentity, agentFilePath, clearSpaceHistory, dialerFor, connectorServers, spawnEnvAllow, deprovisionAgent, DeprovisionError, isConcreteChannel, deprovisionTargetPrincipal, firstFreeName, spawnNameError, idFromCreds, inspectCredHealth, credsRenewalDelayMs, composeWirePersona, loadAgentFile, listPersonaCatalog, personaCatalogDescription, personaCatalogReadable, loadCotalConfig, modelPolicyRefusal, mintCreds, mintGeneration, mintAcceptedToken, openIssuedStore, acceptedBucket, issuedBucket, mintLifecycleUid, managedRetirementOpId, mkSecretDir, newIdentity, actionContext, parsePrincipalKey, principalKey, probeConnect, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer, saveAgentFile, subjectMatches, AUTH_ENDPOINT, EP_CMD_RETIRE_LIFECYCLE, controlServiceSubject, eventChannelPrincipal, resolveService, invokeCommand, } from "@cotal-ai/core";
|
|
8
8
|
import { agentAuthState, agentCredsDir, agentLifecycleSecretFilePaths, agentSecretFilePaths, agentSecretKeyForFile, authDir, claimManagerSiblingIdentities, connectorInstallHint, DELIVERY_CREDS_KIND, extensionConnectors, findCotalRoot, getSpaceAuth, hasUserAuthState, loadExtensionsManifest, loadManagerInstanceIdentity, loadMeshes, localTrustOfSpace, manifestExtensionNames, materializeFromManifest, materializeSecretToFile, MEMBERSHIP_RW_CREDS_KIND, mergeLaunchOptions, remintDaemonCreds, resolveAgentType, resolveOnPath, createManagerInstanceIdentity, spaceMaterialKey, SYSTEM_CREDS_FILES, userAuthStateDir, workspaceSecretStore, writeRenewalRecord } from "@cotal-ai/workspace";
|
|
9
9
|
import { createRuntime, isCustodialRuntime, requireRuntimeAdopt, requireRuntimeReap, RuntimeReapUnproven, } from "./runtime/index.js";
|
|
10
10
|
import { AttachEndpoint } from "./attach-endpoint.js";
|
|
@@ -22,7 +22,7 @@ import { TranscriptReceiver } from "./transcript-receive.js";
|
|
|
22
22
|
// manager-side adapter (transport + slot orchestration + the F1 terminal) — see static-lifecycle.ts.
|
|
23
23
|
import { jetstream, jetstreamManager } from "@nats-io/jetstream";
|
|
24
24
|
import { Kvm } from "@nats-io/kv";
|
|
25
|
-
import { recordsBucket, epAuthBucket, ensureAuthorityStores, ensureContractStore, createEndpointStreams, contractStoreContext, publishContractArtifact, contractArtifactCanonicalBytes, standaloneConnectOpts,
|
|
25
|
+
import { recordsBucket, epAuthBucket, ensureAuthorityStores, ensureContractStore, createEndpointStreams, contractStoreContext, publishContractArtifact, contractArtifactCanonicalBytes, standaloneConnectOpts, rawDigest, STANDING_RENEWABLE_TTL_SEC as MANAGED_STATIC_TTL_SEC, newArtifactSigner, RotatingSigner, generationAnchor, sessionsBucket, SESSION_GRANT_MAX_TTL_MS, REMOTE_MANAGER_IDENTITY_NAMES, } from "@cotal-ai/core";
|
|
26
26
|
// P2 item 6: the manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
|
|
27
27
|
// standup for `attach`, over a dedicated standing session-LEDGER connection (the byte rails ride
|
|
28
28
|
// per-session credentials on their own short-lived connections).
|
|
@@ -32,7 +32,7 @@ import { ManagerSessionPlane, openSessionLedgerKv } from "./session/index.js";
|
|
|
32
32
|
// the register/authorize/serve seams, all driven over a scoped one-shot executor connection.
|
|
33
33
|
import { provisionEndpointGateOpen, endpointRegistrationBarrier, serveIssuanceGateKv, commitSiblingIssuance, markLedgerRowRevoked, epcredRowKey, epgateKey, parseEndpointGate, readEndpointGateGeneration, registerServingInstance, deregisterServiceInstance, serveEndpoint, bindGoal, createGoal, transitionGoal, commitGoalResult, requestGoalCancel, goalAlreadyTerminal, settleGoalUncertain, readGoalResult, readGoalStatus, readGoalSpec, recordGoalIndex, readGoalIndex, clearGoalIndex, listGoalIndex, mintCheckpoint, resumeCheckpoint, readCheckpointSettle, readCheckpointSpec, expireCheckpoint, GOAL_TERMINAL_STATES, goalRefOf, goalProgressTopic, epeSubject, submissionFingerprint, EpEnvelopeError, lifecycleBlocked, lifecycleBlockedFrom, renderLifecycleBlocked, } from "@cotal-ai/core";
|
|
34
34
|
import { MANAGER_ENDPOINT, managerClusterArtifacts, managerCommandDefs, managerContractArtifactValues } from "./manager-service-contract.js";
|
|
35
|
-
import { staticLifecycleTransport, activateStaticLifecycle, runStaticTerminal, readStaticSlot, casStaticSlot, recordSlotCredential, appendStaticCredentialRow, planStaticSlotResume, ownedBySibling, observeStaticSlot, listStaticSlotObservations, renderStaticSlotObservation, StaticSlotReadError, STATIC_SLOT_READ_FAILED_DETAIL, } from "./static-lifecycle.js";
|
|
35
|
+
import { staticLifecycleTransport, activateStaticLifecycle, runStaticTerminal, readStaticSlot, casStaticSlot, recordSlotCredential, appendStaticCredentialRow, planStaticSlotResume, ownedBySibling, observeStaticSlot, listStaticSlotObservations, walkStaticSlots, renderStaticSlotObservation, StaticSlotReadError, STATIC_SLOT_READ_FAILED_DETAIL, } from "./static-lifecycle.js";
|
|
36
36
|
/** Minimum slot lifetime for rate-flooring (P4c). A slot freed (by despawn OR natural exit/reap)
|
|
37
37
|
* before living this long leaves a cooling stamp that still counts toward the ceiling until it
|
|
38
38
|
* expires — so churn (spawn↔despawn or spawn↔fast-exit) can't outrun the concurrency bound. */
|
|
@@ -126,9 +126,11 @@ function retireOpId(lifecycleUid) {
|
|
|
126
126
|
* dash) — what {@link Manager.psOwnerFilter} returns for an unparseable caller so a malformed
|
|
127
127
|
* principal fail-closes to an empty `ps` instead of an unbounded one. */
|
|
128
128
|
const NO_OWNER_MATCHES = "-no-owner-";
|
|
129
|
-
/** A caught value's text for a refusal. A host-supplied store or callback may
|
|
130
|
-
* including one whose `message` is a Symbol or whose `message`
|
|
131
|
-
*
|
|
129
|
+
/** A caught value's text for a refusal or a log line. A host-supplied store, runtime or callback may
|
|
130
|
+
* reject with any value, including `null` or one whose `message` is a Symbol or whose `message`
|
|
131
|
+
* getter or `toString` throws. A handler that throws while building its text skips the work after
|
|
132
|
+
* it, and on a detached chain ends the manager with an unhandled rejection, so the coercion to text
|
|
133
|
+
* runs inside the guard. */
|
|
132
134
|
function rejectionText(e) {
|
|
133
135
|
try {
|
|
134
136
|
return String(e?.message ?? e);
|
|
@@ -137,6 +139,34 @@ function rejectionText(e) {
|
|
|
137
139
|
return "an unreadable rejection";
|
|
138
140
|
}
|
|
139
141
|
}
|
|
142
|
+
/** A caught value as a lifecycle envelope, or undefined when it is not one. A thrown Proxy can throw
|
|
143
|
+
* from `instanceof` itself, so the test runs inside the guard. */
|
|
144
|
+
function caughtEnvelope(e) {
|
|
145
|
+
try {
|
|
146
|
+
return e instanceof EpEnvelopeError ? e : undefined;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** The failed terminal a post-accept fallback commits for `error` and `source`'s optional details.
|
|
153
|
+
* `commitGoalResult` refuses a payload that is not interchangeable JSON, and this terminal must commit
|
|
154
|
+
* whatever failed, so a lone surrogate in the text becomes U+FFFD and details it cannot read or carry
|
|
155
|
+
* (a Proxy's throwing getter, an accessor, a cycle) are dropped. A Proxy can answer the check and the
|
|
156
|
+
* serializer differently, so the detached copy is checked again before it commits. */
|
|
157
|
+
function failedTerminal(error, source) {
|
|
158
|
+
const text = error.replace(/\p{Cs}/gu, "\uFFFD");
|
|
159
|
+
try {
|
|
160
|
+
const details = source?.details;
|
|
161
|
+
if (details) {
|
|
162
|
+
const copy = JSON.parse(canonicalJson(details));
|
|
163
|
+
canonicalJson(copy);
|
|
164
|
+
return { error: text, details: copy };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch { /* unreadable or not interchangeable */ }
|
|
168
|
+
return { error: text };
|
|
169
|
+
}
|
|
140
170
|
/** Run one cleanup step, recording its failure in `failed` as `<what>: <reason>`. A step that threw
|
|
141
171
|
* would otherwise skip every step after it, and a swallowed one would leave nothing to report. */
|
|
142
172
|
async function attemptCleanup(failed, what, step) {
|
|
@@ -911,7 +941,7 @@ export class Manager {
|
|
|
911
941
|
await this.attach.stop();
|
|
912
942
|
throw new Error(held
|
|
913
943
|
? `manager instance ${this.managerInstanceId} already serves space "${this.space}" from ${held.root === this.leaseInfo.root ? "this" : "another"} workspace root (${held.runtime}, pid ${held.pid}, root ${held.root}) - stop it first before restarting the same instance`
|
|
914
|
-
: `could not acquire the manager lease for space "${this.space}": ${e
|
|
944
|
+
: `could not acquire the manager lease for space "${this.space}": ${rejectionText(e)}`);
|
|
915
945
|
}
|
|
916
946
|
this.leaseTimer = setInterval(() => { void this.renewLease(); }, MANAGER_LEASE_RENEW_MS);
|
|
917
947
|
this.leaseTimer.unref?.();
|
|
@@ -948,7 +978,7 @@ export class Manager {
|
|
|
948
978
|
// attempt returns.
|
|
949
979
|
const startupReconcile = this.auth && !this.userMode ? this.reconcileStaticLifecycles() : undefined;
|
|
950
980
|
if (startupReconcile)
|
|
951
|
-
void startupReconcile.catch((e) => console.error(`! ${STARTUP_RECONCILING}: ${e
|
|
981
|
+
void startupReconcile.catch((e) => console.error(`! ${STARTUP_RECONCILING}: ${rejectionText(e)} - no per-alias retry could be planned; a later manager start re-reads unfinished durable terminals`));
|
|
952
982
|
// P2 item 1 (1d): the manager serves NO ctl tiers - its whole control surface is the v0.4
|
|
953
983
|
// service endpoint registered below. The old three-tier rail (self/manager/admin) is deleted;
|
|
954
984
|
// `ctl.delivery`/`ctl.delivery-admin` (the delivery daemon) and `ctl.auth-admin` (the auth
|
|
@@ -999,13 +1029,13 @@ export class Manager {
|
|
|
999
1029
|
await this.renewRemoteExecutor();
|
|
1000
1030
|
}
|
|
1001
1031
|
catch (e) {
|
|
1002
|
-
console.error(`! remote manager renewal pass failed: ${e
|
|
1032
|
+
console.error(`! remote manager renewal pass failed: ${rejectionText(e)}`);
|
|
1003
1033
|
}
|
|
1004
1034
|
try {
|
|
1005
1035
|
await this.runHosting?.renew();
|
|
1006
1036
|
}
|
|
1007
1037
|
catch (e) {
|
|
1008
|
-
console.error(`! remote run-hosting renewal pass failed: ${e
|
|
1038
|
+
console.error(`! remote run-hosting renewal pass failed: ${rejectionText(e)}`);
|
|
1009
1039
|
}
|
|
1010
1040
|
}, intervalMs);
|
|
1011
1041
|
this.credRenewTimer.unref?.();
|
|
@@ -1116,7 +1146,7 @@ export class Manager {
|
|
|
1116
1146
|
reply = await this.ep.requestDeliveryAdmin("reloadStoreIdentity", {}, timeoutMs);
|
|
1117
1147
|
}
|
|
1118
1148
|
catch (e) {
|
|
1119
|
-
const msg = e
|
|
1149
|
+
const msg = rejectionText(e);
|
|
1120
1150
|
if (isAbsentDeliveryAdmin(msg))
|
|
1121
1151
|
return this.absentByLeaseRow(isUnansweredDeliveryAdmin(e));
|
|
1122
1152
|
const failure = `could not challenge the delivery daemon's SecretStore: ${msg}`;
|
|
@@ -1129,7 +1159,7 @@ export class Manager {
|
|
|
1129
1159
|
answer = parseDaemonStoreAnswer(reply.data);
|
|
1130
1160
|
}
|
|
1131
1161
|
catch (e) {
|
|
1132
|
-
throw new Error(`delivery daemon named an unreadable SecretStore: ${e
|
|
1162
|
+
throw new Error(`delivery daemon named an unreadable SecretStore: ${rejectionText(e)}. A daemon older ` +
|
|
1133
1163
|
`than #1694 replies with a bare store identity and no answerer binding; this manager ` +
|
|
1134
1164
|
`cannot establish which process answered, so nothing reminted - upgrade the delivery daemon`);
|
|
1135
1165
|
}
|
|
@@ -1185,7 +1215,7 @@ export class Manager {
|
|
|
1185
1215
|
}
|
|
1186
1216
|
catch (e) {
|
|
1187
1217
|
throw new Error(`could not read the delivery lease row to settle whether the delivery daemon is absent ` +
|
|
1188
|
-
`(${e
|
|
1218
|
+
`(${rejectionText(e)}) - absence is undetermined, nothing reminted`);
|
|
1189
1219
|
}
|
|
1190
1220
|
const holder = entry?.info.holder;
|
|
1191
1221
|
if (holder !== undefined && holder !== "") {
|
|
@@ -1210,7 +1240,7 @@ export class Manager {
|
|
|
1210
1240
|
this.daemonRenewalOwner = held;
|
|
1211
1241
|
}
|
|
1212
1242
|
catch (e) {
|
|
1213
|
-
console.error(`! could not refresh the daemon renewal lease: ${e
|
|
1243
|
+
console.error(`! could not refresh the daemon renewal lease: ${rejectionText(e)} - ownership is re-decided on the next pass`);
|
|
1214
1244
|
}
|
|
1215
1245
|
}
|
|
1216
1246
|
/** Decide whether THIS manager owns the daemon's credential renewal (#1634). Both conditions are
|
|
@@ -1296,7 +1326,7 @@ export class Manager {
|
|
|
1296
1326
|
return true;
|
|
1297
1327
|
}
|
|
1298
1328
|
catch (e) {
|
|
1299
|
-
console.error(`! manager ${label} re-dial attempt failed: ${e
|
|
1329
|
+
console.error(`! manager ${label} re-dial attempt failed: ${rejectionText(e)}`);
|
|
1300
1330
|
}
|
|
1301
1331
|
}
|
|
1302
1332
|
return false;
|
|
@@ -1349,7 +1379,7 @@ export class Manager {
|
|
|
1349
1379
|
: { ok: false, error: reply.error, detail: reply.data };
|
|
1350
1380
|
}
|
|
1351
1381
|
catch (e) {
|
|
1352
|
-
adoption = { ok: false, error: `no delivery-admin responder (${e
|
|
1382
|
+
adoption = { ok: false, error: `no delivery-admin responder (${rejectionText(e)}) - the daemon's 75% re-read backstop adopts the re-signed file` };
|
|
1353
1383
|
}
|
|
1354
1384
|
}
|
|
1355
1385
|
for (const r of results.filter((x) => !x.ok && !x.skipped))
|
|
@@ -1392,7 +1422,7 @@ export class Manager {
|
|
|
1392
1422
|
await this.renewManagedStaticCred(a);
|
|
1393
1423
|
}
|
|
1394
1424
|
catch (e) {
|
|
1395
|
-
console.error(`! managed cred renewal ${a.name}: ${e
|
|
1425
|
+
console.error(`! managed cred renewal ${a.name}: ${rejectionText(e)} - the agent dies loud at this cred's expiry unless it is reminted`);
|
|
1396
1426
|
}
|
|
1397
1427
|
}
|
|
1398
1428
|
}
|
|
@@ -1420,7 +1450,7 @@ export class Manager {
|
|
|
1420
1450
|
}
|
|
1421
1451
|
}
|
|
1422
1452
|
catch (e) {
|
|
1423
|
-
console.error(`! endpoint-serve renewal: ${e
|
|
1453
|
+
console.error(`! endpoint-serve renewal: ${rejectionText(e)} - the manager's service endpoint dies loud at this cred's expiry unless it is re-registered`);
|
|
1424
1454
|
}
|
|
1425
1455
|
}
|
|
1426
1456
|
// The manager is also the goal-writer's renewal owner — re-mint the SAME
|
|
@@ -1439,7 +1469,7 @@ export class Manager {
|
|
|
1439
1469
|
}
|
|
1440
1470
|
}
|
|
1441
1471
|
catch (e) {
|
|
1442
|
-
console.error(`! goal-writer renewal: ${e
|
|
1472
|
+
console.error(`! goal-writer renewal: ${rejectionText(e)} - spawn-as-action stops accepting at this cred's expiry unless the manager restarts`);
|
|
1443
1473
|
}
|
|
1444
1474
|
}
|
|
1445
1475
|
// P2 item 6: the manager is also the session-ledger's renewal owner — re-mint the SAME nkey
|
|
@@ -1461,12 +1491,12 @@ export class Manager {
|
|
|
1461
1491
|
}
|
|
1462
1492
|
}
|
|
1463
1493
|
catch (e) {
|
|
1464
|
-
console.error(`! session-ledger renewal: ${e
|
|
1494
|
+
console.error(`! session-ledger renewal: ${rejectionText(e)} - attach stops establishing sessions at this cred's expiry unless the manager restarts`);
|
|
1465
1495
|
}
|
|
1466
1496
|
}
|
|
1467
1497
|
}
|
|
1468
1498
|
catch (e) {
|
|
1469
|
-
console.error(`! credential renewal pass failed: ${e
|
|
1499
|
+
console.error(`! credential renewal pass failed: ${rejectionText(e)}`);
|
|
1470
1500
|
}
|
|
1471
1501
|
finally {
|
|
1472
1502
|
release();
|
|
@@ -1484,7 +1514,7 @@ export class Manager {
|
|
|
1484
1514
|
this.remoteExecutorCreds = await this.remoteAuthority.renewExecutor();
|
|
1485
1515
|
}
|
|
1486
1516
|
catch (e) {
|
|
1487
|
-
console.error(`! remote manager executor renewal: ${e
|
|
1517
|
+
console.error(`! remote manager executor renewal: ${rejectionText(e)} - registration maintenance and clean deregistration remain unavailable until renewal succeeds`);
|
|
1488
1518
|
if (force)
|
|
1489
1519
|
throw e;
|
|
1490
1520
|
}
|
|
@@ -1555,7 +1585,7 @@ export class Manager {
|
|
|
1555
1585
|
// endpoint's own reconnect loop retries with the adopted credential, not unadopted debt.
|
|
1556
1586
|
this.remoteRenewalDebt = undefined;
|
|
1557
1587
|
await Promise.all([
|
|
1558
|
-
this.ep.reconnect().catch((e) => console.error(`! remote manager supervisor reconnect after renewal: ${e
|
|
1588
|
+
this.ep.reconnect().catch((e) => console.error(`! remote manager supervisor reconnect after renewal: ${rejectionText(e)}`)),
|
|
1559
1589
|
this.pushRenewedCreds(this.serviceServe.nc),
|
|
1560
1590
|
...(this.goalWriter ? [this.pushRenewedCreds(this.goalWriter.nc)] : []),
|
|
1561
1591
|
...(this.sessionLedgerConn ? [this.pushRenewedCreds(this.sessionLedgerConn.nc)] : []),
|
|
@@ -1570,8 +1600,8 @@ export class Manager {
|
|
|
1570
1600
|
return [];
|
|
1571
1601
|
} })
|
|
1572
1602
|
: [];
|
|
1573
|
-
this.remoteRenewalDebt = { at: Date.now(), processEpoch, reason: e
|
|
1574
|
-
console.error(`! remote manager all-duty renewal: ${e
|
|
1603
|
+
this.remoteRenewalDebt = { at: Date.now(), processEpoch, reason: rejectionText(e), unadoptedSubjects };
|
|
1604
|
+
console.error(`! remote manager all-duty renewal: ${rejectionText(e)} - no unsigned or local replacement is available`);
|
|
1575
1605
|
if (force)
|
|
1576
1606
|
throw e;
|
|
1577
1607
|
}
|
|
@@ -1643,7 +1673,7 @@ export class Manager {
|
|
|
1643
1673
|
trackDeprovision(a, context = "") {
|
|
1644
1674
|
this.lifecycleInFlight++;
|
|
1645
1675
|
void this.deprovision(a)
|
|
1646
|
-
.catch((e) => console.error(`deprovision${context ? ` ${context}` : ""} ${a.name} (${a.id}): ${e
|
|
1676
|
+
.catch((e) => console.error(`deprovision${context ? ` ${context}` : ""} ${a.name} (${a.id}): ${rejectionText(e)}`))
|
|
1647
1677
|
.finally(() => this.releaseLifecycle());
|
|
1648
1678
|
}
|
|
1649
1679
|
async awaitLifecycleDrain() {
|
|
@@ -1748,7 +1778,7 @@ export class Manager {
|
|
|
1748
1778
|
parseResumeControlArgs({ attemptId, inventory });
|
|
1749
1779
|
}
|
|
1750
1780
|
catch (e) {
|
|
1751
|
-
failures.push({ name: "<inventory>", id: attemptId, error: `prepared inventory would be rejected at resume: ${e
|
|
1781
|
+
failures.push({ name: "<inventory>", id: attemptId, error: `prepared inventory would be rejected at resume: ${rejectionText(e)}` });
|
|
1752
1782
|
}
|
|
1753
1783
|
this.preservationInventory = inventory;
|
|
1754
1784
|
this.preservationFailures = failures;
|
|
@@ -1833,7 +1863,7 @@ export class Manager {
|
|
|
1833
1863
|
a.handle.stop({ graceful: false });
|
|
1834
1864
|
}
|
|
1835
1865
|
catch (e) {
|
|
1836
|
-
failures.push({ name: a.name, id: a.id, error: `stop failed: ${e
|
|
1866
|
+
failures.push({ name: a.name, id: a.id, error: `stop failed: ${rejectionText(e)}` });
|
|
1837
1867
|
return;
|
|
1838
1868
|
}
|
|
1839
1869
|
try {
|
|
@@ -1842,7 +1872,7 @@ export class Manager {
|
|
|
1842
1872
|
this.agents.delete(a.name);
|
|
1843
1873
|
}
|
|
1844
1874
|
catch (e) {
|
|
1845
|
-
failures.push({ name: a.name, id: a.id, error: e
|
|
1875
|
+
failures.push({ name: a.name, id: a.id, error: rejectionText(e) });
|
|
1846
1876
|
}
|
|
1847
1877
|
}));
|
|
1848
1878
|
if (failures.length === 0)
|
|
@@ -1887,7 +1917,7 @@ export class Manager {
|
|
|
1887
1917
|
return `retained reference is not a regular non-symlink file: ${path}`;
|
|
1888
1918
|
}
|
|
1889
1919
|
catch (e) {
|
|
1890
|
-
return `retained reference unavailable: ${path} (${e
|
|
1920
|
+
return `retained reference unavailable: ${path} (${rejectionText(e)})`;
|
|
1891
1921
|
}
|
|
1892
1922
|
}
|
|
1893
1923
|
if (process.platform !== "win32") {
|
|
@@ -1916,7 +1946,7 @@ export class Manager {
|
|
|
1916
1946
|
}
|
|
1917
1947
|
}
|
|
1918
1948
|
catch (e) {
|
|
1919
|
-
return `retained reference cannot be hashed: ${e
|
|
1949
|
+
return `retained reference cannot be hashed: ${rejectionText(e)}`;
|
|
1920
1950
|
}
|
|
1921
1951
|
return undefined;
|
|
1922
1952
|
}
|
|
@@ -2031,11 +2061,11 @@ export class Manager {
|
|
|
2031
2061
|
await this.awaitHandleExit(a.handle);
|
|
2032
2062
|
}
|
|
2033
2063
|
catch (e) {
|
|
2034
|
-
failures.push(`${a.name}: ${e
|
|
2064
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2035
2065
|
}
|
|
2036
2066
|
}));
|
|
2037
2067
|
// Deprovision EVERY snapshot entry regardless of whether its stop failed (allSettled + a loud log).
|
|
2038
|
-
await Promise.allSettled(managed.filter((a) => !a.suppressCleanup).map((a) => this.deprovision({ ...a, ...(a.handedOff ? { delegatedHandle: a.handle } : {}) }).catch((e) => console.error(`deprovision ${a.name} (${a.id}) on shutdown: ${e
|
|
2068
|
+
await Promise.allSettled(managed.filter((a) => !a.suppressCleanup).map((a) => this.deprovision({ ...a, ...(a.handedOff ? { delegatedHandle: a.handle } : {}) }).catch((e) => console.error(`deprovision ${a.name} (${a.id}) on shutdown: ${rejectionText(e)}`))));
|
|
2039
2069
|
if (failures.length)
|
|
2040
2070
|
throw new Error(`manager shutdown could not prove every seat exited: ${failures.join("; ")}`);
|
|
2041
2071
|
}
|
|
@@ -2052,7 +2082,7 @@ export class Manager {
|
|
|
2052
2082
|
this.agents.delete(a.name);
|
|
2053
2083
|
}
|
|
2054
2084
|
catch (e) {
|
|
2055
|
-
failures.push(`${a.name}: ${e
|
|
2085
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2056
2086
|
}
|
|
2057
2087
|
}
|
|
2058
2088
|
return failures;
|
|
@@ -2071,7 +2101,7 @@ export class Manager {
|
|
|
2071
2101
|
a.handle.stop({ graceful: false });
|
|
2072
2102
|
}
|
|
2073
2103
|
catch (e) {
|
|
2074
|
-
failures.push(`${a.name}: stop failed: ${e
|
|
2104
|
+
failures.push(`${a.name}: stop failed: ${rejectionText(e)}`);
|
|
2075
2105
|
}
|
|
2076
2106
|
try {
|
|
2077
2107
|
await this.awaitHandleExit(a.handle);
|
|
@@ -2079,7 +2109,7 @@ export class Manager {
|
|
|
2079
2109
|
this.agents.delete(a.name);
|
|
2080
2110
|
}
|
|
2081
2111
|
catch (e) {
|
|
2082
|
-
failures.push(`${a.name}: ${e
|
|
2112
|
+
failures.push(`${a.name}: ${rejectionText(e)}`);
|
|
2083
2113
|
}
|
|
2084
2114
|
}));
|
|
2085
2115
|
if (failures.length)
|
|
@@ -2144,7 +2174,7 @@ export class Manager {
|
|
|
2144
2174
|
}
|
|
2145
2175
|
}
|
|
2146
2176
|
catch (e) {
|
|
2147
|
-
seatFailure = e;
|
|
2177
|
+
seatFailure = rejectionText(e);
|
|
2148
2178
|
}
|
|
2149
2179
|
// Every step below runs even when an earlier one fails, so a failed stop still closes this
|
|
2150
2180
|
// process's connections and listener (#2290). Failures are collected and thrown at the end.
|
|
@@ -2154,12 +2184,12 @@ export class Manager {
|
|
|
2154
2184
|
await run();
|
|
2155
2185
|
}
|
|
2156
2186
|
catch (e) {
|
|
2157
|
-
failures.push(`${name}: ${e
|
|
2187
|
+
failures.push(`${name}: ${rejectionText(e)}`);
|
|
2158
2188
|
}
|
|
2159
2189
|
};
|
|
2160
2190
|
// A seat that may still be alive keeps this instance's leases and registration (see
|
|
2161
2191
|
// teardownManagedAgents): they lapse on their TTL instead of being handed to a successor.
|
|
2162
|
-
if (
|
|
2192
|
+
if (seatFailure === undefined) {
|
|
2163
2193
|
await step("release manager lease", () => this.releaseOwnManagerLease());
|
|
2164
2194
|
// #1634: hand the renewal lease back on a clean stop so a sibling picks it up on its next pass
|
|
2165
2195
|
// rather than waiting out the bucket TTL. A non-owner holds no revision and this is a no-op.
|
|
@@ -2175,15 +2205,15 @@ export class Manager {
|
|
|
2175
2205
|
// released run's status write is the last thing this incarnation says about it.
|
|
2176
2206
|
await step("stop run hosting", () => this.runHosting?.stop());
|
|
2177
2207
|
this.runHosting = undefined;
|
|
2178
|
-
if (registrationRevision !== undefined &&
|
|
2208
|
+
if (registrationRevision !== undefined && seatFailure === undefined)
|
|
2179
2209
|
await step("deregister service", () => this.deregisterServiceOnStop(registrationRevision));
|
|
2180
2210
|
await step("stop goal writer", () => this.stopGoalWriter());
|
|
2181
2211
|
await step("stop session plane", () => this.stopSessionPlane());
|
|
2182
2212
|
await step("stop endpoint", () => this.ep.stop());
|
|
2183
2213
|
await step("stop attach endpoint", () => this.attach.stop());
|
|
2184
2214
|
const also = failures.length ? `; teardown also failed: ${failures.join("; ")}` : "";
|
|
2185
|
-
if (seatFailure)
|
|
2186
|
-
throw new Error(`${seatFailure
|
|
2215
|
+
if (seatFailure !== undefined)
|
|
2216
|
+
throw new Error(`${seatFailure}${also}`);
|
|
2187
2217
|
if (releaseFailures.length)
|
|
2188
2218
|
throw new Error(`manager shutdown could not release every detachable seat: ${releaseFailures.join("; ")}${also}`);
|
|
2189
2219
|
if (failures.length)
|
|
@@ -2258,7 +2288,7 @@ export class Manager {
|
|
|
2258
2288
|
// `absent` is silent: there was nothing registered to remove, which is not news at shutdown.
|
|
2259
2289
|
}
|
|
2260
2290
|
catch (e) {
|
|
2261
|
-
console.error(`! could not deregister manager instance ${iid}: ${e
|
|
2291
|
+
console.error(`! could not deregister manager instance ${iid}: ${rejectionText(e)}\n` +
|
|
2262
2292
|
` Its registration now outlives this process and will be frozen into every class scatter in space "${this.space}", each paying the full deadline.\n` +
|
|
2263
2293
|
` NEXT: remove it with \`cotal deregister-instance --instance ${iid}\` once this process is gone.`);
|
|
2264
2294
|
}
|
|
@@ -2333,7 +2363,7 @@ export class Manager {
|
|
|
2333
2363
|
return;
|
|
2334
2364
|
}
|
|
2335
2365
|
catch (renewError) {
|
|
2336
|
-
const why = renewError
|
|
2366
|
+
const why = rejectionText(renewError);
|
|
2337
2367
|
const verdict = await this.reconcileLease();
|
|
2338
2368
|
switch (verdict.kind) {
|
|
2339
2369
|
case "held":
|
|
@@ -2358,7 +2388,7 @@ export class Manager {
|
|
|
2358
2388
|
}
|
|
2359
2389
|
catch (e) {
|
|
2360
2390
|
this.leaseState = before;
|
|
2361
|
-
this.noteLease("gone", `found its liveness lease key gone (renew: ${why}) and could not re-acquire it yet (${e
|
|
2391
|
+
this.noteLease("gone", `found its liveness lease key gone (renew: ${why}) and could not re-acquire it yet (${rejectionText(e)}); serving, retrying`);
|
|
2362
2392
|
}
|
|
2363
2393
|
return;
|
|
2364
2394
|
}
|
|
@@ -2397,7 +2427,7 @@ export class Manager {
|
|
|
2397
2427
|
current = await this.ep.readOwnManagerLease(this.managerInstanceId);
|
|
2398
2428
|
}
|
|
2399
2429
|
catch (e) {
|
|
2400
|
-
return { kind: "unknown", why: e
|
|
2430
|
+
return { kind: "unknown", why: rejectionText(e) };
|
|
2401
2431
|
}
|
|
2402
2432
|
if (current === undefined)
|
|
2403
2433
|
return { kind: "gone" };
|
|
@@ -2414,7 +2444,7 @@ export class Manager {
|
|
|
2414
2444
|
args = parseResumeFinalizeArgs(rawArgs);
|
|
2415
2445
|
}
|
|
2416
2446
|
catch (e) {
|
|
2417
|
-
return { ok: false, error: e
|
|
2447
|
+
return { ok: false, error: rejectionText(e) };
|
|
2418
2448
|
}
|
|
2419
2449
|
if (!this.resumeAttemptId || this.resumeAttemptId !== args.attemptId)
|
|
2420
2450
|
return { ok: false, error: `manager expects resume attempt ${this.resumeAttemptId ?? "<none>"}, not ${args.attemptId}` };
|
|
@@ -2432,7 +2462,7 @@ export class Manager {
|
|
|
2432
2462
|
inactive = this.resumeLivenessErrors(inventory, this.ep.getRoster());
|
|
2433
2463
|
}
|
|
2434
2464
|
catch (e) {
|
|
2435
|
-
return { ok: false, error: `resume attempt ${args.attemptId} cannot verify live principals at finalize: ${e
|
|
2465
|
+
return { ok: false, error: `resume attempt ${args.attemptId} cannot verify live principals at finalize: ${rejectionText(e)}` };
|
|
2436
2466
|
}
|
|
2437
2467
|
if (inactive.length)
|
|
2438
2468
|
return { ok: false, error: `resume attempt ${args.attemptId} is not live at finalize: ${inactive.join("; ")}` };
|
|
@@ -2451,7 +2481,7 @@ export class Manager {
|
|
|
2451
2481
|
// retiredPrincipals, so a copied JWT is refused). Best-effort + loud: a sweep failure must
|
|
2452
2482
|
// not fail the finalize (the next non-resume boot re-drives it), but it is never swallowed.
|
|
2453
2483
|
if (this.auth && !this.userMode)
|
|
2454
|
-
await this.reconcileStaticLifecycles(true).catch((e) => console.error(`! post-resume static reconcile: ${e
|
|
2484
|
+
await this.reconcileStaticLifecycles(true).catch((e) => console.error(`! post-resume static reconcile: ${rejectionText(e)} - no per-alias retry could be planned; a later manager start re-reads unfinished durable terminals`));
|
|
2455
2485
|
this.resumeFinalized = true;
|
|
2456
2486
|
this.resumeRequired = false;
|
|
2457
2487
|
return { ok: true, data: { attemptId: args.attemptId, state: "active" } };
|
|
@@ -2464,7 +2494,7 @@ export class Manager {
|
|
|
2464
2494
|
attemptId = parseResumeCommitArgs(rawArgs).attemptId;
|
|
2465
2495
|
}
|
|
2466
2496
|
catch (e) {
|
|
2467
|
-
return { ok: false, error: e
|
|
2497
|
+
return { ok: false, error: rejectionText(e) };
|
|
2468
2498
|
}
|
|
2469
2499
|
if (!this.resumeAttemptId || this.resumeAttemptId !== attemptId)
|
|
2470
2500
|
return { ok: false, error: `manager expects resume attempt ${this.resumeAttemptId ?? "<none>"}, not ${attemptId}` };
|
|
@@ -2521,7 +2551,7 @@ export class Manager {
|
|
|
2521
2551
|
: { ok: false, data, error: result.error ?? "retained-agent resume failed" };
|
|
2522
2552
|
}
|
|
2523
2553
|
catch (e) {
|
|
2524
|
-
return { ok: false, error: e
|
|
2554
|
+
return { ok: false, error: rejectionText(e) };
|
|
2525
2555
|
}
|
|
2526
2556
|
}
|
|
2527
2557
|
}
|
|
@@ -2548,7 +2578,7 @@ export class Manager {
|
|
|
2548
2578
|
};
|
|
2549
2579
|
}
|
|
2550
2580
|
catch (e) {
|
|
2551
|
-
return { ok: false, error: e
|
|
2581
|
+
return { ok: false, error: rejectionText(e) };
|
|
2552
2582
|
}
|
|
2553
2583
|
}
|
|
2554
2584
|
/** The ONE shared control-admission chokepoint (P2 item 1, checklist 3/8) BOTH dispatch doors
|
|
@@ -2779,7 +2809,7 @@ export class Manager {
|
|
|
2779
2809
|
observed = await observeStaticSlot(recordsKv, DEV_OWNER, name, this.managerInstanceId);
|
|
2780
2810
|
}
|
|
2781
2811
|
catch (error) {
|
|
2782
|
-
throw new EpEnvelopeError("unavailable", `the durable static slot state for "${name}" could not be read: ${error
|
|
2812
|
+
throw new EpEnvelopeError("unavailable", `the durable static slot state for "${name}" could not be read: ${rejectionText(error)}`, [
|
|
2783
2813
|
{ kind: STATIC_SLOT_READ_FAILED_DETAIL, name, record: error instanceof StaticSlotReadError ? error.record : "slot-or-head", operation: "read" },
|
|
2784
2814
|
]);
|
|
2785
2815
|
}
|
|
@@ -2816,7 +2846,7 @@ export class Manager {
|
|
|
2816
2846
|
observed = await listStaticSlotObservations(recordsKv, DEV_OWNER, this.managerInstanceId);
|
|
2817
2847
|
}
|
|
2818
2848
|
catch (error) {
|
|
2819
|
-
throw new EpEnvelopeError("unavailable", `the durable static slot state could not be scanned: ${error
|
|
2849
|
+
throw new EpEnvelopeError("unavailable", `the durable static slot state could not be scanned: ${rejectionText(error)}`, [
|
|
2820
2850
|
{ kind: STATIC_SLOT_READ_FAILED_DETAIL, name: "*", record: error instanceof StaticSlotReadError ? error.record : "slot-or-head", operation: "scan" },
|
|
2821
2851
|
]);
|
|
2822
2852
|
}
|
|
@@ -2954,7 +2984,7 @@ export class Manager {
|
|
|
2954
2984
|
return undefined;
|
|
2955
2985
|
}
|
|
2956
2986
|
catch (e) {
|
|
2957
|
-
return `${entry.name}: ${e
|
|
2987
|
+
return `${entry.name}: ${rejectionText(e)}`;
|
|
2958
2988
|
}
|
|
2959
2989
|
}));
|
|
2960
2990
|
const drift = authority.filter((error) => error !== undefined);
|
|
@@ -2965,7 +2995,7 @@ export class Manager {
|
|
|
2965
2995
|
inactive = this.resumeLivenessErrors(inventory, this.ep.getRoster());
|
|
2966
2996
|
}
|
|
2967
2997
|
catch (e) {
|
|
2968
|
-
return { ok: false, error: `resume attempt ${attemptId} cannot verify live principals: ${e
|
|
2998
|
+
return { ok: false, error: `resume attempt ${attemptId} cannot verify live principals: ${rejectionText(e)}` };
|
|
2969
2999
|
}
|
|
2970
3000
|
if (inactive.length)
|
|
2971
3001
|
return { ok: false, error: `resume attempt ${attemptId} is not live at commit: ${inactive.join("; ")}` };
|
|
@@ -3058,7 +3088,7 @@ export class Manager {
|
|
|
3058
3088
|
}
|
|
3059
3089
|
}
|
|
3060
3090
|
catch (e) {
|
|
3061
|
-
inactive.push(`${entry.name} runtime status failed: ${e
|
|
3091
|
+
inactive.push(`${entry.name} runtime status failed: ${rejectionText(e)}`);
|
|
3062
3092
|
continue;
|
|
3063
3093
|
}
|
|
3064
3094
|
if (!roster.some((presence) => presence.card.id === expectedPrincipal && presence.card.name === entry.name && presence.status !== "offline" &&
|
|
@@ -3114,7 +3144,7 @@ export class Manager {
|
|
|
3114
3144
|
a.handle.stop({ graceful });
|
|
3115
3145
|
}
|
|
3116
3146
|
catch (e) {
|
|
3117
|
-
console.error(`stop ${a.name} (${a.id}): ${e
|
|
3147
|
+
console.error(`stop ${a.name} (${a.id}): ${rejectionText(e)}`);
|
|
3118
3148
|
}
|
|
3119
3149
|
}
|
|
3120
3150
|
/** Keep an accepted stop inside the lifecycle drain until the runtime proves the child is gone,
|
|
@@ -3157,7 +3187,7 @@ export class Manager {
|
|
|
3157
3187
|
id: a.id,
|
|
3158
3188
|
handle: a.handle,
|
|
3159
3189
|
authoritative: true,
|
|
3160
|
-
error: `accepted stop could not prove exit: ${e
|
|
3190
|
+
error: `accepted stop could not prove exit: ${rejectionText(e)}`,
|
|
3161
3191
|
});
|
|
3162
3192
|
})
|
|
3163
3193
|
.finally(() => this.releaseLifecycle());
|
|
@@ -3197,7 +3227,7 @@ export class Manager {
|
|
|
3197
3227
|
provider = resolveAuthProvider();
|
|
3198
3228
|
}
|
|
3199
3229
|
catch (e) {
|
|
3200
|
-
return { error: e
|
|
3230
|
+
return { error: rejectionText(e) };
|
|
3201
3231
|
}
|
|
3202
3232
|
const dir = userAuthStateDir(this.workspaceRoot, this.space);
|
|
3203
3233
|
// The agent's capability scope rides its ledger row (act.scope in every bearer) — same
|
|
@@ -3305,7 +3335,7 @@ export class Manager {
|
|
|
3305
3335
|
provider = resolveAuthProvider();
|
|
3306
3336
|
}
|
|
3307
3337
|
catch (e) {
|
|
3308
|
-
return { error: e
|
|
3338
|
+
return { error: rejectionText(e) };
|
|
3309
3339
|
}
|
|
3310
3340
|
const secrets = this.secrets;
|
|
3311
3341
|
// The token the agent will present to `POST /exchange` for the rest of its life. Generated
|
|
@@ -3463,7 +3493,7 @@ export class Manager {
|
|
|
3463
3493
|
catch (e) {
|
|
3464
3494
|
// A runtime that throws while being asked has told us something real; it must not take the
|
|
3465
3495
|
// log line (or the free path it sits on) down with it.
|
|
3466
|
-
detail = `exit detail unreadable from runtime "${a.handle.kind}": ${e
|
|
3496
|
+
detail = `exit detail unreadable from runtime "${a.handle.kind}": ${rejectionText(e)}`;
|
|
3467
3497
|
}
|
|
3468
3498
|
console.error(`seat reaped: ${a.name} (${a.id}, uid ${a.lifecycleUid}${a.handle.pid !== undefined ? `, pid ${a.handle.pid}` : ""}) - ${causeText}; ${detail}`);
|
|
3469
3499
|
}
|
|
@@ -3683,8 +3713,8 @@ export class Manager {
|
|
|
3683
3713
|
catch (e) {
|
|
3684
3714
|
const h = this.retiring.get(a.name);
|
|
3685
3715
|
if (h && h.lifecycleUid === a.lifecycleUid)
|
|
3686
|
-
h.lastError = `the agent's standing mint authority could not be revoked (${e
|
|
3687
|
-
console.error(`revoke agent grant ${a.name}: ${e
|
|
3716
|
+
h.lastError = `the agent's standing mint authority could not be revoked (${rejectionText(e)}); the name stays held so a copied actor token cannot mint fresh credentials. NEXT: a same-name spawn re-drives the full teardown (including the revoke), or recover the auth state.`;
|
|
3717
|
+
console.error(`revoke agent grant ${a.name}: ${rejectionText(e)}`);
|
|
3688
3718
|
}
|
|
3689
3719
|
}
|
|
3690
3720
|
const shredFailure = unshredded.length ? `could not shred "${a.name}": ${unshredded.join("; ")}` : undefined;
|
|
@@ -3697,7 +3727,7 @@ export class Manager {
|
|
|
3697
3727
|
catch (e) {
|
|
3698
3728
|
const h = this.retiring.get(a.name);
|
|
3699
3729
|
if (h && h.lifecycleUid === a.lifecycleUid) {
|
|
3700
|
-
h.lastError = e
|
|
3730
|
+
h.lastError = rejectionText(e);
|
|
3701
3731
|
if (e instanceof DeprovisionError)
|
|
3702
3732
|
h.lastResources = e.accounting;
|
|
3703
3733
|
}
|
|
@@ -3843,7 +3873,7 @@ export class Manager {
|
|
|
3843
3873
|
}
|
|
3844
3874
|
}
|
|
3845
3875
|
catch (e) {
|
|
3846
|
-
const copy = uncertain(e
|
|
3876
|
+
const copy = uncertain(rejectionText(e));
|
|
3847
3877
|
if (held)
|
|
3848
3878
|
held.lastError = copy;
|
|
3849
3879
|
console.error(`despawn ${a.name}: ${copy}`);
|
|
@@ -3937,7 +3967,7 @@ export class Manager {
|
|
|
3937
3967
|
return { complete: true, channels: data.channels };
|
|
3938
3968
|
}
|
|
3939
3969
|
catch (e) {
|
|
3940
|
-
return { complete: false, channels: [], reason: e
|
|
3970
|
+
return { complete: false, channels: [], reason: rejectionText(e) };
|
|
3941
3971
|
}
|
|
3942
3972
|
}
|
|
3943
3973
|
/** Reap a parent's children on its exit (P4b). Every descendant remains managed until the runtime's
|
|
@@ -3959,7 +3989,7 @@ export class Manager {
|
|
|
3959
3989
|
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
3960
3990
|
}
|
|
3961
3991
|
catch (error) {
|
|
3962
|
-
throw new Error(`cannot read connector session state ${path}: ${error
|
|
3992
|
+
throw new Error(`cannot read connector session state ${path}: ${rejectionText(error)}`);
|
|
3963
3993
|
}
|
|
3964
3994
|
const state = parsed;
|
|
3965
3995
|
if (state.version !== 1 || typeof state.sessionId !== "string" || !state.sessionId.trim() || state.sessionId.length > 4096 ||
|
|
@@ -3986,7 +4016,7 @@ export class Manager {
|
|
|
3986
4016
|
}
|
|
3987
4017
|
catch (error) {
|
|
3988
4018
|
throw new Error(`retained ${connector.name} agent ${entry.name} has no sessionId in its older inventory and no usable upgrade state at ${path} ` +
|
|
3989
|
-
`(${error
|
|
4019
|
+
`(${rejectionText(error)}). Reload the live Pi seat before the preservation cut; refusing to resume fresh and lose its context.`);
|
|
3990
4020
|
}
|
|
3991
4021
|
}
|
|
3992
4022
|
/** A resumed seat's fork provenance (#1500). The seat forks after it launches, so this reads the
|
|
@@ -4071,7 +4101,7 @@ export class Manager {
|
|
|
4071
4101
|
this.recordContinuity(a, this.readManagedSession(a));
|
|
4072
4102
|
}
|
|
4073
4103
|
catch (error) {
|
|
4074
|
-
console.error(`! ${a.name}: continuity: exact assignment not updated at ${boundary}: ${error
|
|
4104
|
+
console.error(`! ${a.name}: continuity: exact assignment not updated at ${boundary}: ${rejectionText(error)}`);
|
|
4075
4105
|
}
|
|
4076
4106
|
}
|
|
4077
4107
|
async awaitManagedSessionState(a) {
|
|
@@ -4084,7 +4114,7 @@ export class Manager {
|
|
|
4084
4114
|
return this.readManagedSessionState(a);
|
|
4085
4115
|
}
|
|
4086
4116
|
catch (error) {
|
|
4087
|
-
last = error
|
|
4117
|
+
last = rejectionText(error);
|
|
4088
4118
|
}
|
|
4089
4119
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4090
4120
|
}
|
|
@@ -4117,7 +4147,7 @@ export class Manager {
|
|
|
4117
4147
|
return;
|
|
4118
4148
|
}
|
|
4119
4149
|
catch (error) {
|
|
4120
|
-
last = error
|
|
4150
|
+
last = rejectionText(error);
|
|
4121
4151
|
}
|
|
4122
4152
|
}
|
|
4123
4153
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -4222,7 +4252,7 @@ export class Manager {
|
|
|
4222
4252
|
tail = await this.tail((replacement ?? a.handle).attach());
|
|
4223
4253
|
}
|
|
4224
4254
|
catch { /* runtime has no readable tail */ }
|
|
4225
|
-
console.error(`! ${a.name}: ${supervised ? "supervised restart" : "Pi session recovery"} failed: ${error
|
|
4255
|
+
console.error(`! ${a.name}: ${supervised ? "supervised restart" : "Pi session recovery"} failed: ${rejectionText(error)}${tail ? ` - last output: ${tail}` : ""} - retiring the managed seat`);
|
|
4226
4256
|
// The replacement may be alive but unable to prove readiness. Stop it BEFORE
|
|
4227
4257
|
// retiring credentials/durables; otherwise an untracked process survives under torn auth.
|
|
4228
4258
|
try {
|
|
@@ -4262,7 +4292,7 @@ export class Manager {
|
|
|
4262
4292
|
}
|
|
4263
4293
|
}
|
|
4264
4294
|
catch (error) {
|
|
4265
|
-
console.error(`! ${a.name}: cannot classify Pi process exit for recovery: ${error
|
|
4295
|
+
console.error(`! ${a.name}: cannot classify Pi process exit for recovery: ${rejectionText(error)} - retiring the seat`);
|
|
4266
4296
|
}
|
|
4267
4297
|
}
|
|
4268
4298
|
this.freeSlot(a, true, "process-exit");
|
|
@@ -4389,7 +4419,7 @@ export class Manager {
|
|
|
4389
4419
|
shareTools = strList(args.shareTools, "shareTools");
|
|
4390
4420
|
}
|
|
4391
4421
|
catch (e) {
|
|
4392
|
-
return Promise.resolve({ ok: false, error: e
|
|
4422
|
+
return Promise.resolve({ ok: false, error: rejectionText(e) });
|
|
4393
4423
|
}
|
|
4394
4424
|
// #373: the event-plane admission gate. `startAgent` resolves `eventsRequired || opts.events
|
|
4395
4425
|
// !== false`, so omission ARMS the plane — a gate on the explicit bit alone is bypassed by
|
|
@@ -4450,14 +4480,14 @@ export class Manager {
|
|
|
4450
4480
|
cwd = realpathSync(resolved);
|
|
4451
4481
|
}
|
|
4452
4482
|
catch (error) {
|
|
4453
|
-
return { refusal: `path cannot be resolved: ${error
|
|
4483
|
+
return { refusal: `path cannot be resolved: ${rejectionText(error)}` };
|
|
4454
4484
|
}
|
|
4455
4485
|
try {
|
|
4456
4486
|
if (!statSync(cwd).isDirectory())
|
|
4457
4487
|
return { refusal: "path is not a directory" };
|
|
4458
4488
|
}
|
|
4459
4489
|
catch (error) {
|
|
4460
|
-
return { refusal: error
|
|
4490
|
+
return { refusal: rejectionText(error) };
|
|
4461
4491
|
}
|
|
4462
4492
|
return { cwd, host: hostname() };
|
|
4463
4493
|
}
|
|
@@ -4505,7 +4535,7 @@ export class Manager {
|
|
|
4505
4535
|
declared = loadExtensionsManifest().extensions.flatMap((ext) => extensionConnectors(ext));
|
|
4506
4536
|
}
|
|
4507
4537
|
catch (error) {
|
|
4508
|
-
const reason = error
|
|
4538
|
+
const reason = rejectionText(error);
|
|
4509
4539
|
console.error(`! manager boot: connector inventory unavailable - ${reason}`);
|
|
4510
4540
|
this.connectorStatuses = [{ agent: "(inventory)", state: "unavailable", binaries: {}, reason }];
|
|
4511
4541
|
console.error("! manager boot: no connector available - spawn and launch stay on this instance rail only so a sibling that can launch them can take the class queue");
|
|
@@ -4589,7 +4619,7 @@ export class Manager {
|
|
|
4589
4619
|
return { agent: connector.name, supported: true, ...catalog };
|
|
4590
4620
|
}
|
|
4591
4621
|
catch (e) {
|
|
4592
|
-
return { agent: connector.name, supported: true, models: [], error: e
|
|
4622
|
+
return { agent: connector.name, supported: true, models: [], error: rejectionText(e) };
|
|
4593
4623
|
}
|
|
4594
4624
|
};
|
|
4595
4625
|
if (requested) {
|
|
@@ -4598,7 +4628,7 @@ export class Manager {
|
|
|
4598
4628
|
connector = await this.resolveConnector(requested);
|
|
4599
4629
|
}
|
|
4600
4630
|
catch (e) {
|
|
4601
|
-
return { ok: false, error: e
|
|
4631
|
+
return { ok: false, error: rejectionText(e) };
|
|
4602
4632
|
}
|
|
4603
4633
|
const result = await one(connector);
|
|
4604
4634
|
return result.error ? { ok: false, error: result.error } : { ok: true, data: result };
|
|
@@ -4612,7 +4642,7 @@ export class Manager {
|
|
|
4612
4642
|
connector = await this.resolveConnector(name);
|
|
4613
4643
|
}
|
|
4614
4644
|
catch (e) {
|
|
4615
|
-
return { agent: name, supported: false, models: [], error: e
|
|
4645
|
+
return { agent: name, supported: false, models: [], error: rejectionText(e) };
|
|
4616
4646
|
}
|
|
4617
4647
|
return one(connector);
|
|
4618
4648
|
}));
|
|
@@ -4674,7 +4704,7 @@ export class Manager {
|
|
|
4674
4704
|
persistLaunchSpec(this.workspaceRoot, spec);
|
|
4675
4705
|
}
|
|
4676
4706
|
catch (e) {
|
|
4677
|
-
return { ok: false, error: e
|
|
4707
|
+
return { ok: false, error: rejectionText(e) };
|
|
4678
4708
|
}
|
|
4679
4709
|
}
|
|
4680
4710
|
else {
|
|
@@ -4682,7 +4712,7 @@ export class Manager {
|
|
|
4682
4712
|
spec = launchSpecForRun(this.workspaceRoot, runId);
|
|
4683
4713
|
}
|
|
4684
4714
|
catch (e) {
|
|
4685
|
-
return { ok: false, error: e
|
|
4715
|
+
return { ok: false, error: rejectionText(e) };
|
|
4686
4716
|
}
|
|
4687
4717
|
}
|
|
4688
4718
|
const la = spec.agents.find((a) => a.name === name);
|
|
@@ -4705,7 +4735,7 @@ export class Manager {
|
|
|
4705
4735
|
configPath = materializePersona(this.workspaceRoot, runId, la);
|
|
4706
4736
|
}
|
|
4707
4737
|
catch (e) {
|
|
4708
|
-
return { ok: false, error: e
|
|
4738
|
+
return { ok: false, error: rejectionText(e) };
|
|
4709
4739
|
}
|
|
4710
4740
|
const reply = await this.startAgent({ ...launchAgentToStartOpts(la, configPath, spec.owner, runId), route }, caller, hooks);
|
|
4711
4741
|
if (reply.ok)
|
|
@@ -4789,7 +4819,7 @@ export class Manager {
|
|
|
4789
4819
|
def = loadAgentFile(configPath);
|
|
4790
4820
|
}
|
|
4791
4821
|
catch (e) {
|
|
4792
|
-
return { ok: false, error: e
|
|
4822
|
+
return { ok: false, error: rejectionText(e) };
|
|
4793
4823
|
}
|
|
4794
4824
|
}
|
|
4795
4825
|
const agent = resolveAgentType({ flag: opts.agent, pin: def?.agent, callerDefault: opts.defaultAgent });
|
|
@@ -4803,7 +4833,7 @@ export class Manager {
|
|
|
4803
4833
|
connector = await this.resolveConnector(agent);
|
|
4804
4834
|
}
|
|
4805
4835
|
catch (e) {
|
|
4806
|
-
return { ok: false, error: e
|
|
4836
|
+
return { ok: false, error: rejectionText(e) };
|
|
4807
4837
|
}
|
|
4808
4838
|
const readinessTimeoutMs = connector.readinessTimeoutMs ?? this.readinessTimeoutMs;
|
|
4809
4839
|
if (!Number.isSafeInteger(readinessTimeoutMs) || readinessTimeoutMs <= 0)
|
|
@@ -4842,7 +4872,7 @@ export class Manager {
|
|
|
4842
4872
|
carried = this.transcripts.peek(opts.resumeClaim, opts.resume);
|
|
4843
4873
|
}
|
|
4844
4874
|
catch (e) {
|
|
4845
|
-
return { ok: false, error: e
|
|
4875
|
+
return { ok: false, error: rejectionText(e) };
|
|
4846
4876
|
}
|
|
4847
4877
|
}
|
|
4848
4878
|
// A restart policy this host cannot honour is refused at accept, never accepted and ignored.
|
|
@@ -4865,7 +4895,7 @@ export class Manager {
|
|
|
4865
4895
|
this.delegatedMeshRecord();
|
|
4866
4896
|
}
|
|
4867
4897
|
catch (e) {
|
|
4868
|
-
return { ok: false, error: e
|
|
4898
|
+
return { ok: false, error: rejectionText(e) };
|
|
4869
4899
|
}
|
|
4870
4900
|
if (opts.resume)
|
|
4871
4901
|
return { ok: false, error: `${delegatedBy}, so it cannot resume a session held on this host (resume)` };
|
|
@@ -4954,7 +4984,7 @@ export class Manager {
|
|
|
4954
4984
|
allowSubscribe = resolveReadAcl(subscribe ?? [], allowSubscribe);
|
|
4955
4985
|
}
|
|
4956
4986
|
catch (e) {
|
|
4957
|
-
return { ok: false, error: opts.resolved ? `launch agent: ${e
|
|
4987
|
+
return { ok: false, error: opts.resolved ? `launch agent: ${rejectionText(e)}` : `persona ${configPath}: ${rejectionText(e)}` };
|
|
4958
4988
|
}
|
|
4959
4989
|
// Checked after every path has resolved its selectors: a direct `startAgent` call skips the
|
|
4960
4990
|
// `start` op's checks, and no connector may receive a blank one (#2862).
|
|
@@ -5005,7 +5035,7 @@ export class Manager {
|
|
|
5005
5035
|
});
|
|
5006
5036
|
}
|
|
5007
5037
|
catch (e) {
|
|
5008
|
-
return { ok: false, error: e
|
|
5038
|
+
return { ok: false, error: rejectionText(e) };
|
|
5009
5039
|
}
|
|
5010
5040
|
if (policyRefusal)
|
|
5011
5041
|
return { ok: false, error: policyRefusal };
|
|
@@ -5036,7 +5066,7 @@ export class Manager {
|
|
|
5036
5066
|
reopenSession = readContinuityAssignment(this.workspaceRoot, { space: this.space, name: identityName, connector: agent, cwd: resolvedCwd ?? this.workspaceRoot });
|
|
5037
5067
|
}
|
|
5038
5068
|
catch (e) {
|
|
5039
|
-
return { ok: false, error: e
|
|
5069
|
+
return { ok: false, error: rejectionText(e) };
|
|
5040
5070
|
}
|
|
5041
5071
|
}
|
|
5042
5072
|
// The child takes launch options as `--opt k=v`, so only string values can cross to it.
|
|
@@ -5529,7 +5559,7 @@ export class Manager {
|
|
|
5529
5559
|
}
|
|
5530
5560
|
}
|
|
5531
5561
|
catch (error) {
|
|
5532
|
-
const detail = `${managed.name} joined, but its exact host session could not be bound for supervised recovery: ${error
|
|
5562
|
+
const detail = `${managed.name} joined, but its exact host session could not be bound for supervised recovery: ${rejectionText(error)}`;
|
|
5533
5563
|
this.stopHandle(managed, false);
|
|
5534
5564
|
this.freeSlot(managed, true, "session-bind-failed");
|
|
5535
5565
|
await hooks?.onOutcome?.({ kind: "failed", data: { error: detail } });
|
|
@@ -5646,7 +5676,7 @@ export class Manager {
|
|
|
5646
5676
|
: principalKey(DEV_OWNER, entry.identity.id).key;
|
|
5647
5677
|
}
|
|
5648
5678
|
catch (e) {
|
|
5649
|
-
return { ok: false, agents: [], error: `invalid retained principal for ${entry.name}: ${e
|
|
5679
|
+
return { ok: false, agents: [], error: `invalid retained principal for ${entry.name}: ${rejectionText(e)}` };
|
|
5650
5680
|
}
|
|
5651
5681
|
if (principals.has(principal))
|
|
5652
5682
|
return { ok: false, agents: [], error: `resume inventory contains duplicate principal "${principal}"` };
|
|
@@ -5722,7 +5752,7 @@ export class Manager {
|
|
|
5722
5752
|
discardLaunchArtifacts(spec.artifacts);
|
|
5723
5753
|
}
|
|
5724
5754
|
catch (e) {
|
|
5725
|
-
console.error(`! resume: ${e
|
|
5755
|
+
console.error(`! resume: ${rejectionText(e)}`);
|
|
5726
5756
|
}
|
|
5727
5757
|
}
|
|
5728
5758
|
release();
|
|
@@ -5801,7 +5831,7 @@ export class Manager {
|
|
|
5801
5831
|
throw new Error(`retained credential identity ${actual} does not match inventory principal ${entry.identity.id}`);
|
|
5802
5832
|
}
|
|
5803
5833
|
catch (e) {
|
|
5804
|
-
throw new Error(`retained credential for ${entry.name} is unusable: ${e
|
|
5834
|
+
throw new Error(`retained credential for ${entry.name} is unusable: ${rejectionText(e)}`);
|
|
5805
5835
|
}
|
|
5806
5836
|
const accepted = await this.probeStaticCredential(credentialText);
|
|
5807
5837
|
if (!accepted.ok)
|
|
@@ -5889,7 +5919,7 @@ export class Manager {
|
|
|
5889
5919
|
};
|
|
5890
5920
|
}
|
|
5891
5921
|
catch (e) {
|
|
5892
|
-
throw new Error(`retained user principal ${entry.identity.owner}.${entry.identity.actor} could not be reused: ${e
|
|
5922
|
+
throw new Error(`retained user principal ${entry.identity.owner}.${entry.identity.actor} could not be reused: ${rejectionText(e)}`);
|
|
5893
5923
|
}
|
|
5894
5924
|
}
|
|
5895
5925
|
/** The seat reference behind a live retained principal, when that seat is provably one a lost
|
|
@@ -5922,7 +5952,7 @@ export class Manager {
|
|
|
5922
5952
|
console.error(`resume: reaped orphaned seat ${reference.kind}:${reference.id} of retained principal "${principal}" (${evidence.detail})`);
|
|
5923
5953
|
}
|
|
5924
5954
|
catch (e) {
|
|
5925
|
-
return `retained principal "${principal}" is already live and its recorded seat ${reference.kind}:${reference.id} could not be reaped: ${e
|
|
5955
|
+
return `retained principal "${principal}" is already live and its recorded seat ${reference.kind}:${reference.id} could not be reaped: ${rejectionText(e)}`;
|
|
5926
5956
|
}
|
|
5927
5957
|
const deadline = Date.now() + ORPHAN_PRESENCE_CLEAR_MS;
|
|
5928
5958
|
while (this.ep.getRoster().some((p) => p.card.id === principal && p.status !== "offline")) {
|
|
@@ -5958,7 +5988,7 @@ export class Manager {
|
|
|
5958
5988
|
await this.validateRetainedAuthority(entry);
|
|
5959
5989
|
}
|
|
5960
5990
|
catch (e) {
|
|
5961
|
-
return { ok: false, error: e
|
|
5991
|
+
return { ok: false, error: rejectionText(e) };
|
|
5962
5992
|
}
|
|
5963
5993
|
return this.launchPreparedResume(entry, cached, batchReserved);
|
|
5964
5994
|
}
|
|
@@ -5968,7 +5998,7 @@ export class Manager {
|
|
|
5968
5998
|
return { ok: false, error: `retained cwd is not a real directory: ${entry.launch.cwd}` };
|
|
5969
5999
|
}
|
|
5970
6000
|
catch (e) {
|
|
5971
|
-
return { ok: false, error: `retained cwd unavailable: ${entry.launch.cwd} (${e
|
|
6001
|
+
return { ok: false, error: `retained cwd unavailable: ${entry.launch.cwd} (${rejectionText(e)})` };
|
|
5972
6002
|
}
|
|
5973
6003
|
let connector;
|
|
5974
6004
|
try {
|
|
@@ -5982,7 +6012,7 @@ export class Manager {
|
|
|
5982
6012
|
connector = await this.resolveConnector(entry.launch.connector);
|
|
5983
6013
|
}
|
|
5984
6014
|
catch (e) {
|
|
5985
|
-
return { ok: false, error: e
|
|
6015
|
+
return { ok: false, error: rejectionText(e) };
|
|
5986
6016
|
}
|
|
5987
6017
|
const harness = this.launchHarness(connector);
|
|
5988
6018
|
if ("refusal" in harness)
|
|
@@ -5992,7 +6022,7 @@ export class Manager {
|
|
|
5992
6022
|
retainedSession = this.retainedSessionId(entry, connector);
|
|
5993
6023
|
}
|
|
5994
6024
|
catch (error) {
|
|
5995
|
-
return { ok: false, error: error
|
|
6025
|
+
return { ok: false, error: rejectionText(error) };
|
|
5996
6026
|
}
|
|
5997
6027
|
if (entry.launch.forkSource && !retainedSession && !connector.supportsResume)
|
|
5998
6028
|
return { ok: false, error: `${connector.name} connector does not support session fork (resume)` };
|
|
@@ -6012,7 +6042,7 @@ export class Manager {
|
|
|
6012
6042
|
spec = source.agents.find((a) => a.name === launchSource.requested);
|
|
6013
6043
|
}
|
|
6014
6044
|
catch (e) {
|
|
6015
|
-
return { ok: false, error: e
|
|
6045
|
+
return { ok: false, error: rejectionText(e) };
|
|
6016
6046
|
}
|
|
6017
6047
|
if (!spec || spec.hash !== launchSource.hash)
|
|
6018
6048
|
return { ok: false, error: `retained manifest agent ${launchSource.requested} is missing or its hash changed; refusing same-principal resume` };
|
|
@@ -6024,7 +6054,7 @@ export class Manager {
|
|
|
6024
6054
|
launchOptions = loadAgentFile(entry.launch.source.configPath).launchOptions;
|
|
6025
6055
|
}
|
|
6026
6056
|
catch (e) {
|
|
6027
|
-
return { ok: false, error: e
|
|
6057
|
+
return { ok: false, error: rejectionText(e) };
|
|
6028
6058
|
}
|
|
6029
6059
|
}
|
|
6030
6060
|
// Asked once `exact` is known: an exact seat reopens its retained session or fails, like its
|
|
@@ -6037,7 +6067,7 @@ export class Manager {
|
|
|
6037
6067
|
authority = await this.validateRetainedAuthority(entry);
|
|
6038
6068
|
}
|
|
6039
6069
|
catch (e) {
|
|
6040
|
-
return { ok: false, error: e
|
|
6070
|
+
return { ok: false, error: rejectionText(e) };
|
|
6041
6071
|
}
|
|
6042
6072
|
try {
|
|
6043
6073
|
const resumeConfig = loadCotalConfig(this.workspaceRoot);
|
|
@@ -6086,7 +6116,7 @@ export class Manager {
|
|
|
6086
6116
|
return this.launchPreparedResume(entry, value, batchReserved);
|
|
6087
6117
|
}
|
|
6088
6118
|
catch (e) {
|
|
6089
|
-
return { ok: false, error: e
|
|
6119
|
+
return { ok: false, error: rejectionText(e) };
|
|
6090
6120
|
}
|
|
6091
6121
|
}
|
|
6092
6122
|
finally {
|
|
@@ -6169,7 +6199,7 @@ export class Manager {
|
|
|
6169
6199
|
await this.recordSlotRuntime(managed);
|
|
6170
6200
|
}
|
|
6171
6201
|
catch (error) {
|
|
6172
|
-
return await this.stopFailedResume(managed, "resume-custody-unrecorded", `${managed.name} resumed, but ${error
|
|
6202
|
+
return await this.stopFailedResume(managed, "resume-custody-unrecorded", `${managed.name} resumed, but ${rejectionText(error)}`);
|
|
6173
6203
|
}
|
|
6174
6204
|
const readiness = await this.awaitReadiness(managed, readinessTimeoutMs);
|
|
6175
6205
|
if (!readiness.ok && !readiness.uncertain)
|
|
@@ -6196,7 +6226,7 @@ export class Manager {
|
|
|
6196
6226
|
}
|
|
6197
6227
|
}
|
|
6198
6228
|
catch (error) {
|
|
6199
|
-
return await this.stopFailedResume(managed, "resume-session-rebind-failed", `${managed.name} resumed, but its exact host session could not be rebound: ${error
|
|
6229
|
+
return await this.stopFailedResume(managed, "resume-session-rebind-failed", `${managed.name} resumed, but its exact host session could not be rebound: ${rejectionText(error)}`);
|
|
6200
6230
|
}
|
|
6201
6231
|
}
|
|
6202
6232
|
if (!this.resumeAttemptId)
|
|
@@ -6210,7 +6240,7 @@ export class Manager {
|
|
|
6210
6240
|
};
|
|
6211
6241
|
}
|
|
6212
6242
|
catch (e) {
|
|
6213
|
-
return { ok: false, error: e
|
|
6243
|
+
return { ok: false, error: rejectionText(e) };
|
|
6214
6244
|
}
|
|
6215
6245
|
finally {
|
|
6216
6246
|
if (!batchReserved) {
|
|
@@ -6229,7 +6259,7 @@ export class Manager {
|
|
|
6229
6259
|
}
|
|
6230
6260
|
catch (exit) {
|
|
6231
6261
|
this.watchExit(managed);
|
|
6232
|
-
return { ok: false, error: `${detail}; it stays managed because its stop is unproven: ${exit
|
|
6262
|
+
return { ok: false, error: `${detail}; it stays managed because its stop is unproven: ${rejectionText(exit)}` };
|
|
6233
6263
|
}
|
|
6234
6264
|
this.freeSlot(managed, true, cause, true);
|
|
6235
6265
|
return { ok: false, error: detail };
|
|
@@ -6981,7 +7011,7 @@ export class Manager {
|
|
|
6981
7011
|
// One registration operation for this boot. Fresh executors may replace a dead connection, but
|
|
6982
7012
|
// they must resume THIS freeze rather than minting a new op that discards Phase-2 progress.
|
|
6983
7013
|
const registrationOpId = mintLifecycleUid();
|
|
6984
|
-
const executorExpired = (e) => /closed connection/i.test(
|
|
7014
|
+
const executorExpired = (e) => /closed connection/i.test(rejectionText(e));
|
|
6985
7015
|
const retryExpiredExecutor = async (label, fn) => {
|
|
6986
7016
|
for (;;) {
|
|
6987
7017
|
try {
|
|
@@ -7588,14 +7618,14 @@ export class Manager {
|
|
|
7588
7618
|
await this.reconcileOneGoal(entry.ref, entry.iid);
|
|
7589
7619
|
}
|
|
7590
7620
|
catch (e) {
|
|
7591
|
-
console.error(`! goal reconcile for ${entry.ref.goalId}: ${e
|
|
7621
|
+
console.error(`! goal reconcile for ${entry.ref.goalId}: ${rejectionText(e)}`);
|
|
7592
7622
|
}
|
|
7593
7623
|
}
|
|
7594
7624
|
if (entries.length)
|
|
7595
7625
|
console.error(`goal-index boot reconcile: swept ${entries.length} inherited goal(s)`);
|
|
7596
7626
|
}
|
|
7597
7627
|
catch (e) {
|
|
7598
|
-
console.error(`! goal-index boot reconcile failed: ${e
|
|
7628
|
+
console.error(`! goal-index boot reconcile failed: ${rejectionText(e)} - accepted goals from a predecessor may stay unsettled until the next restart`);
|
|
7599
7629
|
}
|
|
7600
7630
|
finally {
|
|
7601
7631
|
this.goalReconcileDone = true;
|
|
@@ -7645,7 +7675,7 @@ export class Manager {
|
|
|
7645
7675
|
return;
|
|
7646
7676
|
}
|
|
7647
7677
|
console.error(`goal reconcile ${ref.goalId}: within the readiness window (${remaining}ms) - arming a bounded settle`);
|
|
7648
|
-
const t = setTimeout(() => { settle().catch((e) => console.error(`! goal reconcile settle ${ref.goalId}: ${e
|
|
7678
|
+
const t = setTimeout(() => { settle().catch((e) => console.error(`! goal reconcile settle ${ref.goalId}: ${rejectionText(e)}`)); }, remaining + 100);
|
|
7649
7679
|
t.unref?.();
|
|
7650
7680
|
}
|
|
7651
7681
|
/** P2 item 2: publish a goal PROGRESS event on the caller-scoped epe subtree, over the SERVE
|
|
@@ -7661,7 +7691,7 @@ export class Manager {
|
|
|
7661
7691
|
nc.publish(epeSubject(this.space, MANAGER_ENDPOINT, this.managerInstanceId, epoch, goalProgressTopic(ref)), new TextEncoder().encode(JSON.stringify({ v: 1, goalId: ref.goalId, ...event })));
|
|
7662
7692
|
}
|
|
7663
7693
|
catch (e) {
|
|
7664
|
-
console.error(`! goal progress emit for ${ref.goalId} failed: ${e
|
|
7694
|
+
console.error(`! goal progress emit for ${ref.goalId} failed: ${rejectionText(e)}`);
|
|
7665
7695
|
}
|
|
7666
7696
|
}
|
|
7667
7697
|
/** The own-gate currency belt: before the goal-writer commits a terminal fact, the manager reads
|
|
@@ -7800,7 +7830,7 @@ export class Manager {
|
|
|
7800
7830
|
// ENTRY. This leg is infrastructure-class and converges through the reconcile index at the
|
|
7801
7831
|
// next boot, which is why the index is NOT cleared above on this path. Do not "close" it
|
|
7802
7832
|
// here with a retry loop.
|
|
7803
|
-
console.error(`! goal terminal commit for ${goalId} failed: ${e
|
|
7833
|
+
console.error(`! goal terminal commit for ${goalId} failed: ${rejectionText(e)}`);
|
|
7804
7834
|
}
|
|
7805
7835
|
};
|
|
7806
7836
|
const bg = run({
|
|
@@ -7885,7 +7915,7 @@ export class Manager {
|
|
|
7885
7915
|
// the caller follows epe to a terminal that never comes, and the reconcile index that would
|
|
7886
7916
|
// settle it is only swept at BOOT, so a manager that stays up never converges it.
|
|
7887
7917
|
if (reply.ok === false && !terminalEntered)
|
|
7888
|
-
return onOutcome({ kind: "failed", data:
|
|
7918
|
+
return onOutcome({ kind: "failed", data: failedTerminal(reply.error ?? "spawn failed after accept", reply) });
|
|
7889
7919
|
}).catch((e) => {
|
|
7890
7920
|
if (acceptance === undefined) {
|
|
7891
7921
|
rejectAccept(e);
|
|
@@ -7893,9 +7923,9 @@ export class Manager {
|
|
|
7893
7923
|
}
|
|
7894
7924
|
// Same obligation for a genuine rejection (one that escaped `run`'s own catch).
|
|
7895
7925
|
if (!terminalEntered)
|
|
7896
|
-
return onOutcome({ kind: "failed", data:
|
|
7897
|
-
console.error(`! spawn-as-action async body for ${goalId}: ${
|
|
7898
|
-
}).catch((e) => console.error(`! goal terminal fallback for ${goalId}: ${
|
|
7926
|
+
return onOutcome({ kind: "failed", data: failedTerminal(rejectionText(e), caughtEnvelope(e)) });
|
|
7927
|
+
console.error(`! spawn-as-action async body for ${goalId}: ${rejectionText(e)}`);
|
|
7928
|
+
}).catch((e) => console.error(`! goal terminal fallback for ${goalId}: ${rejectionText(e)}`));
|
|
7899
7929
|
return acceptP;
|
|
7900
7930
|
}
|
|
7901
7931
|
/** H2: an acceptance served from a WINNER'S durable acceptance floor (the goal-index entry it
|
|
@@ -8038,7 +8068,7 @@ export class Manager {
|
|
|
8038
8068
|
// The accept is inline (no launch closure to fail later), so a post-bind throw unwinds HERE:
|
|
8039
8069
|
// commit the failed terminal this attempt owns, clear the index, and refuse the accept — an
|
|
8040
8070
|
// accepted-but-unanswered goal must never be left for the boot sweep to find (H1's rule).
|
|
8041
|
-
const msg =
|
|
8071
|
+
const msg = rejectionText(e);
|
|
8042
8072
|
try {
|
|
8043
8073
|
await this.assertGoalWriterEpochCurrent(executor.epoch);
|
|
8044
8074
|
// The goal is TARGET-PINNED, so its completion proves the seat's currency exactly as the
|
|
@@ -8054,9 +8084,9 @@ export class Manager {
|
|
|
8054
8084
|
await clearGoalIndex(gw.ctx, ref);
|
|
8055
8085
|
}
|
|
8056
8086
|
catch (e2) {
|
|
8057
|
-
console.error(`! turn accept unwind for ${goalId}: ${e2
|
|
8087
|
+
console.error(`! turn accept unwind for ${goalId}: ${rejectionText(e2)}`);
|
|
8058
8088
|
}
|
|
8059
|
-
throw e
|
|
8089
|
+
throw caughtEnvelope(e) ?? new EpEnvelopeError("internal", `turn accept for ${goalId} failed: ${msg}`);
|
|
8060
8090
|
}
|
|
8061
8091
|
const pending = {
|
|
8062
8092
|
ref, goalId,
|
|
@@ -8256,7 +8286,7 @@ export class Manager {
|
|
|
8256
8286
|
await clearGoalIndex(gw.ctx, p.ref);
|
|
8257
8287
|
}
|
|
8258
8288
|
catch (e) {
|
|
8259
|
-
console.error(`! turn deadline terminal for ${p.goalId}: ${e
|
|
8289
|
+
console.error(`! turn deadline terminal for ${p.goalId}: ${rejectionText(e)}`);
|
|
8260
8290
|
}
|
|
8261
8291
|
this.maybeStopTurnSweep();
|
|
8262
8292
|
}
|
|
@@ -8288,7 +8318,7 @@ export class Manager {
|
|
|
8288
8318
|
ensureTurnSweep() {
|
|
8289
8319
|
if (this.turnSweepTimer !== undefined)
|
|
8290
8320
|
return;
|
|
8291
|
-
const t = setInterval(() => { void this.sweepTurnDeadlines().catch((e) => console.error(`! turn deadline sweep: ${e
|
|
8321
|
+
const t = setInterval(() => { void this.sweepTurnDeadlines().catch((e) => console.error(`! turn deadline sweep: ${rejectionText(e)}`)); }, TURN_SWEEP_MS);
|
|
8292
8322
|
t.unref?.();
|
|
8293
8323
|
this.turnSweepTimer = t;
|
|
8294
8324
|
}
|
|
@@ -8357,7 +8387,7 @@ export class Manager {
|
|
|
8357
8387
|
await this.commitTurnDeadline(p);
|
|
8358
8388
|
}
|
|
8359
8389
|
catch (e) {
|
|
8360
|
-
console.error(`! turn deadline sweep for ${p.goalId}: ${e
|
|
8390
|
+
console.error(`! turn deadline sweep for ${p.goalId}: ${rejectionText(e)}`);
|
|
8361
8391
|
}
|
|
8362
8392
|
}
|
|
8363
8393
|
}
|
|
@@ -8488,7 +8518,7 @@ export class Manager {
|
|
|
8488
8518
|
});
|
|
8489
8519
|
}
|
|
8490
8520
|
catch (e) {
|
|
8491
|
-
throw new Error(`could not record the custody reference ${runtime.kind}:${runtime.id} on the static slot of "${a.name}": ${e
|
|
8521
|
+
throw new Error(`could not record the custody reference ${runtime.kind}:${runtime.id} on the static slot of "${a.name}": ${rejectionText(e)}`);
|
|
8492
8522
|
}
|
|
8493
8523
|
}
|
|
8494
8524
|
/** Mint the custody reference for a seat this manager is about to spawn, BEFORE the processes
|
|
@@ -8534,7 +8564,7 @@ export class Manager {
|
|
|
8534
8564
|
disposal =
|
|
8535
8565
|
e instanceof RuntimeReapUnproven
|
|
8536
8566
|
? `the spawned seat was NOT proved gone and may still be running as ${e.reference.kind}:${e.reference.id} (${e.message})`
|
|
8537
|
-
: `the spawned seat could NOT be reaped: ${e
|
|
8567
|
+
: `the spawned seat could NOT be reaped: ${rejectionText(e)}`;
|
|
8538
8568
|
}
|
|
8539
8569
|
}
|
|
8540
8570
|
throw new Error(`runtime "${this.runtime.kind}" reserved custody ${reserved.kind}:${reserved.id} for "${name}" but spawned ` +
|
|
@@ -8635,8 +8665,8 @@ export class Manager {
|
|
|
8635
8665
|
catch (e) {
|
|
8636
8666
|
const h = this.retiring.get(a.name);
|
|
8637
8667
|
if (h && h.lifecycleUid === a.lifecycleUid)
|
|
8638
|
-
h.lastError = `the static retirement did not complete (${e
|
|
8639
|
-
console.error(`static retirement ${a.name} (${a.id}): ${e
|
|
8668
|
+
h.lastError = `the static retirement did not complete (${rejectionText(e)}); the name stays held - a same-name spawn retries the same terminal (op ${opId})`;
|
|
8669
|
+
console.error(`static retirement ${a.name} (${a.id}): ${rejectionText(e)}`);
|
|
8640
8670
|
if (surfaceFailure)
|
|
8641
8671
|
throw e;
|
|
8642
8672
|
}
|
|
@@ -8739,7 +8769,7 @@ export class Manager {
|
|
|
8739
8769
|
await this.retryStaticReconcile(key);
|
|
8740
8770
|
};
|
|
8741
8771
|
void run().catch((error) => {
|
|
8742
|
-
item.lastError = `retry driver failed before the exact terminal: ${error
|
|
8772
|
+
item.lastError = `retry driver failed before the exact terminal: ${rejectionText(error)}`;
|
|
8743
8773
|
item.disposition = "retry-exhausted";
|
|
8744
8774
|
item.remedy = "restart this manager for a fresh per-process retry budget";
|
|
8745
8775
|
console.error(`! static reconcile retry-exhausted alias=${item.alias} phase=${item.phase} uid=${item.lifecycleUid}: ${item.lastError}; NEXT: restart this manager for a fresh per-process retry budget`);
|
|
@@ -8780,7 +8810,7 @@ export class Manager {
|
|
|
8780
8810
|
row = await this.readStaticReconcileSlot(item.alias);
|
|
8781
8811
|
}
|
|
8782
8812
|
catch (error) {
|
|
8783
|
-
item.lastError = `durable slot re-read failed: ${error
|
|
8813
|
+
item.lastError = `durable slot re-read failed: ${rejectionText(error)}`;
|
|
8784
8814
|
if (item.attempts >= item.maxAttempts) {
|
|
8785
8815
|
item.disposition = "retry-exhausted";
|
|
8786
8816
|
item.remedy = "restart this manager for a fresh per-process retry budget";
|
|
@@ -8864,7 +8894,7 @@ export class Manager {
|
|
|
8864
8894
|
return true;
|
|
8865
8895
|
}
|
|
8866
8896
|
catch (error) {
|
|
8867
|
-
item.lastError = error
|
|
8897
|
+
item.lastError = rejectionText(error);
|
|
8868
8898
|
try {
|
|
8869
8899
|
const fresh = await this.readStaticReconcileSlot(item.alias);
|
|
8870
8900
|
if (fresh?.lifecycleUid === item.lifecycleUid && fresh.actor === item.actor)
|
|
@@ -8963,16 +8993,8 @@ export class Manager {
|
|
|
8963
8993
|
const kvm = new Kvm(nc);
|
|
8964
8994
|
await ensureAuthorityStores(jsm, kvm, this.space);
|
|
8965
8995
|
const recordsKv = await kvm.open(recordsBucket(this.space));
|
|
8966
|
-
const
|
|
8967
|
-
|
|
8968
|
-
const aliases = [];
|
|
8969
|
-
for await (const k of keys)
|
|
8970
|
-
aliases.push(k.split(".").slice(2).join("."));
|
|
8971
|
-
for (const alias of aliases) {
|
|
8972
|
-
const slot = await readStaticSlot(t, DEV_OWNER, alias);
|
|
8973
|
-
if (slot !== undefined)
|
|
8974
|
-
slotRows.push(slot.row);
|
|
8975
|
-
}
|
|
8996
|
+
for (const slot of await walkStaticSlots(recordsKv, DEV_OWNER))
|
|
8997
|
+
slotRows.push(slot.row);
|
|
8976
8998
|
}
|
|
8977
8999
|
catch (error) {
|
|
8978
9000
|
sweep.completedAt = new Date().toISOString();
|
|
@@ -9221,7 +9243,7 @@ export class Manager {
|
|
|
9221
9243
|
return { ok: true, data: result };
|
|
9222
9244
|
}
|
|
9223
9245
|
catch (e) {
|
|
9224
|
-
return { ok: false, error: e
|
|
9246
|
+
return { ok: false, error: rejectionText(e) };
|
|
9225
9247
|
}
|
|
9226
9248
|
}
|
|
9227
9249
|
/** Persist a peer-defined persona as config. After this, `start name` auto-discovers
|
|
@@ -9253,7 +9275,7 @@ export class Manager {
|
|
|
9253
9275
|
existing = loadAgentFile(path);
|
|
9254
9276
|
}
|
|
9255
9277
|
catch (e) {
|
|
9256
|
-
return { ok: false, error: e
|
|
9278
|
+
return { ok: false, error: rejectionText(e) };
|
|
9257
9279
|
}
|
|
9258
9280
|
if (!admin && existing.owner !== caller) {
|
|
9259
9281
|
const owner = existing.owner ? `owned by ${existing.owner}` : "operator-owned (legacy file - no agent owner)";
|
|
@@ -9280,13 +9302,13 @@ export class Manager {
|
|
|
9280
9302
|
}, existing);
|
|
9281
9303
|
}
|
|
9282
9304
|
catch (e) {
|
|
9283
|
-
return { ok: false, error: e
|
|
9305
|
+
return { ok: false, error: rejectionText(e) };
|
|
9284
9306
|
}
|
|
9285
9307
|
try {
|
|
9286
9308
|
saveAgentFile(path, def);
|
|
9287
9309
|
}
|
|
9288
9310
|
catch (e) {
|
|
9289
|
-
return { ok: false, error: e
|
|
9311
|
+
return { ok: false, error: rejectionText(e) };
|
|
9290
9312
|
}
|
|
9291
9313
|
return { ok: true, data: { name, path } };
|
|
9292
9314
|
}
|
|
@@ -9444,7 +9466,7 @@ export class Manager {
|
|
|
9444
9466
|
accepted = await write(part.data);
|
|
9445
9467
|
}
|
|
9446
9468
|
catch (error) {
|
|
9447
|
-
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: ${error
|
|
9469
|
+
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: ${rejectionText(error)}`);
|
|
9448
9470
|
}
|
|
9449
9471
|
if (!Number.isSafeInteger(accepted)) {
|
|
9450
9472
|
throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: runtime accepted ${String(accepted)} of ${intendedBytes} bytes`);
|
|
@@ -9495,7 +9517,7 @@ export class Manager {
|
|
|
9495
9517
|
}
|
|
9496
9518
|
catch (e) {
|
|
9497
9519
|
slot.release();
|
|
9498
|
-
return { ok: false, error: e
|
|
9520
|
+
return { ok: false, error: rejectionText(e) };
|
|
9499
9521
|
}
|
|
9500
9522
|
// establishAttach releases the claim it was handed on every exit; nothing to unwind here.
|
|
9501
9523
|
const { grant } = await this.sessionPlane.establishAttach(caller, { name: a.name, lifecycleUid: a.lifecycleUid }, session, slot);
|