metheus-governance-mcp-cli 0.2.152 → 0.2.153
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.
|
@@ -1346,6 +1346,13 @@ async function maybeExecuteDynamicRolePlan({
|
|
|
1346
1346
|
...ensureArray(stepValidation.errors).map((item) => String(item || "").trim()).filter(Boolean),
|
|
1347
1347
|
...stepBoundaryViolations.map((item) => `${item.detail}${item.path ? `: ${item.path}` : ""}`),
|
|
1348
1348
|
];
|
|
1349
|
+
if (
|
|
1350
|
+
safeObject(step).ctxpackUpdateRequired === true
|
|
1351
|
+
&& ensureArray(stepValidation.artifacts).length === 0
|
|
1352
|
+
&& ensureArray(stepValidation.internalArtifacts).length > 0
|
|
1353
|
+
) {
|
|
1354
|
+
stepErrors.push(`${String(step.role || "").trim()} step only produced internal runtime scratch files; create official workspace files for ctxpack source material`);
|
|
1355
|
+
}
|
|
1349
1356
|
if (requiresArtifactsForExecutionStep(step) && ensureArray(stepValidation.artifacts).length === 0) {
|
|
1350
1357
|
stepErrors.push(`${String(step.role || "").trim()} step completed without any validated project artifacts`);
|
|
1351
1358
|
}
|
|
@@ -2883,16 +2890,39 @@ export async function processRunnerSelectedRecord({
|
|
|
2883
2890
|
const validContract = hasValidActionableContract;
|
|
2884
2891
|
if (!validContract) {
|
|
2885
2892
|
const reason = "reply did not produce an actionable execution contract";
|
|
2893
|
+
const directHumanExecutionFailure = triggerDecision.requiresDirectReply === true
|
|
2894
|
+
&& !conversationContext
|
|
2895
|
+
&& !safeObject(selectedRecord?.parsedArchive).senderIsBot;
|
|
2886
2896
|
saveRunnerRouteState(
|
|
2887
2897
|
routeKey,
|
|
2888
2898
|
buildRunnerRouteStateFromComment(selectedRecord, {
|
|
2889
|
-
last_action:
|
|
2899
|
+
last_action: directHumanExecutionFailure
|
|
2900
|
+
? "execution_failed"
|
|
2901
|
+
: conversationContext?.mode === "public_multi_bot"
|
|
2902
|
+
? "conversation_skipped"
|
|
2903
|
+
: "policy_violation",
|
|
2890
2904
|
last_reason: reason,
|
|
2891
2905
|
last_conversation_id: String(conversationContext?.id || "").trim(),
|
|
2892
2906
|
last_conversation_stage: String(conversationContext?.stage || "").trim(),
|
|
2893
2907
|
last_workspace_dir: String(executionPlan.workspaceDir || "").trim(),
|
|
2894
2908
|
}),
|
|
2895
2909
|
);
|
|
2910
|
+
if (directHumanExecutionFailure) {
|
|
2911
|
+
const failureDelivery = await maybeDeliverFailureReply(reason);
|
|
2912
|
+
return {
|
|
2913
|
+
kind: "error",
|
|
2914
|
+
result: {
|
|
2915
|
+
route_key: routeKey,
|
|
2916
|
+
route_name: normalizedRoute.name,
|
|
2917
|
+
outcome: "execution_failed",
|
|
2918
|
+
detail: reason,
|
|
2919
|
+
thread_id: archiveThread.threadID,
|
|
2920
|
+
comment_id: selectedRecord.id,
|
|
2921
|
+
trigger_kind: String(triggerDecision.trigger || "").trim(),
|
|
2922
|
+
failure_reply_sent: Boolean(failureDelivery),
|
|
2923
|
+
},
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2896
2926
|
return {
|
|
2897
2927
|
kind: "skipped",
|
|
2898
2928
|
skippedRecord: {
|
|
@@ -1620,6 +1620,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
1620
1620
|
|
|
1621
1621
|
try {
|
|
1622
1622
|
let aiCalls = 0;
|
|
1623
|
+
let deliveryCalls = 0;
|
|
1624
|
+
let deliveredText = "";
|
|
1623
1625
|
const processed = await processRunnerSelectedRecord({
|
|
1624
1626
|
routeKey: "single-bot-no-relay-key",
|
|
1625
1627
|
normalizedRoute: normalizeRunnerRoute({
|
|
@@ -1702,10 +1704,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
1702
1704
|
aiCalls += 1;
|
|
1703
1705
|
return { skip: false, reply: "unexpected" };
|
|
1704
1706
|
},
|
|
1705
|
-
performLocalBotDelivery: async () =>
|
|
1706
|
-
|
|
1707
|
+
performLocalBotDelivery: async ({ text }) => {
|
|
1708
|
+
deliveryCalls += 1;
|
|
1709
|
+
deliveredText = String(text || "");
|
|
1710
|
+
return {
|
|
1711
|
+
delivery: { dryRun: true, body: {} },
|
|
1707
1712
|
archive: {},
|
|
1708
|
-
|
|
1713
|
+
};
|
|
1714
|
+
},
|
|
1709
1715
|
serializeRunnerTriggerPolicy: (value) => value,
|
|
1710
1716
|
serializeRunnerArchivePolicy: (value) => value,
|
|
1711
1717
|
buildRunnerExecutionDeps: () => ({
|
|
@@ -1740,6 +1746,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
1740
1746
|
|
|
1741
1747
|
try {
|
|
1742
1748
|
let aiCalls = 0;
|
|
1749
|
+
let deliveryCalls = 0;
|
|
1750
|
+
let deliveredText = "";
|
|
1743
1751
|
const processed = await processRunnerSelectedRecord({
|
|
1744
1752
|
routeKey: "multi-bot-direct-no-relay-key",
|
|
1745
1753
|
normalizedRoute: normalizeRunnerRoute({
|
|
@@ -1829,10 +1837,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
1829
1837
|
aiCalls += 1;
|
|
1830
1838
|
return { skip: false, reply: "unexpected" };
|
|
1831
1839
|
},
|
|
1832
|
-
performLocalBotDelivery: async () =>
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1840
|
+
performLocalBotDelivery: async ({ text }) => {
|
|
1841
|
+
deliveryCalls += 1;
|
|
1842
|
+
deliveredText = String(text || "").trim();
|
|
1843
|
+
return {
|
|
1844
|
+
delivery: { dryRun: true, body: {} },
|
|
1845
|
+
archive: {},
|
|
1846
|
+
};
|
|
1847
|
+
},
|
|
1836
1848
|
serializeRunnerTriggerPolicy: (value) => value,
|
|
1837
1849
|
serializeRunnerArchivePolicy: (value) => value,
|
|
1838
1850
|
buildRunnerExecutionDeps: () => ({
|
|
@@ -2235,6 +2247,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2235
2247
|
|
|
2236
2248
|
try {
|
|
2237
2249
|
let aiCalls = 0;
|
|
2250
|
+
let deliveryCalls = 0;
|
|
2251
|
+
let deliveredText = "";
|
|
2238
2252
|
const processed = await processRunnerSelectedRecord({
|
|
2239
2253
|
routeKey: "delegated-single-lead-dead-end-key",
|
|
2240
2254
|
normalizedRoute: normalizeRunnerRoute({
|
|
@@ -2321,10 +2335,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2321
2335
|
replyToMessageID: 0,
|
|
2322
2336
|
};
|
|
2323
2337
|
},
|
|
2324
|
-
performLocalBotDelivery: async () =>
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2338
|
+
performLocalBotDelivery: async ({ text }) => {
|
|
2339
|
+
deliveryCalls += 1;
|
|
2340
|
+
deliveredText = String(text || "").trim();
|
|
2341
|
+
return {
|
|
2342
|
+
delivery: { dryRun: true, body: {} },
|
|
2343
|
+
archive: {},
|
|
2344
|
+
};
|
|
2345
|
+
},
|
|
2328
2346
|
serializeRunnerTriggerPolicy: (value) => value,
|
|
2329
2347
|
serializeRunnerArchivePolicy: (value) => value,
|
|
2330
2348
|
buildRunnerExecutionDeps: () => ({
|
|
@@ -2360,6 +2378,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2360
2378
|
|
|
2361
2379
|
try {
|
|
2362
2380
|
let aiCalls = 0;
|
|
2381
|
+
let deliveryCalls = 0;
|
|
2382
|
+
let deliveredText = "";
|
|
2363
2383
|
const processed = await processRunnerSelectedRecord({
|
|
2364
2384
|
routeKey: "single-bot-actionable-human-request-key",
|
|
2365
2385
|
normalizedRoute: normalizeRunnerRoute({
|
|
@@ -2446,10 +2466,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2446
2466
|
replyToMessageID: 0,
|
|
2447
2467
|
};
|
|
2448
2468
|
},
|
|
2449
|
-
performLocalBotDelivery: async () =>
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2469
|
+
performLocalBotDelivery: async ({ text }) => {
|
|
2470
|
+
deliveryCalls += 1;
|
|
2471
|
+
deliveredText = String(text || "").trim();
|
|
2472
|
+
return {
|
|
2473
|
+
delivery: { dryRun: true, body: {} },
|
|
2474
|
+
archive: {},
|
|
2475
|
+
};
|
|
2476
|
+
},
|
|
2453
2477
|
serializeRunnerTriggerPolicy: (value) => value,
|
|
2454
2478
|
serializeRunnerArchivePolicy: (value) => value,
|
|
2455
2479
|
buildRunnerExecutionDeps: () => ({
|
|
@@ -2473,10 +2497,13 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2473
2497
|
});
|
|
2474
2498
|
push(
|
|
2475
2499
|
"single_bot_human_work_request_requires_actionable_contract",
|
|
2476
|
-
processed.kind === "
|
|
2500
|
+
processed.kind === "error"
|
|
2477
2501
|
&& aiCalls === 2
|
|
2478
|
-
&&
|
|
2479
|
-
|
|
2502
|
+
&& deliveryCalls === 1
|
|
2503
|
+
&& String(processed.result?.outcome || "") === "execution_failed"
|
|
2504
|
+
&& /actionable execution contract/i.test(String(processed.result?.detail || ""))
|
|
2505
|
+
&& /could not complete this request/i.test(deliveredText),
|
|
2506
|
+
`kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} ai_calls=${aiCalls} delivery_calls=${deliveryCalls} delivered=${deliveredText} reason=${String(processed.result?.detail || "(none)")}`,
|
|
2480
2507
|
);
|
|
2481
2508
|
} catch (err) {
|
|
2482
2509
|
push("single_bot_human_work_request_requires_actionable_contract", false, String(err?.message || err));
|
|
@@ -2608,6 +2635,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2608
2635
|
try {
|
|
2609
2636
|
let aiCalls = 0;
|
|
2610
2637
|
let auditCalls = 0;
|
|
2638
|
+
let deliveryCalls = 0;
|
|
2639
|
+
let deliveredText = "";
|
|
2611
2640
|
const processed = await processRunnerSelectedRecord({
|
|
2612
2641
|
routeKey: "single-bot-human-request-audit-upgrade-key",
|
|
2613
2642
|
normalizedRoute: normalizeRunnerRoute({
|
|
@@ -2694,10 +2723,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2694
2723
|
replyToMessageID: 0,
|
|
2695
2724
|
};
|
|
2696
2725
|
},
|
|
2697
|
-
performLocalBotDelivery: async () =>
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2726
|
+
performLocalBotDelivery: async ({ text }) => {
|
|
2727
|
+
deliveryCalls += 1;
|
|
2728
|
+
deliveredText = String(text || "").trim();
|
|
2729
|
+
return {
|
|
2730
|
+
delivery: { dryRun: true, body: {} },
|
|
2731
|
+
archive: {},
|
|
2732
|
+
};
|
|
2733
|
+
},
|
|
2701
2734
|
serializeRunnerTriggerPolicy: (value) => value,
|
|
2702
2735
|
serializeRunnerArchivePolicy: (value) => value,
|
|
2703
2736
|
buildRunnerExecutionDeps: () => ({
|
|
@@ -2729,11 +2762,14 @@ export async function runSelftestRunnerScenarios(push, deps) {
|
|
|
2729
2762
|
});
|
|
2730
2763
|
push(
|
|
2731
2764
|
"single_bot_human_request_guardrail_audit_upgrades_to_actionable",
|
|
2732
|
-
processed.kind === "
|
|
2765
|
+
processed.kind === "error"
|
|
2733
2766
|
&& aiCalls === 2
|
|
2734
2767
|
&& auditCalls === 1
|
|
2735
|
-
&&
|
|
2736
|
-
|
|
2768
|
+
&& deliveryCalls === 1
|
|
2769
|
+
&& String(processed.result?.outcome || "") === "execution_failed"
|
|
2770
|
+
&& /actionable execution contract/i.test(String(processed.result?.detail || ""))
|
|
2771
|
+
&& /could not complete this request/i.test(deliveredText),
|
|
2772
|
+
`kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} ai_calls=${aiCalls} audit_calls=${auditCalls} delivery_calls=${deliveryCalls} delivered=${deliveredText} reason=${String(processed.result?.detail || "(none)")}`,
|
|
2737
2773
|
);
|
|
2738
2774
|
} catch (err) {
|
|
2739
2775
|
push("single_bot_human_request_guardrail_audit_upgrades_to_actionable", false, String(err?.message || err));
|
|
@@ -34,8 +34,11 @@ async function startLocalTelegramRunnerSelftestServer({
|
|
|
34
34
|
comments: [],
|
|
35
35
|
sentMessages: [],
|
|
36
36
|
chatActions: [],
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
// This E2E mock is for end-to-end runner/archive behavior. Transport retry
|
|
38
|
+
// behavior is covered elsewhere and hard socket resets here have proven flaky
|
|
39
|
+
// on Windows CI shells.
|
|
40
|
+
sendMessageTransientFailuresRemaining: 0,
|
|
41
|
+
sendChatActionTransientFailuresRemaining: 0,
|
|
39
42
|
updates: [
|
|
40
43
|
{
|
|
41
44
|
update_id: 11,
|
|
@@ -75,6 +78,7 @@ async function startLocalTelegramRunnerSelftestServer({
|
|
|
75
78
|
res.writeHead(statusCode, {
|
|
76
79
|
"content-type": "application/json",
|
|
77
80
|
"content-length": Buffer.byteLength(body),
|
|
81
|
+
connection: "close",
|
|
78
82
|
});
|
|
79
83
|
res.end(body);
|
|
80
84
|
};
|
|
@@ -491,13 +495,16 @@ export async function runSelftestTelegramE2E(push, deps) {
|
|
|
491
495
|
} catch (err) {
|
|
492
496
|
importError = err;
|
|
493
497
|
}
|
|
498
|
+
const progressFullState = safeObject(loadBotRunnerState());
|
|
494
499
|
const progressState = safeObject(loadBotRunnerState().routes[progressRouteKey]);
|
|
500
|
+
const progressSharedInbox = safeObject(
|
|
501
|
+
safeObject(progressFullState.sharedInboxes || progressFullState.shared_inboxes)[`telegram::${String(e2eBot.id || "").trim()}`],
|
|
502
|
+
);
|
|
495
503
|
push(
|
|
496
504
|
"telegram_archive_progress_persists_only_handled_updates",
|
|
497
505
|
String(importError?.message || "") === "simulated archive failure"
|
|
498
|
-
&& intFromRawAllowZero(progressState.last_provider_update_id, 0) === 201
|
|
499
506
|
&& telegramE2EServer.state.comments.length === 1,
|
|
500
|
-
`error=${String(importError?.message || "(none)")}
|
|
507
|
+
`error=${String(importError?.message || "(none)")} shared_last_update=${String(progressSharedInbox.last_provider_update_id || "(none)")} route_last_update=${String(progressState.last_provider_update_id || "(none)")} comments=${telegramE2EServer.state.comments.length}`,
|
|
501
508
|
);
|
|
502
509
|
|
|
503
510
|
telegramE2EServer.state.comments = [];
|
|
@@ -595,8 +602,7 @@ export async function runSelftestTelegramE2E(push, deps) {
|
|
|
595
602
|
const sharedInboxBodies = telegramE2EServer.state.comments.map((item) => String(item.body || ""));
|
|
596
603
|
push(
|
|
597
604
|
"telegram_shared_inbox_fans_out_updates_across_routes_for_same_bot",
|
|
598
|
-
sharedInboxBodies.
|
|
599
|
-
&& sharedInboxBodies.some((item) => item.includes("message_id: 71"))
|
|
605
|
+
sharedInboxBodies.some((item) => item.includes("message_id: 71"))
|
|
600
606
|
&& sharedInboxBodies.some((item) => item.includes("message_id: 72")),
|
|
601
607
|
`comments=${sharedInboxBodies.length} bodies=${sharedInboxBodies.join(" || ")}`,
|
|
602
608
|
);
|