metheus-governance-mcp-cli 0.2.214 → 0.2.216

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 CHANGED
@@ -2364,6 +2364,11 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
2364
2364
  ),
2365
2365
  ai_reply_generated_at: firstNonEmptyString([entry.ai_reply_generated_at, entry.aiReplyGeneratedAt]),
2366
2366
  ai_reply_preview: String(entry.ai_reply_preview || entry.aiReplyPreview || "").trim(),
2367
+ response_contract_validation_status: String(entry.response_contract_validation_status || entry.responseContractValidationStatus || "").trim().toLowerCase(),
2368
+ response_contract_validation_reason: String(entry.response_contract_validation_reason || entry.responseContractValidationReason || "").trim(),
2369
+ response_contract_validation_targets: ensureArray(entry.response_contract_validation_targets || entry.responseContractValidationTargets)
2370
+ .map((value) => normalizeTelegramMentionUsername(value))
2371
+ .filter(Boolean),
2367
2372
  delivery_status: String(entry.delivery_status || entry.deliveryStatus || "").trim().toLowerCase(),
2368
2373
  archive_status: String(entry.archive_status || entry.archiveStatus || "").trim().toLowerCase(),
2369
2374
  transport_error: String(entry.transport_error || entry.transportError || "").trim(),
@@ -3658,28 +3663,13 @@ function runnerRequestRequiresActionableContract(requestRaw) {
3658
3663
  const replyExpectation = String(request.conversation_reply_expectation || "").trim().toLowerCase();
3659
3664
  const executionContractType = String(request.execution_contract_type || "").trim().toLowerCase();
3660
3665
  const intentMode = String(request.conversation_intent_mode || "").trim().toLowerCase();
3661
- const intentType = String(
3662
- request.conversation_intent_type
3663
- || request.intent_type
3664
- || request.normalized_intent
3665
- || "",
3666
- ).trim().toLowerCase();
3667
- const hasExecutionIntent = [
3668
- "general_execution",
3669
- "ctxpack_mutation",
3670
- "workitem_mutation",
3671
- ].includes(intentType);
3672
3666
  if (request.execution_contract_actionable === true) {
3673
3667
  return true;
3674
3668
  }
3675
3669
  if (["delegation", "direct_result", "summary_request", "final_summary"].includes(executionContractType)) {
3676
3670
  return true;
3677
3671
  }
3678
- if (
3679
- intentMode === "single_bot"
3680
- && replyExpectation === "actionable"
3681
- && hasExecutionIntent
3682
- ) {
3672
+ if (intentMode === "single_bot" && replyExpectation === "actionable") {
3683
3673
  return true;
3684
3674
  }
3685
3675
  return false;
@@ -4495,6 +4485,9 @@ function markRunnerRequestLifecycle({
4495
4485
  aiReplyGenerated = false,
4496
4486
  aiReplyGeneratedAt = "",
4497
4487
  aiReplyPreview = "",
4488
+ responseContractValidationStatus = "",
4489
+ responseContractValidationReason = "",
4490
+ responseContractValidationTargets = [],
4498
4491
  deliveryStatus = "",
4499
4492
  archiveStatus = "",
4500
4493
  transportError = "",
@@ -4610,6 +4603,18 @@ function markRunnerRequestLifecycle({
4610
4603
  ? firstNonEmptyString([aiReplyGeneratedAt, existing.ai_reply_generated_at, nowISO])
4611
4604
  : String(existing.ai_reply_generated_at || "").trim(),
4612
4605
  ai_reply_preview: String(aiReplyPreview || existing.ai_reply_preview || "").trim(),
4606
+ response_contract_validation_status: String(
4607
+ responseContractValidationStatus || existing.response_contract_validation_status || "",
4608
+ ).trim().toLowerCase(),
4609
+ response_contract_validation_reason: String(
4610
+ responseContractValidationReason || existing.response_contract_validation_reason || "",
4611
+ ).trim(),
4612
+ response_contract_validation_targets: uniqueOrderedStrings(
4613
+ ensureArray(responseContractValidationTargets).length
4614
+ ? responseContractValidationTargets
4615
+ : existing.response_contract_validation_targets,
4616
+ normalizeTelegramMentionUsername,
4617
+ ),
4613
4618
  delivery_status: String(deliveryStatus || existing.delivery_status || "").trim().toLowerCase(),
4614
4619
  archive_status: String(archiveStatus || existing.archive_status || "").trim().toLowerCase(),
4615
4620
  transport_error: String(transportError || existing.transport_error || "").trim(),
@@ -8789,6 +8794,9 @@ async function processRunnerRouteOnce(route, runtime, mode, options = {}) {
8789
8794
  aiReplyGenerated: processed.result?.ai_reply_generated === true,
8790
8795
  aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
8791
8796
  aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
8797
+ responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
8798
+ responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
8799
+ responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
8792
8800
  deliveryStatus: String(processed.result?.delivery_status || "").trim(),
8793
8801
  archiveStatus: String(processed.result?.archive_status || "").trim(),
8794
8802
  transportError: String(processed.result?.transport_error || "").trim(),
@@ -11204,6 +11212,9 @@ async function runRunnerStartResolvedRoutes(routes, flags, options = {}) {
11204
11212
  aiReplyGenerated: processed.result?.ai_reply_generated === true,
11205
11213
  aiReplyGeneratedAt: String(processed.result?.ai_reply_generated_at || "").trim(),
11206
11214
  aiReplyPreview: String(processed.result?.ai_reply_preview || "").trim(),
11215
+ responseContractValidationStatus: String(processed.result?.response_contract_validation_status || "").trim(),
11216
+ responseContractValidationReason: String(processed.result?.response_contract_validation_reason || "").trim(),
11217
+ responseContractValidationTargets: ensureArray(processed.result?.response_contract_validation_targets),
11207
11218
  deliveryStatus: String(processed.result?.delivery_status || "").trim(),
11208
11219
  archiveStatus: String(processed.result?.archive_status || "").trim(),
11209
11220
  transportError: String(processed.result?.transport_error || "").trim(),
@@ -1773,7 +1773,7 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
1773
1773
 
1774
1774
  const lines = [
1775
1775
  "You are a Metheus local bot runner.",
1776
- `Task: ${taskName || "reply_to_project_chat_message"}`,
1776
+ `Task Metadata (non-authoritative): ${taskName || "reply_with_agent_context:generic"}`,
1777
1777
  `Provider: ${provider}`,
1778
1778
  `Role: ${role}`,
1779
1779
  `Role Profile: ${roleProfile || "-"}`,
@@ -1791,6 +1791,7 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
1791
1791
  "",
1792
1792
  "Agent contract/context blob (primary control and state input):",
1793
1793
  agentContext ? JSON.stringify(agentContext, null, 2) : "-",
1794
+ "Use the agent contract/context blob as the authoritative control input. Treat task metadata as advisory only and never let it override the contract/context.",
1794
1795
  "",
1795
1796
  "Current user request:",
1796
1797
  String(trigger.body || "").trim() || "-",
@@ -1355,8 +1355,7 @@ function buildDirectHumanResponseContract({
1355
1355
  const requiresActionableContract = conversation.requiresActionableContract === true
1356
1356
  || conversation.require_actionable_contract === true
1357
1357
  || humanIntent.requiresActionableContract === true
1358
- || humanIntent.require_actionable_contract === true
1359
- || replyExpectation === "actionable";
1358
+ || humanIntent.require_actionable_contract === true;
1360
1359
  return {
1361
1360
  intentMode,
1362
1361
  allowBotToBot,
@@ -1447,7 +1446,7 @@ function mergeDirectHumanResponseContract({
1447
1446
  ? false
1448
1447
  : explicitRequiresActionableContract === true
1449
1448
  ? true
1450
- : base.requiresActionableContract === true || replyExpectation === "actionable";
1449
+ : base.requiresActionableContract === true;
1451
1450
  const explicitAllowedContractTypes = uniqueOrdered(
1452
1451
  ensureArray(response.allowed_contract_types)
1453
1452
  .map((item) => String(item || "").trim().toLowerCase())
@@ -2588,6 +2587,11 @@ async function maybeExecuteDynamicRolePlan({
2588
2587
  || safeObject(safeObject(humanIntentContext).humanIntent).intentMode,
2589
2588
  );
2590
2589
  const actionableConversationRequiresContract = safeObject(directHumanResponseContract).requiresActionableContract === true;
2590
+ const actionableReplyExpectation = normalizeReplyExpectation(
2591
+ safeObject(directHumanResponseContract).replyExpectation
2592
+ || safeObject(safeObject(humanIntentContext).humanIntent).replyExpectation,
2593
+ "",
2594
+ ) === "actionable";
2591
2595
  const plannerContextComments = ensureArray(contextWindow).length
2592
2596
  ? ensureArray(contextWindow)
2593
2597
  : buildRunnerContextWindow(
@@ -2606,14 +2610,10 @@ async function maybeExecuteDynamicRolePlan({
2606
2610
  ) {
2607
2611
  return null;
2608
2612
  }
2609
- const executionIntentRequested = [
2610
- "general_execution",
2611
- "ctxpack_mutation",
2612
- "workitem_mutation",
2613
- ].includes(humanIntentType);
2614
2613
  const shouldPlanExecution = assignmentTasks.length > 0 || (
2615
2614
  triggerDecision.requiresDirectReply === true
2616
- && executionIntentRequested
2615
+ && humanIntentMode === "single_bot"
2616
+ && actionableReplyExpectation
2617
2617
  );
2618
2618
  if (!shouldPlanExecution) {
2619
2619
  return null;
@@ -5009,25 +5009,11 @@ export async function processRunnerSelectedRecord({
5009
5009
  const directHumanPeerMap = humanIntentContext?.peerMap instanceof Map
5010
5010
  ? humanIntentContext.peerMap
5011
5011
  : buildConversationPeerMap(bot, normalizedRoute, executionDeps);
5012
- const delegatedBotMentions = extractManagedPeerMentionSelectors(
5013
- String(aiResult.reply || "").trim(),
5014
- directHumanPeerMap,
5015
- currentBotSelector,
5016
- );
5017
5012
  const requiredDelegationTargets = uniqueOrdered(
5018
- (
5019
- delegatedBotMentions.length > 0
5020
- ? delegatedBotMentions
5021
- : requiresPeerDelegationContract
5022
- ? peerAllowedResponders
5023
- : []
5024
- )
5013
+ (requiresPeerDelegationContract ? peerAllowedResponders : [])
5025
5014
  .map((item) => normalizeMentionSelector(item))
5026
5015
  .filter(Boolean),
5027
5016
  );
5028
- if (delegatedBotMentions.length > 0) {
5029
- allowedActionableTypes = new Set(["delegation"]);
5030
- }
5031
5017
  if (requiresPeerDelegationContract) {
5032
5018
  allowedActionableTypes = new Set(["delegation"]);
5033
5019
  requiresActionableContract = true;
@@ -5037,97 +5023,24 @@ export async function processRunnerSelectedRecord({
5037
5023
  && executionContract.actionable === true
5038
5024
  && (!allowedActionableTypes.size || allowedActionableTypes.has(String(executionContract.type || "").trim().toLowerCase())),
5039
5025
  );
5040
- if (!requiresActionableContract && requiredDelegationTargets.length > 0) {
5041
- requiresActionableContract = true;
5042
- }
5043
- if (
5044
- !requiresActionableContract
5045
- && !hasValidActionableContract
5046
- && effectiveTriggerDecision.requiresDirectReply === true
5047
- && !conversationContext
5048
- && !safeObject(selectedRecord?.parsedArchive).senderIsBot
5049
- && typeof executionDeps?.auditDirectHumanReplyWithAI === "function"
5050
- ) {
5051
- const auditPeerMap = humanIntentContext?.peerMap instanceof Map
5052
- ? humanIntentContext.peerMap
5053
- : buildConversationPeerMap(bot, normalizedRoute, executionDeps);
5054
- try {
5055
- const audit = await executionDeps.auditDirectHumanReplyWithAI({
5056
- humanMessageText: String(safeObject(selectedRecord?.parsedArchive).body || "").trim(),
5057
- botReplyText: String(aiResult.reply || "").trim(),
5058
- currentBotUsername: String(bot?.username || bot?.name || "").trim(),
5059
- managedBots: buildConversationParticipantViews(Array.from(auditPeerMap.keys()), auditPeerMap),
5060
- workspaceDir: String(effectiveExecutionPlan.workspaceDir || process.cwd()).trim() || process.cwd(),
5061
- });
5062
- if (audit?.requires_actionable_contract === true && audit?.reply_satisfies_request !== true) {
5063
- requiresActionableContract = true;
5064
- }
5065
- } catch {}
5066
- }
5067
- if (requiresActionableContract && !hasValidActionableContract) {
5068
- const forcedContractPayload = {
5069
- ...aiPayload,
5070
- response_contract: {
5071
- ...effectiveResponseContractPayload,
5072
- allow_skip: false,
5073
- must_reply: true,
5074
- require_actionable_contract: true,
5075
- human_intent_mode: String(effectiveResponseContractPayload.human_intent_mode || "").trim(),
5076
- human_lead_bot: String(effectiveResponseContractPayload.human_lead_bot || "").trim(),
5077
- human_summary_bot: String(effectiveResponseContractPayload.human_summary_bot || "").trim(),
5078
- human_allowed_responders: ensureArray(effectiveResponseContractPayload.human_allowed_responders).length
5079
- ? ensureArray(effectiveResponseContractPayload.human_allowed_responders)
5080
- : uniqueOrdered([
5081
- currentBotSelector,
5082
- ...requiredDelegationTargets,
5083
- ].filter(Boolean)),
5084
- allow_bot_to_bot: requiredDelegationTargets.length > 0
5085
- || requiresPeerDelegationContract
5086
- || effectiveResponseContractPayload.human_intent_mode === "delegated_single_lead",
5087
- allowed_contract_types: requiredDelegationTargets.length > 0 || requiresPeerDelegationContract
5088
- ? ["delegation"]
5089
- : ensureArray(effectiveResponseContractPayload.allowed_contract_types).length
5090
- ? ensureArray(effectiveResponseContractPayload.allowed_contract_types)
5091
- : ["direct_result", "summary_request", "final_summary"],
5092
- required_delegation_targets: requiredDelegationTargets,
5093
- contract_hint: requiredDelegationTargets.length > 0
5094
- ? `Your previous reply mentioned ${requiredDelegationTargets.map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ")} without a delegation contract. Return contract.type=\"delegation\" with actionable=true, assignments for those exact bots, and matching next_responders.`
5095
- : "",
5096
- },
5026
+ const responseContractValidation = (() => {
5027
+ if (requiresActionableContract && !hasValidActionableContract) {
5028
+ return {
5029
+ ok: false,
5030
+ status: "missing_required_contract",
5031
+ reason: requiredDelegationTargets.length > 0
5032
+ ? `reply mentioned managed peer bot(s) ${requiredDelegationTargets.map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ")} without a matching delegation contract`
5033
+ : "reply did not produce a required execution contract",
5034
+ targets: requiredDelegationTargets,
5035
+ };
5036
+ }
5037
+ return {
5038
+ ok: true,
5039
+ status: "valid",
5040
+ reason: "",
5041
+ targets: requiredDelegationTargets,
5097
5042
  };
5098
- effectiveResponseContractPayload = safeObject(forcedContractPayload.response_contract);
5099
- allowedActionableTypes = new Set(
5100
- ensureArray(effectiveResponseContractPayload.allowed_contract_types)
5101
- .map((item) => String(item || "").trim().toLowerCase())
5102
- .filter(Boolean),
5103
- );
5104
- aiResult = await runRunnerAIExecution({
5105
- inputPayload: forcedContractPayload,
5106
- route: normalizedRoute,
5107
- destination,
5108
- executionPlan: effectiveExecutionPlan,
5109
- deps: executionDeps,
5110
- });
5111
- executionContract = conversationContext?.mode === "public_multi_bot"
5112
- ? normalizeConversationExecutionContract(
5113
- aiResult.contract,
5114
- {
5115
- allowedResponderSelectors: conversationContext.allowedResponderSelectors,
5116
- summaryBotUsername: conversationContext.summaryBotUsername,
5117
- },
5118
- { currentBotSelector, excludeCurrentTargetAssignments: true },
5119
- )
5120
- : normalizeResponseExecutionContract(
5121
- aiResult.contract,
5122
- effectiveResponseContractPayload,
5123
- { currentBotSelector },
5124
- );
5125
- hasValidActionableContract = Boolean(
5126
- executionContract
5127
- && executionContract.actionable === true
5128
- && (!allowedActionableTypes.size || allowedActionableTypes.has(String(executionContract.type || "").trim().toLowerCase())),
5129
- );
5130
- }
5043
+ })();
5131
5044
  directHumanResponseContract = mergeDirectHumanResponseContract({
5132
5045
  baseContract: directHumanResponseContract,
5133
5046
  responseContract: effectiveResponseContractPayload,
@@ -5153,56 +5066,6 @@ export async function processRunnerSelectedRecord({
5153
5066
  directHumanResponseContract,
5154
5067
  executionContract,
5155
5068
  });
5156
- if (requiresActionableContract) {
5157
- const validContract = hasValidActionableContract;
5158
- if (!validContract) {
5159
- const reason = requiredDelegationTargets.length > 0
5160
- ? `reply mentioned managed peer bot(s) ${requiredDelegationTargets.map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ")} without a required delegation contract`
5161
- : "reply did not produce an actionable execution contract";
5162
- const directHumanExecutionFailure = effectiveTriggerDecision.requiresDirectReply === true
5163
- && !conversationContext
5164
- && !safeObject(selectedRecord?.parsedArchive).senderIsBot;
5165
- saveRunnerRouteState(
5166
- routeKey,
5167
- buildRunnerRouteStateFromComment(selectedRecord, {
5168
- last_action: directHumanExecutionFailure
5169
- ? "execution_failed"
5170
- : conversationContext?.mode === "public_multi_bot"
5171
- ? "conversation_skipped"
5172
- : "policy_violation",
5173
- last_reason: reason,
5174
- last_conversation_id: String(conversationContext?.id || "").trim(),
5175
- last_conversation_stage: String(conversationContext?.stage || "").trim(),
5176
- last_workspace_dir: String(effectiveExecutionPlan.workspaceDir || "").trim(),
5177
- ...intentStatePatch,
5178
- }),
5179
- );
5180
- if (directHumanExecutionFailure) {
5181
- const failureDelivery = await maybeDeliverFailureReply(reason);
5182
- return {
5183
- kind: "error",
5184
- result: {
5185
- route_key: routeKey,
5186
- route_name: normalizedRoute.name,
5187
- outcome: "execution_failed",
5188
- detail: reason,
5189
- thread_id: archiveThread.threadID,
5190
- comment_id: selectedRecord.id,
5191
- trigger_kind: String(effectiveTriggerDecision.trigger || "").trim(),
5192
- failure_reply_sent: Boolean(failureDelivery),
5193
- },
5194
- };
5195
- }
5196
- return {
5197
- kind: "skipped",
5198
- skippedRecord: {
5199
- id: selectedRecord.id,
5200
- reason,
5201
- messageID: intFromRawAllowZero(selectedRecord?.parsedArchive?.messageID, 0),
5202
- },
5203
- };
5204
- }
5205
- }
5206
5069
  const normalizedExecutionContractType = String(executionContract?.type || "").trim().toLowerCase();
5207
5070
  const effectiveResolvedIntentType = normalizeHumanIntentType(
5208
5071
  directHumanResponseContract.intentType || resolvedIntentType,
@@ -5333,17 +5196,7 @@ export async function processRunnerSelectedRecord({
5333
5196
  },
5334
5197
  };
5335
5198
  }
5336
- if (
5337
- conversationContext?.mode === "public_multi_bot"
5338
- && String(conversationContext.intentMode || "").trim() === "delegated_single_lead"
5339
- && currentBotSelector
5340
- && currentBotSelector !== normalizeMentionSelector(conversationContext.leadBotUsername)
5341
- && (!executionContract || executionContract.actionable !== true)
5342
- ) {
5343
- executionContract = buildImplicitSummaryRequestContract(conversationContext, currentBotSelector);
5344
- }
5345
-
5346
- const replyToMessageID = aiResult.replyToMessageID > 0
5199
+ const replyToMessageID = aiResult.replyToMessageID > 0
5347
5200
  ? aiResult.replyToMessageID
5348
5201
  : intFromRawAllowZero(selectedRecord.parsedArchive?.messageID, 0);
5349
5202
  const sanitizedReplyText = sanitizeForcedDirectReplyText({
@@ -5469,6 +5322,9 @@ export async function processRunnerSelectedRecord({
5469
5322
  last_trigger: String(effectiveTriggerDecision.trigger || "").trim(),
5470
5323
  last_conversation_id: String(effectiveConversationContext?.id || "").trim(),
5471
5324
  last_conversation_stage: String(effectiveConversationContext?.stage || "").trim(),
5325
+ last_contract_validation_status: String(responseContractValidation.status || "").trim(),
5326
+ last_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
5327
+ last_contract_validation_targets: ensureArray(responseContractValidation.targets),
5472
5328
  last_speaker_bot_username: normalizeMentionSelector(bot?.username || bot?.name),
5473
5329
  last_workspace_dir: String(effectiveExecutionPlan.workspaceDir || "").trim(),
5474
5330
  ...intentStatePatch,
@@ -5507,6 +5363,9 @@ export async function processRunnerSelectedRecord({
5507
5363
  archive_status: "not_attempted",
5508
5364
  transport_error: transportError,
5509
5365
  archive_error: "",
5366
+ response_contract_validation_status: String(responseContractValidation.status || "").trim(),
5367
+ response_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
5368
+ response_contract_validation_targets: ensureArray(responseContractValidation.targets),
5510
5369
  reply_chars: String(sanitizedReplyText || "").length,
5511
5370
  execution_mode: effectiveExecutionPlan.mode,
5512
5371
  role_profile: effectiveExecutionPlan.roleProfileName,
@@ -5593,7 +5452,10 @@ export async function processRunnerSelectedRecord({
5593
5452
  last_reply_message_id: intFromRawAllowZero(
5594
5453
  safeObject(deliveryResult.delivery.body).result?.message_id ?? safeObject(deliveryResult.delivery.body).message_id,
5595
5454
  0,
5596
- ),
5455
+ ),
5456
+ last_contract_validation_status: String(responseContractValidation.status || "").trim(),
5457
+ last_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
5458
+ last_contract_validation_targets: ensureArray(responseContractValidation.targets),
5597
5459
  last_trigger: String(effectiveTriggerDecision.trigger || "").trim(),
5598
5460
  last_reason: effectiveConversationContext?.mode === "public_multi_bot"
5599
5461
  ? [
@@ -5691,6 +5553,9 @@ export async function processRunnerSelectedRecord({
5691
5553
  ai_reply_generated: true,
5692
5554
  ai_reply_generated_at: aiReplyGeneratedAt,
5693
5555
  ai_reply_preview: aiReplyPreview,
5556
+ response_contract_validation_status: String(responseContractValidation.status || "").trim(),
5557
+ response_contract_validation_reason: String(responseContractValidation.reason || "").trim(),
5558
+ response_contract_validation_targets: ensureArray(responseContractValidation.targets),
5694
5559
  delivery_status: deliveryResult.delivery.dryRun ? "dry_run" : "delivered",
5695
5560
  execution_mode: effectiveExecutionPlan.mode,
5696
5561
  role_profile: effectiveExecutionPlan.roleProfileName,
@@ -95,15 +95,8 @@ function buildRunnerTaskName(humanIntentType, humanIntentContract = null) {
95
95
  const normalizedIntentType = String(humanIntentType || "").trim().toLowerCase();
96
96
  const contract = safeObject(humanIntentContract);
97
97
  const executionContractType = String(contract.executionContractType || contract.execution_contract_type || "").trim().toLowerCase();
98
- if (normalizedIntentType === "status_query") return "answer_project_status_query";
99
- if (normalizedIntentType === "workspace_query") return "answer_project_workspace_query";
100
- if (normalizedIntentType === "bot_role_query") return "answer_project_bot_role_query";
101
- if (normalizedIntentType === "artifact_location_query") return "answer_project_artifact_location_query";
102
- if (normalizedIntentType === "small_talk") return "reply_to_project_chat_greeting";
103
- if (executionContractType) {
104
- return "reply_to_project_actionable_message";
105
- }
106
- return "reply_to_project_chat_message";
98
+ const legacyHint = executionContractType || normalizedIntentType || "generic";
99
+ return `reply_with_agent_context:${legacyHint}`;
107
100
  }
108
101
 
109
102
  export function evaluateTelegramRunnerTrigger(record, route, bot) {
@@ -184,8 +177,14 @@ export function buildRunnerInputPayload({
184
177
  const executionContractType = String(
185
178
  directHumanIntent.executionContractType || directHumanIntent.execution_contract_type || "",
186
179
  ).trim().toLowerCase();
180
+ const taskMetadata = buildRunnerTaskName(directHumanIntent.intentType, directHumanIntent);
187
181
  return {
188
- task: buildRunnerTaskName(directHumanIntent.intentType, directHumanIntent),
182
+ task: taskMetadata,
183
+ task_metadata: {
184
+ legacy_task_hint: taskMetadata,
185
+ intent_type: String(directHumanIntent.intentType || "").trim(),
186
+ execution_contract_type: executionContractType,
187
+ },
189
188
  project_id: String(route?.projectID || "").trim(),
190
189
  provider: String(route?.provider || "").trim(),
191
190
  role: String(bot?.role || route?.role || "").trim(),
@@ -4565,18 +4565,20 @@ export async function runSelftestRunnerScenarios(push, deps) {
4565
4565
  },
4566
4566
  });
4567
4567
  push(
4568
- "direct_human_public_delegate_reply_is_upgraded_to_actionable_contract",
4568
+ "direct_human_public_delegate_reply_records_missing_contract_without_fabrication",
4569
4569
  processed.kind === "replied"
4570
- && aiCalls >= 1
4570
+ && aiCalls === 1
4571
4571
  && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4572
4572
  && String(deliveredConversation[0]?.leadBotUsername || "") === "ryoai_bot"
4573
4573
  && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4574
4574
  && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4575
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation",
4576
- `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")} required_targets=${JSON.stringify(safeObject(forcedContractPayload?.response_contract).required_delegation_targets || [])}`,
4575
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4576
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract"
4577
+ && ensureArray(processed.result?.response_contract_validation_targets).includes("ryoai3_bot"),
4578
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")} targets=${JSON.stringify(processed.result?.response_contract_validation_targets || [])}`,
4577
4579
  );
4578
4580
  } catch (err) {
4579
- push("direct_human_public_delegate_reply_is_upgraded_to_actionable_contract", false, String(err?.message || err));
4581
+ push("direct_human_public_delegate_reply_records_missing_contract_without_fabrication", false, String(err?.message || err));
4580
4582
  }
4581
4583
 
4582
4584
  try {
@@ -4715,20 +4717,21 @@ export async function runSelftestRunnerScenarios(push, deps) {
4715
4717
  ],
4716
4718
  },
4717
4719
  });
4718
- push(
4719
- "direct_human_public_delegate_repairs_lead_bot_selector_for_archive_contract",
4720
- processed.kind === "replied"
4721
- && aiCalls >= 1
4722
- && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4723
- && String(deliveredConversation[0]?.leadBotUsername || "") === "ryoai_bot"
4724
- && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4725
- && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4726
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation",
4727
- `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} lead=${String(deliveredConversation[0]?.leadBotUsername || "(none)")} mode=${String(deliveredConversation[0]?.mode || "(none)")}`,
4728
- );
4729
- } catch (err) {
4730
- push("direct_human_public_delegate_repairs_lead_bot_selector_for_archive_contract", false, String(err?.message || err));
4731
- }
4720
+ push(
4721
+ "direct_human_public_delegate_preserves_lead_context_while_recording_missing_contract",
4722
+ processed.kind === "replied"
4723
+ && aiCalls === 1
4724
+ && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4725
+ && String(deliveredConversation[0]?.leadBotUsername || "") === "ryoai_bot"
4726
+ && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4727
+ && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4728
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4729
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract",
4730
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} lead=${String(deliveredConversation[0]?.leadBotUsername || "(none)")} mode=${String(deliveredConversation[0]?.mode || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")}`,
4731
+ );
4732
+ } catch (err) {
4733
+ push("direct_human_public_delegate_preserves_lead_context_while_recording_missing_contract", false, String(err?.message || err));
4734
+ }
4732
4735
 
4733
4736
  try {
4734
4737
  let aiCalls = 0;
@@ -4862,18 +4865,19 @@ export async function runSelftestRunnerScenarios(push, deps) {
4862
4865
  },
4863
4866
  });
4864
4867
  push(
4865
- "direct_human_public_delegate_fallback_uses_response_allowed_responders",
4868
+ "direct_human_public_delegate_records_allowed_responders_without_fabricated_contract",
4866
4869
  processed.kind === "replied"
4867
- && aiCalls >= 1
4870
+ && aiCalls === 1
4868
4871
  && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4869
4872
  && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4870
4873
  && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4871
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation",
4872
- `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} allowed=${JSON.stringify(deliveredConversation[0]?.allowedResponderSelectors || [])} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")}`,
4873
- );
4874
- } catch (err) {
4875
- push("direct_human_public_delegate_fallback_uses_response_allowed_responders", false, String(err?.message || err));
4876
- }
4874
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4875
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract",
4876
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} allowed=${JSON.stringify(deliveredConversation[0]?.allowedResponderSelectors || [])} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")}`,
4877
+ );
4878
+ } catch (err) {
4879
+ push("direct_human_public_delegate_records_allowed_responders_without_fabricated_contract", false, String(err?.message || err));
4880
+ }
4877
4881
 
4878
4882
  try {
4879
4883
  let aiCalls = 0;
@@ -5012,13 +5016,12 @@ export async function runSelftestRunnerScenarios(push, deps) {
5012
5016
  });
5013
5017
  push(
5014
5018
  "direct_human_public_peer_mention_rejects_summary_request_without_delegation",
5015
- processed.kind === "skipped"
5016
- && aiCalls >= 1
5017
- && deliveredConversation.length === 0
5018
- && ensureArray(safeObject(forcedContractPayload?.response_contract).required_delegation_targets).includes("ryoai3_bot")
5019
- && String(safeObject(forcedContractPayload?.response_contract).contract_hint || "").trim().length > 0
5020
- && String(processed.skippedRecord?.reason || "").includes("delegation contract"),
5021
- `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} required_targets=${JSON.stringify(safeObject(forcedContractPayload?.response_contract).required_delegation_targets || [])} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
5019
+ processed.kind === "replied"
5020
+ && aiCalls === 1
5021
+ && deliveredConversation.length === 1
5022
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract"
5023
+ && ensureArray(processed.result?.response_contract_validation_targets).includes("ryoai3_bot"),
5024
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} validation=${String(processed.result?.response_contract_validation_status || "(none)")} targets=${JSON.stringify(processed.result?.response_contract_validation_targets || [])}`,
5022
5025
  );
5023
5026
  } catch (err) {
5024
5027
  push("direct_human_public_peer_mention_rejects_summary_request_without_delegation", false, String(err?.message || err));
@@ -5152,12 +5155,10 @@ export async function runSelftestRunnerScenarios(push, deps) {
5152
5155
  });
5153
5156
  push(
5154
5157
  "delegated_single_lead_lead_opening_requires_delegation_contract_for_peer_followup",
5155
- processed.kind === "skipped"
5156
- && aiCalls === 2
5157
- && !String(deliveredText || "").trim()
5158
- && ensureArray(safeObject(forcedContractPayload?.response_contract).required_delegation_targets).includes("ryoai2_bot")
5159
- && ensureArray(safeObject(forcedContractPayload?.response_contract).required_delegation_targets).includes("ryoai3_bot")
5160
- && String(safeObject(forcedContractPayload?.response_contract).contract_hint || "").trim().length > 0,
5158
+ processed.kind === "replied"
5159
+ && aiCalls === 1
5160
+ && String(deliveredText || "").trim() === "I will analyze first and come back later."
5161
+ && !safeObject(forcedContractPayload?.response_contract).required_delegation_targets,
5161
5162
  `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} reply=${String(deliveredText || "(none)")} required_targets=${JSON.stringify(safeObject(forcedContractPayload?.response_contract).required_delegation_targets || [])} hint=${String(safeObject(forcedContractPayload?.response_contract).contract_hint || "(none)")}`,
5162
5163
  );
5163
5164
  } catch (err) {
@@ -5284,26 +5285,26 @@ export async function runSelftestRunnerScenarios(push, deps) {
5284
5285
  ],
5285
5286
  },
5286
5287
  });
5287
- push(
5288
- "single_bot_human_work_request_requires_actionable_contract",
5289
- processed.kind === "error"
5290
- && aiCalls === 2
5291
- && deliveryCalls === 1
5292
- && String(processed.result?.outcome || "") === "execution_failed"
5293
- && /actionable execution contract/i.test(String(processed.result?.detail || ""))
5294
- && /could not complete this request/i.test(deliveredText),
5295
- `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)")}`,
5296
- );
5288
+ push(
5289
+ "single_bot_human_work_request_requires_actionable_contract",
5290
+ processed.kind === "replied"
5291
+ && aiCalls === 1
5292
+ && deliveryCalls === 1
5293
+ && String(processed.result?.outcome || "") === "dry_run"
5294
+ && deliveredText === "I will inspect the project first and come back later.",
5295
+ `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)")}`,
5296
+ );
5297
5297
  } catch (err) {
5298
5298
  push("single_bot_human_work_request_requires_actionable_contract", false, String(err?.message || err));
5299
5299
  }
5300
5300
 
5301
- try {
5302
- let aiCalls = 0;
5303
- let deliveryCalls = 0;
5304
- let deliveredText = "";
5305
- let capturedFailureFacts = null;
5306
- const processed = await processRunnerSelectedRecord({
5301
+ try {
5302
+ let aiCalls = 0;
5303
+ let deliveryCalls = 0;
5304
+ let deliveredText = "";
5305
+ let capturedFailureFacts = null;
5306
+ const workspaceDir = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-runner-selftest-ai-failure-explainer-"));
5307
+ const processed = await processRunnerSelectedRecord({
5307
5308
  routeKey: "single-bot-human-work-request-ai-failure-explainer-key",
5308
5309
  normalizedRoute: normalizeRunnerRoute({
5309
5310
  name: "telegram-monitor-single-bot-human-work-request-ai-failure-explainer",
@@ -5368,7 +5369,7 @@ export async function runSelftestRunnerScenarios(push, deps) {
5368
5369
  permissionMode: "read_only",
5369
5370
  reasoningEffort: "low",
5370
5371
  },
5371
- workspaceDir: process.cwd(),
5372
+ workspaceDir,
5372
5373
  workspaceSource: "selftest",
5373
5374
  usedCommandFallback: false,
5374
5375
  },
@@ -5381,14 +5382,27 @@ export async function runSelftestRunnerScenarios(push, deps) {
5381
5382
  deps: {
5382
5383
  saveRunnerRouteState: () => {},
5383
5384
  startRunnerTypingHeartbeat: () => ({ async stop() {} }),
5384
- runRunnerAIExecution: async () => {
5385
- aiCalls += 1;
5386
- return {
5387
- skip: false,
5388
- reply: "I reviewed the request but did not produce a contract.",
5389
- contract: null,
5390
- };
5391
- },
5385
+ runRunnerAIExecution: async ({ inputPayload }) => {
5386
+ aiCalls += 1;
5387
+ const stepRole = String(inputPayload?.execution_step?.role || "").trim();
5388
+ if (stepRole === "monitor") {
5389
+ return {
5390
+ skip: false,
5391
+ reply: "Inspected the implementation guide request.",
5392
+ };
5393
+ }
5394
+ if (stepRole === "worker") {
5395
+ return {
5396
+ skip: false,
5397
+ reply: "Started the implementation guide update.",
5398
+ artifacts: [],
5399
+ };
5400
+ }
5401
+ return {
5402
+ skip: false,
5403
+ reply: "Preparing the implementation guide update.",
5404
+ };
5405
+ },
5392
5406
  explainExecutionFailureWithAI: ({ failureFacts }) => {
5393
5407
  capturedFailureFacts = safeObject(failureFacts);
5394
5408
  return {
@@ -5407,7 +5421,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
5407
5421
  },
5408
5422
  serializeRunnerTriggerPolicy: (value) => value,
5409
5423
  serializeRunnerArchivePolicy: (value) => value,
5410
- buildRunnerExecutionDeps: () => ({
5424
+ buildRunnerExecutionDeps: () => ({
5425
+ validateWorkspaceArtifacts,
5411
5426
  analyzeHumanConversationIntentWithAI: async () => ({
5412
5427
  mode: "single_bot",
5413
5428
  lead_bot: "ryoai_bot",
@@ -5417,9 +5432,36 @@ export async function runSelftestRunnerScenarios(push, deps) {
5417
5432
  summary_bot: "",
5418
5433
  allow_bot_to_bot: false,
5419
5434
  reply_expectation: "actionable",
5420
- intent_type: "ctxpack_mutation",
5435
+ intent_type: "general_execution",
5421
5436
  }),
5422
- }),
5437
+ planRoleExecutionWithAI: async () => ({
5438
+ requiresExecution: true,
5439
+ summaryRole: "monitor",
5440
+ steps: [
5441
+ { role: "monitor", goal: "Inspect request" },
5442
+ { role: "worker", goal: "Update implementation guide", artifactsRequired: true },
5443
+ ],
5444
+ }),
5445
+ resolveRunnerExecutionPlanForRole: (_route, _bot, roleName) => ({
5446
+ mode: "role_profile",
5447
+ roleProfileName: String(roleName || "").trim(),
5448
+ roleProfile: {
5449
+ client: "sample",
5450
+ model: "",
5451
+ permissionMode: String(roleName || "").trim() === "worker" ? "workspace_write" : "read_only",
5452
+ reasoningEffort: "low",
5453
+ },
5454
+ workspaceDir,
5455
+ workspaceSource: "selftest",
5456
+ usedCommandFallback: false,
5457
+ }),
5458
+ loadBotRunnerConfig: () => ({
5459
+ roleProfiles: {},
5460
+ botBindings: {},
5461
+ routes: [],
5462
+ projectMappings: {},
5463
+ }),
5464
+ }),
5423
5465
  buildRunnerDeliveryDeps: () => ({}),
5424
5466
  buildRunnerRuntimeDeps: () => ({}),
5425
5467
  resolveConversationPeerBots: () => [
@@ -5433,8 +5475,8 @@ export async function runSelftestRunnerScenarios(push, deps) {
5433
5475
  && aiCalls >= 1
5434
5476
  && deliveryCalls === 1
5435
5477
  && deliveredText === "AI failure summary"
5436
- && String(capturedFailureFacts?.error_type || "") === "missing_actionable_contract"
5437
- && String(capturedFailureFacts?.stage || "") === "execution_contract",
5478
+ && String(capturedFailureFacts?.error_type || "") === "artifact_validation_failed"
5479
+ && String(capturedFailureFacts?.stage || "") === "artifact_validation",
5438
5480
  `kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} ai_calls=${aiCalls} delivery_calls=${deliveryCalls} delivered=${deliveredText} failure_type=${String(capturedFailureFacts?.error_type || "(none)")} stage=${String(capturedFailureFacts?.stage || "(none)")}`,
5439
5481
  );
5440
5482
  } catch (err) {
@@ -5694,17 +5736,17 @@ export async function runSelftestRunnerScenarios(push, deps) {
5694
5736
  ],
5695
5737
  },
5696
5738
  });
5697
- push(
5698
- "single_bot_human_request_guardrail_audit_upgrades_to_actionable",
5699
- processed.kind === "error"
5700
- && aiCalls === 2
5701
- && auditCalls === 1
5702
- && deliveryCalls === 1
5703
- && String(processed.result?.outcome || "") === "execution_failed"
5704
- && /actionable execution contract/i.test(String(processed.result?.detail || ""))
5705
- && /could not complete this request/i.test(deliveredText),
5706
- `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)")}`,
5707
- );
5739
+ push(
5740
+ "single_bot_human_request_guardrail_audit_upgrades_to_actionable",
5741
+ processed.kind === "replied"
5742
+ && aiCalls === 1
5743
+ && auditCalls === 0
5744
+ && deliveryCalls === 1
5745
+ && String(processed.result?.outcome || "") === "dry_run"
5746
+ && String(processed.result?.response_contract_validation_status || "") === "valid"
5747
+ && String(deliveredText || "").trim().length > 0,
5748
+ `kind=${String(processed.kind || "(none)")} outcome=${String(processed.result?.outcome || "(none)")} ai_calls=${aiCalls} audit_calls=${auditCalls} delivery_calls=${deliveryCalls} delivered=${deliveredText} validation=${String(processed.result?.response_contract_validation_status || "(none)")}`,
5749
+ );
5708
5750
  } catch (err) {
5709
5751
  push("single_bot_human_request_guardrail_audit_upgrades_to_actionable", false, String(err?.message || err));
5710
5752
  }
@@ -9305,13 +9347,13 @@ export async function runSelftestRunnerScenarios(push, deps) {
9305
9347
  ],
9306
9348
  },
9307
9349
  });
9308
- push(
9309
- "delegated_single_lead_peer_to_peer_reply_reaches_ai_decision",
9310
- processed.kind === "replied"
9311
- && aiCalls === 1
9312
- && String(processed.result?.execution_contract_type || "") === "summary_request",
9313
- `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} contract=${String(processed.result?.execution_contract_type || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
9314
- );
9350
+ push(
9351
+ "delegated_single_lead_peer_to_peer_reply_reaches_ai_decision",
9352
+ processed.kind === "replied"
9353
+ && aiCalls === 1
9354
+ && !processed.skippedRecord,
9355
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} contract=${String(processed.result?.execution_contract_type || "(none)")} reason=${String(processed.skippedRecord?.reason || "(none)")}`,
9356
+ );
9315
9357
  } catch (err) {
9316
9358
  push("delegated_single_lead_peer_to_peer_reply_reaches_ai_decision", false, String(err?.message || err));
9317
9359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.214",
3
+ "version": "0.2.216",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [