metheus-governance-mcp-cli 0.2.285 → 0.2.286
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/cli.mjs +76 -24
- package/lib/runner-recovery.mjs +83 -17
- package/lib/selftest-runner-scenarios.mjs +271 -5
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -3562,7 +3562,9 @@ function buildRunnerRequestKey({
|
|
|
3562
3562
|
const intent = canonicalHumanKey
|
|
3563
3563
|
? "-"
|
|
3564
3564
|
: String(normalizedIntent || "").trim().toLowerCase() || "-";
|
|
3565
|
-
const resolvedConversationID =
|
|
3565
|
+
const resolvedConversationID = canonicalHumanKey
|
|
3566
|
+
? "-"
|
|
3567
|
+
: String(conversationID || parsed.conversationID || "").trim() || "-";
|
|
3566
3568
|
return [
|
|
3567
3569
|
String(normalizedRoute?.projectID || "").trim() || "-",
|
|
3568
3570
|
String(normalizedRoute?.provider || "").trim() || "-",
|
|
@@ -3994,10 +3996,10 @@ function runnerRequestPreferredNextExpectedResponders(entryRaw) {
|
|
|
3994
3996
|
);
|
|
3995
3997
|
}
|
|
3996
3998
|
|
|
3997
|
-
function runnerRequestPreferredAuthoritySelectedBotUsernames(entryRaw) {
|
|
3998
|
-
const entry = safeObject(entryRaw);
|
|
3999
|
-
const normalizedSummaryBot = normalizeTelegramMentionUsername(entry.conversation_summary_bot);
|
|
4000
|
-
return uniqueOrderedStrings(
|
|
3999
|
+
function runnerRequestPreferredAuthoritySelectedBotUsernames(entryRaw) {
|
|
4000
|
+
const entry = safeObject(entryRaw);
|
|
4001
|
+
const normalizedSummaryBot = normalizeTelegramMentionUsername(entry.conversation_summary_bot);
|
|
4002
|
+
return uniqueOrderedStrings(
|
|
4001
4003
|
runnerRequestPreferredNextExpectedResponders(entry).length
|
|
4002
4004
|
? runnerRequestPreferredNextExpectedResponders(entry)
|
|
4003
4005
|
: runnerRequestPreferredExecutionContractTargets(entry).length
|
|
@@ -4025,6 +4027,35 @@ function extractRunnerExplicitSelectedBotUsernamesFromParsed(parsedArchiveRaw) {
|
|
|
4025
4027
|
normalizeTelegramMentionUsername,
|
|
4026
4028
|
);
|
|
4027
4029
|
}
|
|
4030
|
+
|
|
4031
|
+
function runnerRequestAllowsSharedHumanClaimTakeover({
|
|
4032
|
+
entryRaw,
|
|
4033
|
+
currentBotUsername = "",
|
|
4034
|
+
canonicalHumanMessageKey = "",
|
|
4035
|
+
}) {
|
|
4036
|
+
const entry = safeObject(entryRaw);
|
|
4037
|
+
const normalizedCurrentBotUsername = normalizeTelegramMentionUsername(currentBotUsername);
|
|
4038
|
+
const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
|
|
4039
|
+
if (!normalizedCurrentBotUsername || !normalizedCanonicalHumanMessageKey) {
|
|
4040
|
+
return false;
|
|
4041
|
+
}
|
|
4042
|
+
if (String(entry.canonical_human_message_key || "").trim() !== normalizedCanonicalHumanMessageKey) {
|
|
4043
|
+
return false;
|
|
4044
|
+
}
|
|
4045
|
+
const pendingResponders = runnerRequestPreferredNextExpectedResponders(entry);
|
|
4046
|
+
if (pendingResponders.length > 0) {
|
|
4047
|
+
return pendingResponders.includes(normalizedCurrentBotUsername);
|
|
4048
|
+
}
|
|
4049
|
+
const directHumanResponders = uniqueOrderedStrings(
|
|
4050
|
+
[
|
|
4051
|
+
...ensureArray(entry.selected_bot_usernames),
|
|
4052
|
+
...ensureArray(entry.conversation_initial_responders),
|
|
4053
|
+
...ensureArray(entry.conversation_allowed_responders),
|
|
4054
|
+
],
|
|
4055
|
+
normalizeTelegramMentionUsername,
|
|
4056
|
+
);
|
|
4057
|
+
return directHumanResponders.includes(normalizedCurrentBotUsername);
|
|
4058
|
+
}
|
|
4028
4059
|
|
|
4029
4060
|
function runnerRequestPreferredAIReplyPreview(entryRaw) {
|
|
4030
4061
|
const entry = safeObject(entryRaw);
|
|
@@ -5067,8 +5098,8 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5067
5098
|
reason: "non_human_comment_cannot_create_request",
|
|
5068
5099
|
};
|
|
5069
5100
|
}
|
|
5070
|
-
const currentState = loadBotRunnerState();
|
|
5071
|
-
const currentRouteState = safeObject(safeObject(currentState.routes)[String(routeKey || "").trim()]);
|
|
5101
|
+
const currentState = loadBotRunnerState();
|
|
5102
|
+
const currentRouteState = safeObject(safeObject(currentState.routes)[String(routeKey || "").trim()]);
|
|
5072
5103
|
const replyChainResolution = await resolveRunnerReplyChainConversationContextWithServerFallback({
|
|
5073
5104
|
state: currentState,
|
|
5074
5105
|
normalizedRoute,
|
|
@@ -5168,6 +5199,16 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5168
5199
|
const authoritativeDecisionBundle = decisionBundleValidation.ok === true
|
|
5169
5200
|
? safeObject(decisionBundleValidation.bundle)
|
|
5170
5201
|
: {};
|
|
5202
|
+
const normalizedAuthoritativeSourceMessageEnvelope = normalizeRunnerTelegramMessageEnvelope(
|
|
5203
|
+
authoritativeSourceMessageEnvelope,
|
|
5204
|
+
);
|
|
5205
|
+
const currentClaimBotUsername = normalizeTelegramMentionUsername(
|
|
5206
|
+
normalizedAuthoritativeSourceMessageEnvelope.source_bot_username
|
|
5207
|
+
|| normalizedAuthoritativeSourceMessageEnvelope.sender_username
|
|
5208
|
+
|| currentRouteState.last_source_bot_username
|
|
5209
|
+
|| currentRouteState.source_message_bot_username
|
|
5210
|
+
|| currentRouteState.last_speaker_bot_username,
|
|
5211
|
+
);
|
|
5171
5212
|
const authorityReplyChainContext = await buildRunnerAuthorityReplyChainContext({
|
|
5172
5213
|
selectedRecord,
|
|
5173
5214
|
replyChainContext,
|
|
@@ -5200,24 +5241,35 @@ async function claimRunnerRequestForHumanComment({
|
|
|
5200
5241
|
requestKey,
|
|
5201
5242
|
};
|
|
5202
5243
|
}
|
|
5203
|
-
if (
|
|
5204
|
-
isActiveRunnerRequestStatus(existing.status)
|
|
5205
|
-
&& String(existing.claimed_by_route || "").trim()
|
|
5206
|
-
&& String(existing.claimed_by_route || "").trim() !== String(routeKey || "").trim()
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5244
|
+
if (
|
|
5245
|
+
isActiveRunnerRequestStatus(existing.status)
|
|
5246
|
+
&& String(existing.claimed_by_route || "").trim()
|
|
5247
|
+
&& String(existing.claimed_by_route || "").trim() !== String(routeKey || "").trim()
|
|
5248
|
+
&& !runnerRequestAllowsSharedHumanClaimTakeover({
|
|
5249
|
+
entryRaw: existing,
|
|
5250
|
+
currentBotUsername: currentClaimBotUsername,
|
|
5251
|
+
canonicalHumanMessageKey,
|
|
5252
|
+
})
|
|
5253
|
+
) {
|
|
5254
|
+
return {
|
|
5255
|
+
ok: false,
|
|
5256
|
+
reason: "request_already_claimed",
|
|
5257
|
+
requestKey,
|
|
5258
|
+
};
|
|
5259
|
+
}
|
|
5260
|
+
const nowISO = new Date().toISOString();
|
|
5261
|
+
const existingSourceMessageEnvelope = normalizeRunnerTelegramMessageEnvelope(existing.source_message_envelope);
|
|
5262
|
+
const preserveExistingCanonicalSourceEnvelope = Boolean(
|
|
5263
|
+
canonicalHumanMessageKey
|
|
5264
|
+
&& String(existing.canonical_human_message_key || "").trim() === canonicalHumanMessageKey
|
|
5265
|
+
&& intFromRawAllowZero(existing.source_message_id, 0) === currentMessageID
|
|
5266
|
+
&& Object.keys(existingSourceMessageEnvelope).length > 0
|
|
5217
5267
|
);
|
|
5218
|
-
const sourceMessageEnvelope =
|
|
5219
|
-
?
|
|
5220
|
-
:
|
|
5268
|
+
const sourceMessageEnvelope = preserveExistingCanonicalSourceEnvelope
|
|
5269
|
+
? existingSourceMessageEnvelope
|
|
5270
|
+
: Object.keys(normalizedAuthoritativeSourceMessageEnvelope).length
|
|
5271
|
+
? normalizedAuthoritativeSourceMessageEnvelope
|
|
5272
|
+
: existingSourceMessageEnvelope;
|
|
5221
5273
|
const decisionConversationParticipants = uniqueOrderedStrings(
|
|
5222
5274
|
ensureArray(authoritativeDecisionBundle.participants),
|
|
5223
5275
|
normalizeTelegramMentionUsername,
|
package/lib/runner-recovery.mjs
CHANGED
|
@@ -46,6 +46,58 @@ function uniqueOrderedStrings(values, normalizer = (value) => String(value || ""
|
|
|
46
46
|
return output;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
function buildRunnerRequestRecoveryAuthoritativeDecisionBundle(requestRaw) {
|
|
50
|
+
return safeObject(safeObject(requestRaw).authoritative_decision_bundle);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildRunnerRequestRecoveryPreferredExecutionContractTargets(requestRaw) {
|
|
54
|
+
const request = safeObject(requestRaw);
|
|
55
|
+
const decisionBundle = buildRunnerRequestRecoveryAuthoritativeDecisionBundle(request);
|
|
56
|
+
return uniqueOrderedStrings(
|
|
57
|
+
ensureArray(decisionBundle.execution_contract_targets).length
|
|
58
|
+
? decisionBundle.execution_contract_targets
|
|
59
|
+
: ensureArray(request.execution_contract_targets).length
|
|
60
|
+
? request.execution_contract_targets
|
|
61
|
+
: ensureArray(request.root_execution_contract_targets),
|
|
62
|
+
normalizeTelegramMentionUsername,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function buildRunnerRequestRecoveryPreferredNextExpectedResponders(requestRaw) {
|
|
67
|
+
const request = safeObject(requestRaw);
|
|
68
|
+
const decisionBundle = buildRunnerRequestRecoveryAuthoritativeDecisionBundle(request);
|
|
69
|
+
return uniqueOrderedStrings(
|
|
70
|
+
ensureArray(decisionBundle.next_expected_responders).length
|
|
71
|
+
? decisionBundle.next_expected_responders
|
|
72
|
+
: ensureArray(request.next_expected_responders).length
|
|
73
|
+
? request.next_expected_responders
|
|
74
|
+
: ensureArray(request.root_next_expected_responders),
|
|
75
|
+
normalizeTelegramMentionUsername,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function runnerRequestShouldRemainRunningDuringRecovery(requestRaw) {
|
|
80
|
+
const request = safeObject(requestRaw);
|
|
81
|
+
const decisionBundle = buildRunnerRequestRecoveryAuthoritativeDecisionBundle(request);
|
|
82
|
+
const preferredExecutionContractType = String(
|
|
83
|
+
decisionBundle.execution_contract_type
|
|
84
|
+
|| request.execution_contract_type
|
|
85
|
+
|| request.root_execution_contract_type
|
|
86
|
+
|| "",
|
|
87
|
+
).trim().toLowerCase();
|
|
88
|
+
const preferredExecutionContractTargets = buildRunnerRequestRecoveryPreferredExecutionContractTargets(request);
|
|
89
|
+
const preferredNextExpectedResponders = buildRunnerRequestRecoveryPreferredNextExpectedResponders(request);
|
|
90
|
+
if (decisionBundle.should_close_after_reply === true) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (decisionBundle.should_close_after_reply === false) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return preferredExecutionContractType === "delegation"
|
|
97
|
+
|| preferredExecutionContractTargets.length > 0
|
|
98
|
+
|| preferredNextExpectedResponders.length > 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
49
101
|
function normalizeRunnerRequestStatus(rawStatus) {
|
|
50
102
|
const status = String(rawStatus || "").trim().toLowerCase();
|
|
51
103
|
return [
|
|
@@ -144,25 +196,39 @@ export function buildRunnerRequestRecoveryPatchFromRouteState(currentStateRaw, r
|
|
|
144
196
|
const requestStatus = normalizeRunnerRequestStatus(request.status);
|
|
145
197
|
if (!isFinalRunnerRequestStatus(requestStatus)) {
|
|
146
198
|
const routeAction = String(routeState.last_action || "").trim().toLowerCase();
|
|
199
|
+
const shouldRemainRunning = runnerRequestShouldRemainRunningDuringRecovery(request);
|
|
147
200
|
if (routeAction === "replied") {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
201
|
+
if (shouldRemainRunning) {
|
|
202
|
+
patch.status = "running";
|
|
203
|
+
patch.completed_at = "";
|
|
204
|
+
patch.closed_at = "";
|
|
205
|
+
patch.closed_reason = "";
|
|
206
|
+
} else {
|
|
207
|
+
patch.status = "completed";
|
|
208
|
+
patch.completed_at = firstNonEmptyString([
|
|
209
|
+
request.completed_at,
|
|
210
|
+
request.updated_at,
|
|
211
|
+
new Date().toISOString(),
|
|
212
|
+
]);
|
|
213
|
+
}
|
|
154
214
|
} else if (routeAction === "error" || routeAction === "skipped" || routeAction === "closed") {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
215
|
+
if (shouldRemainRunning) {
|
|
216
|
+
patch.status = "running";
|
|
217
|
+
patch.closed_at = "";
|
|
218
|
+
patch.closed_reason = "";
|
|
219
|
+
} else {
|
|
220
|
+
patch.status = "closed";
|
|
221
|
+
patch.closed_at = firstNonEmptyString([
|
|
222
|
+
request.closed_at,
|
|
223
|
+
request.updated_at,
|
|
224
|
+
new Date().toISOString(),
|
|
225
|
+
]);
|
|
226
|
+
patch.closed_reason = firstNonEmptyString([
|
|
227
|
+
request.closed_reason,
|
|
228
|
+
routeState.last_reason,
|
|
229
|
+
routeAction,
|
|
230
|
+
]);
|
|
231
|
+
}
|
|
166
232
|
}
|
|
167
233
|
}
|
|
168
234
|
if (Object.keys(patch).length) {
|
|
@@ -2334,8 +2334,238 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2334
2334
|
`primary=${String(sharedHumanClaimPrimary.requestKey || "(none)")} peer=${String(sharedHumanClaimPeer.requestKey || "(none)")} peer_reason=${String(sharedHumanClaimPeer.reason || "(none)")} count=${sharedHumanRequestCount} canonical=${String(safeObject(sharedHumanRequests[0]).canonical_human_message_key || "(none)")}`,
|
|
2335
2335
|
);
|
|
2336
2336
|
|
|
2337
|
+
const canonicalConversationVariantBody = "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같은 사람 메시지";
|
|
2338
|
+
const canonicalConversationVariantPrimary = {
|
|
2339
|
+
id: "comment-request-shared-human-conversation-1",
|
|
2340
|
+
createdAt: "2026-04-01T06:10:00.000Z",
|
|
2341
|
+
updatedAt: "2026-04-01T06:10:00.000Z",
|
|
2342
|
+
parsedArchive: {
|
|
2343
|
+
kind: "telegram_message",
|
|
2344
|
+
chatID: "-100124",
|
|
2345
|
+
chatType: "supergroup",
|
|
2346
|
+
body: canonicalConversationVariantBody,
|
|
2347
|
+
messageID: 1290,
|
|
2348
|
+
senderID: "7002",
|
|
2349
|
+
senderIsBot: false,
|
|
2350
|
+
occurredAt: "2026-04-01T06:10:00.000Z",
|
|
2351
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2352
|
+
},
|
|
2353
|
+
};
|
|
2354
|
+
const canonicalConversationVariantPeer = {
|
|
2355
|
+
id: "comment-request-shared-human-conversation-2",
|
|
2356
|
+
createdAt: "2026-04-01T06:10:00.000Z",
|
|
2357
|
+
updatedAt: "2026-04-01T06:10:00.000Z",
|
|
2358
|
+
parsedArchive: {
|
|
2359
|
+
kind: "telegram_message",
|
|
2360
|
+
chatID: "-100124",
|
|
2361
|
+
chatType: "supergroup",
|
|
2362
|
+
body: canonicalConversationVariantBody,
|
|
2363
|
+
messageID: 1290,
|
|
2364
|
+
senderID: "7002",
|
|
2365
|
+
senderIsBot: false,
|
|
2366
|
+
occurredAt: "2026-04-01T06:10:00.000Z",
|
|
2367
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2368
|
+
conversationID: "comment-request-shared-human-conversation-1",
|
|
2369
|
+
},
|
|
2370
|
+
};
|
|
2371
|
+
const canonicalConversationVariantPrimaryClaim = await claimRunnerRequestForHumanComment({
|
|
2372
|
+
normalizedRoute: sharedHumanRouteRyoai1,
|
|
2373
|
+
routeKey: sharedHumanRouteRyoai1Key,
|
|
2374
|
+
selectedRecord: canonicalConversationVariantPrimary,
|
|
2375
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2376
|
+
normalizedIntent: "discussion_request",
|
|
2377
|
+
authoritativeSourceMessageEnvelope: {
|
|
2378
|
+
chat_id: "-100124",
|
|
2379
|
+
message_id: 1290,
|
|
2380
|
+
sender_id: "7002",
|
|
2381
|
+
sender_is_bot: false,
|
|
2382
|
+
occurred_at: "2026-04-01T06:10:00.000Z",
|
|
2383
|
+
body: canonicalConversationVariantBody,
|
|
2384
|
+
source_origin: "local_telegram_inbound",
|
|
2385
|
+
source_route_key: sharedHumanRouteRyoai1Key,
|
|
2386
|
+
source_bot_username: "ryoai_bot",
|
|
2387
|
+
},
|
|
2388
|
+
});
|
|
2389
|
+
const canonicalConversationVariantPeerClaim = await claimRunnerRequestForHumanComment({
|
|
2390
|
+
normalizedRoute: sharedHumanRouteRyoai3,
|
|
2391
|
+
routeKey: sharedHumanRouteRyoai3Key,
|
|
2392
|
+
selectedRecord: canonicalConversationVariantPeer,
|
|
2393
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2394
|
+
normalizedIntent: "discussion_request",
|
|
2395
|
+
authoritativeSourceMessageEnvelope: {
|
|
2396
|
+
chat_id: "-100124",
|
|
2397
|
+
message_id: 1290,
|
|
2398
|
+
sender_id: "7002",
|
|
2399
|
+
sender_is_bot: false,
|
|
2400
|
+
occurred_at: "2026-04-01T06:10:00.000Z",
|
|
2401
|
+
body: canonicalConversationVariantBody,
|
|
2402
|
+
source_origin: "local_telegram_inbound",
|
|
2403
|
+
source_route_key: sharedHumanRouteRyoai3Key,
|
|
2404
|
+
source_bot_username: "ryoai3_bot",
|
|
2405
|
+
},
|
|
2406
|
+
});
|
|
2407
|
+
const canonicalConversationVariantState = loadBotRunnerState();
|
|
2408
|
+
const canonicalConversationVariantRequests = Object.values(safeObject(canonicalConversationVariantState.requests))
|
|
2409
|
+
.filter((entryRaw) => {
|
|
2410
|
+
const entry = safeObject(entryRaw);
|
|
2411
|
+
return String(entry.chat_id || "") === "-100124"
|
|
2412
|
+
&& intFromRawAllowZero(entry.source_message_id, 0) === 1290;
|
|
2413
|
+
});
|
|
2414
|
+
push(
|
|
2415
|
+
"runner_human_opening_request_key_ignores_conversation_id_for_canonical_inbound",
|
|
2416
|
+
canonicalConversationVariantPrimaryClaim.ok === true
|
|
2417
|
+
&& (canonicalConversationVariantPeerClaim.ok === true || String(canonicalConversationVariantPeerClaim.reason || "") === "request_already_claimed")
|
|
2418
|
+
&& String(canonicalConversationVariantPrimaryClaim.requestKey || "") === String(canonicalConversationVariantPeerClaim.requestKey || "")
|
|
2419
|
+
&& canonicalConversationVariantRequests.length === 1,
|
|
2420
|
+
`primary=${String(canonicalConversationVariantPrimaryClaim.requestKey || "(none)")} peer=${String(canonicalConversationVariantPeerClaim.requestKey || "(none)")} peer_reason=${String(canonicalConversationVariantPeerClaim.reason || "(none)")} count=${canonicalConversationVariantRequests.length}`,
|
|
2421
|
+
);
|
|
2422
|
+
|
|
2423
|
+
const sharedDirectTakeoverBody = "@RyoAI_bot @RyoAI2_bot @RyoAI3_bot 같이 답해";
|
|
2424
|
+
const sharedDirectTakeoverRecordLead = {
|
|
2425
|
+
id: "comment-request-shared-direct-1",
|
|
2426
|
+
createdAt: "2026-04-01T06:20:00.000Z",
|
|
2427
|
+
updatedAt: "2026-04-01T06:20:00.000Z",
|
|
2428
|
+
parsedArchive: {
|
|
2429
|
+
kind: "telegram_message",
|
|
2430
|
+
chatID: "-100125",
|
|
2431
|
+
chatType: "supergroup",
|
|
2432
|
+
body: sharedDirectTakeoverBody,
|
|
2433
|
+
messageID: 1291,
|
|
2434
|
+
senderID: "7003",
|
|
2435
|
+
senderIsBot: false,
|
|
2436
|
+
occurredAt: "2026-04-01T06:20:00.000Z",
|
|
2437
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2438
|
+
},
|
|
2439
|
+
};
|
|
2440
|
+
const sharedDirectTakeoverLeadClaim = await claimRunnerRequestForHumanComment({
|
|
2441
|
+
normalizedRoute: sharedHumanRouteRyoai1,
|
|
2442
|
+
routeKey: sharedHumanRouteRyoai1Key,
|
|
2443
|
+
selectedRecord: sharedDirectTakeoverRecordLead,
|
|
2444
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2445
|
+
normalizedIntent: "discussion_request",
|
|
2446
|
+
authoritativeSourceMessageEnvelope: {
|
|
2447
|
+
chat_id: "-100125",
|
|
2448
|
+
message_id: 1291,
|
|
2449
|
+
sender_id: "7003",
|
|
2450
|
+
sender_is_bot: false,
|
|
2451
|
+
occurred_at: "2026-04-01T06:20:00.000Z",
|
|
2452
|
+
body: sharedDirectTakeoverBody,
|
|
2453
|
+
source_origin: "local_telegram_inbound",
|
|
2454
|
+
source_route_key: sharedHumanRouteRyoai1Key,
|
|
2455
|
+
source_bot_username: "ryoai_bot",
|
|
2456
|
+
},
|
|
2457
|
+
});
|
|
2458
|
+
const sharedDirectTakeoverCanonicalKey = buildArchivedInboundMessageKey({
|
|
2459
|
+
chatID: "-100125",
|
|
2460
|
+
messageID: 1291,
|
|
2461
|
+
messageThreadID: 0,
|
|
2462
|
+
kind: "telegram_message",
|
|
2463
|
+
senderID: "7003",
|
|
2464
|
+
senderIsBot: false,
|
|
2465
|
+
occurredAt: "2026-04-01T06:20:00.000Z",
|
|
2466
|
+
body: sharedDirectTakeoverBody,
|
|
2467
|
+
}).replace(/^human:/, "");
|
|
2468
|
+
const sharedDirectTakeoverState = loadBotRunnerState();
|
|
2469
|
+
saveBotRunnerState({
|
|
2470
|
+
...sharedDirectTakeoverState,
|
|
2471
|
+
requests: {
|
|
2472
|
+
...safeObject(sharedDirectTakeoverState.requests),
|
|
2473
|
+
[sharedDirectTakeoverLeadClaim.requestKey]: {
|
|
2474
|
+
...safeObject(safeObject(sharedDirectTakeoverState.requests)[sharedDirectTakeoverLeadClaim.requestKey]),
|
|
2475
|
+
canonical_human_message_key: sharedDirectTakeoverCanonicalKey,
|
|
2476
|
+
source_message_id: 1291,
|
|
2477
|
+
source_message_origin: "local_telegram_inbound",
|
|
2478
|
+
source_message_route_key: sharedHumanRouteRyoai1Key,
|
|
2479
|
+
source_message_bot_username: "ryoai_bot",
|
|
2480
|
+
source_message_envelope: {
|
|
2481
|
+
chat_id: "-100125",
|
|
2482
|
+
message_id: 1291,
|
|
2483
|
+
body: sharedDirectTakeoverBody,
|
|
2484
|
+
source_origin: "local_telegram_inbound",
|
|
2485
|
+
source_route_key: sharedHumanRouteRyoai1Key,
|
|
2486
|
+
source_bot_username: "ryoai_bot",
|
|
2487
|
+
},
|
|
2488
|
+
selected_bot_usernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2489
|
+
conversation_initial_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2490
|
+
conversation_allowed_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2491
|
+
conversation_intent_mode: "multi_bot_direct",
|
|
2492
|
+
execution_contract_type: "direct_result",
|
|
2493
|
+
execution_contract_targets: ["ryoai_bot"],
|
|
2494
|
+
next_expected_responders: ["ryoai2_bot", "ryoai3_bot"],
|
|
2495
|
+
status: "running",
|
|
2496
|
+
claimed_by_route: sharedHumanRouteRyoai1Key,
|
|
2497
|
+
authoritative_decision_bundle: {
|
|
2498
|
+
schema_version: "runner_conversation_decision.v1",
|
|
2499
|
+
decision_type: "reply_outcome",
|
|
2500
|
+
conversation_intent_mode: "multi_bot_direct",
|
|
2501
|
+
allowed_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2502
|
+
initial_responders: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2503
|
+
selected_bot_usernames: ["ryoai_bot"],
|
|
2504
|
+
allow_bot_to_bot: false,
|
|
2505
|
+
execution_contract_type: "direct_result",
|
|
2506
|
+
execution_contract_targets: ["ryoai_bot"],
|
|
2507
|
+
next_expected_responders: ["ryoai2_bot", "ryoai3_bot"],
|
|
2508
|
+
should_close_after_reply: false,
|
|
2509
|
+
turn_kind: "direct_reply",
|
|
2510
|
+
actionable_for_current_route: true,
|
|
2511
|
+
visible_handoff_required: false,
|
|
2512
|
+
visible_handoff_targets: [],
|
|
2513
|
+
reasoning_summary: "shared direct reply remains open for the remaining directly mentioned bots",
|
|
2514
|
+
},
|
|
2515
|
+
},
|
|
2516
|
+
},
|
|
2517
|
+
});
|
|
2518
|
+
const sharedDirectTakeoverRecordPeer = {
|
|
2519
|
+
id: "comment-request-shared-direct-2",
|
|
2520
|
+
createdAt: "2026-04-01T06:20:00.000Z",
|
|
2521
|
+
updatedAt: "2026-04-01T06:20:00.000Z",
|
|
2522
|
+
parsedArchive: {
|
|
2523
|
+
kind: "telegram_message",
|
|
2524
|
+
chatID: "-100125",
|
|
2525
|
+
chatType: "supergroup",
|
|
2526
|
+
body: sharedDirectTakeoverBody,
|
|
2527
|
+
messageID: 1291,
|
|
2528
|
+
senderID: "7003",
|
|
2529
|
+
senderIsBot: false,
|
|
2530
|
+
occurredAt: "2026-04-01T06:20:00.000Z",
|
|
2531
|
+
mentionUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2532
|
+
conversationID: "comment-request-shared-direct-1",
|
|
2533
|
+
},
|
|
2534
|
+
};
|
|
2535
|
+
const sharedDirectTakeoverPeerClaim = await claimRunnerRequestForHumanComment({
|
|
2536
|
+
normalizedRoute: sharedHumanRouteRyoai3,
|
|
2537
|
+
routeKey: sharedHumanRouteRyoai3Key,
|
|
2538
|
+
selectedRecord: sharedDirectTakeoverRecordPeer,
|
|
2539
|
+
selectedBotUsernames: ["ryoai_bot", "ryoai2_bot", "ryoai3_bot"],
|
|
2540
|
+
normalizedIntent: "discussion_request",
|
|
2541
|
+
authoritativeSourceMessageEnvelope: {
|
|
2542
|
+
chat_id: "-100125",
|
|
2543
|
+
message_id: 1291,
|
|
2544
|
+
sender_id: "7003",
|
|
2545
|
+
sender_is_bot: false,
|
|
2546
|
+
occurred_at: "2026-04-01T06:20:00.000Z",
|
|
2547
|
+
body: sharedDirectTakeoverBody,
|
|
2548
|
+
source_origin: "local_telegram_inbound",
|
|
2549
|
+
source_route_key: sharedHumanRouteRyoai3Key,
|
|
2550
|
+
source_bot_username: "ryoai3_bot",
|
|
2551
|
+
},
|
|
2552
|
+
});
|
|
2553
|
+
const sharedDirectTakeoverRequest = safeObject(
|
|
2554
|
+
safeObject(loadBotRunnerState().requests)[sharedDirectTakeoverLeadClaim.requestKey],
|
|
2555
|
+
);
|
|
2556
|
+
push(
|
|
2557
|
+
"runner_shared_human_direct_reply_allows_pending_route_takeover_without_rekeying",
|
|
2558
|
+
sharedDirectTakeoverLeadClaim.ok === true
|
|
2559
|
+
&& sharedDirectTakeoverPeerClaim.ok === true
|
|
2560
|
+
&& String(sharedDirectTakeoverPeerClaim.requestKey || "") === String(sharedDirectTakeoverLeadClaim.requestKey || "")
|
|
2561
|
+
&& String(sharedDirectTakeoverRequest.claimed_by_route || "") === sharedHumanRouteRyoai3Key
|
|
2562
|
+
&& String(sharedDirectTakeoverRequest.source_message_route_key || "") === sharedHumanRouteRyoai1Key
|
|
2563
|
+
&& String(safeObject(sharedDirectTakeoverRequest.source_message_envelope).source_route_key || "") === sharedHumanRouteRyoai1Key,
|
|
2564
|
+
`lead=${String(sharedDirectTakeoverLeadClaim.requestKey || "(none)")} peer=${String(sharedDirectTakeoverPeerClaim.requestKey || "(none)")} claimed_by=${String(sharedDirectTakeoverRequest.claimed_by_route || "(none)")} source_route=${String(sharedDirectTakeoverRequest.source_message_route_key || "(none)")}`,
|
|
2565
|
+
);
|
|
2566
|
+
|
|
2337
2567
|
const rootTaskRecord = {
|
|
2338
|
-
id: "comment-request-root-task-1",
|
|
2568
|
+
id: "comment-request-root-task-1",
|
|
2339
2569
|
createdAt: "2026-03-22T00:05:00.000Z",
|
|
2340
2570
|
updatedAt: "2026-03-22T00:05:00.000Z",
|
|
2341
2571
|
parsedArchive: {
|
|
@@ -17529,10 +17759,46 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
17529
17759
|
&& !Number(recoveredSourceEnvelope.message_id || 0),
|
|
17530
17760
|
`origin=${String(recoveryPatch.source_message_origin || "(none)")} route=${String(recoveryPatch.source_message_route_key || "(none)")} bot=${String(recoveryPatch.source_message_bot_username || "(none)")} message=${String(recoveredSourceEnvelope.message_id || "(none)")} thread=${String(recoveryPatch.source_message_thread_id || "(none)")}`,
|
|
17531
17761
|
);
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17762
|
+
|
|
17763
|
+
const runningRecoveryPatch = buildRunnerRequestRecoveryPatchFromRouteState(
|
|
17764
|
+
{
|
|
17765
|
+
routes: {
|
|
17766
|
+
[provenanceRouteKey]: {
|
|
17767
|
+
last_source_message_id: 780,
|
|
17768
|
+
last_action: "replied",
|
|
17769
|
+
},
|
|
17770
|
+
},
|
|
17771
|
+
},
|
|
17772
|
+
{
|
|
17773
|
+
request_key: "request-provenance-running-recovery",
|
|
17774
|
+
claimed_by_route: provenanceRouteKey,
|
|
17775
|
+
chat_id: "-100123",
|
|
17776
|
+
source_message_id: 780,
|
|
17777
|
+
status: "running",
|
|
17778
|
+
execution_contract_type: "direct_result",
|
|
17779
|
+
next_expected_responders: ["ryoai2_bot"],
|
|
17780
|
+
authoritative_decision_bundle: {
|
|
17781
|
+
schema_version: "runner_conversation_decision.v1",
|
|
17782
|
+
decision_type: "reply_outcome",
|
|
17783
|
+
conversation_intent_mode: "multi_bot_direct",
|
|
17784
|
+
execution_contract_type: "direct_result",
|
|
17785
|
+
next_expected_responders: ["ryoai2_bot"],
|
|
17786
|
+
should_close_after_reply: false,
|
|
17787
|
+
},
|
|
17788
|
+
},
|
|
17789
|
+
provenanceRouteKey,
|
|
17790
|
+
);
|
|
17791
|
+
push(
|
|
17792
|
+
"runner_request_recovery_keeps_running_requests_with_pending_responders",
|
|
17793
|
+
String(runningRecoveryPatch.status || "") === "running"
|
|
17794
|
+
&& !String(runningRecoveryPatch.completed_at || "").trim()
|
|
17795
|
+
&& !String(runningRecoveryPatch.closed_at || "").trim(),
|
|
17796
|
+
`status=${String(runningRecoveryPatch.status || "(none)")} completed_at=${String(runningRecoveryPatch.completed_at || "(none)")} closed_at=${String(runningRecoveryPatch.closed_at || "(none)")}`,
|
|
17797
|
+
);
|
|
17798
|
+
|
|
17799
|
+
saveBotRunnerState({
|
|
17800
|
+
routes: {
|
|
17801
|
+
[provenanceRouteKey]: {
|
|
17536
17802
|
active_request_key: "request-provenance-continuation",
|
|
17537
17803
|
last_source_message_id: 779,
|
|
17538
17804
|
recent_local_inbound_envelopes: {
|