metheus-governance-mcp-cli 0.2.280 → 0.2.282

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
@@ -3111,20 +3111,25 @@ function normalizeBotRunnerRequests(rawRequests, nowMs = Date.now()) {
3111
3111
  entry.sourceMessageBotUsername,
3112
3112
  ]),
3113
3113
  });
3114
- normalized[requestKey] = {
3115
- request_key: requestKey,
3116
- project_id: String(entry.project_id || entry.projectID || "").trim(),
3117
- provider: String(entry.provider || "").trim(),
3118
- chat_id: firstNonEmptyString([
3119
- entry.chat_id,
3120
- entry.chatID,
3121
- normalizedSourceMessageEnvelope.chat_id,
3122
- ]),
3123
- source_message_id: intFromRawAllowZero(
3124
- entry.source_message_id
3125
- || entry.sourceMessageID
3126
- || normalizedSourceMessageEnvelope.message_id,
3127
- 0,
3114
+ normalized[requestKey] = {
3115
+ request_key: requestKey,
3116
+ project_id: String(entry.project_id || entry.projectID || "").trim(),
3117
+ provider: String(entry.provider || "").trim(),
3118
+ chat_id: firstNonEmptyString([
3119
+ entry.chat_id,
3120
+ entry.chatID,
3121
+ normalizedSourceMessageEnvelope.chat_id,
3122
+ ]),
3123
+ canonical_human_message_key: firstNonEmptyString([
3124
+ entry.canonical_human_message_key,
3125
+ entry.canonicalHumanMessageKey,
3126
+ normalizedSourceMessageEnvelope.canonical_human_message_key,
3127
+ ]),
3128
+ source_message_id: intFromRawAllowZero(
3129
+ entry.source_message_id
3130
+ || entry.sourceMessageID
3131
+ || normalizedSourceMessageEnvelope.message_id,
3132
+ 0,
3128
3133
  ) || undefined,
3129
3134
  source_message_thread_id: intFromRawAllowZero(
3130
3135
  entry.source_message_thread_id
@@ -3813,18 +3818,35 @@ function shouldBypassRunnerStartupLoopForContractFollowup({
3813
3818
  return true;
3814
3819
  }
3815
3820
 
3816
- function findRunnerRequestsForMessageID(state, normalizedRoute, selectors = {}) {
3817
- const chatID = String(selectors.chatID || "").trim();
3818
- const messageID = intFromRawAllowZero(selectors.messageID, 0);
3819
- if (!chatID || messageID <= 0) {
3820
- return [];
3821
- }
3822
- return findRunnerRequestsForScope(state, normalizedRoute, { chatID })
3823
- .filter((entry) => (
3824
- intFromRawAllowZero(entry.source_message_id, 0) === messageID
3825
- || intFromRawAllowZero(entry.last_source_message_id, 0) === messageID
3826
- ));
3827
- }
3821
+ function findRunnerRequestsForMessageID(state, normalizedRoute, selectors = {}) {
3822
+ const chatID = String(selectors.chatID || "").trim();
3823
+ const messageID = intFromRawAllowZero(selectors.messageID, 0);
3824
+ const canonicalHumanMessageKey = String(selectors.canonicalHumanMessageKey || "").trim();
3825
+ if (!chatID || (messageID <= 0 && !canonicalHumanMessageKey)) {
3826
+ return [];
3827
+ }
3828
+ return findRunnerRequestsForScope(state, normalizedRoute, { chatID })
3829
+ .filter((entryRaw) => {
3830
+ const entry = safeObject(entryRaw);
3831
+ if (canonicalHumanMessageKey) {
3832
+ const requestCanonicalHumanMessageKey = firstNonEmptyString([
3833
+ entry.canonical_human_message_key,
3834
+ safeObject(entry.source_message_envelope).canonical_human_message_key,
3835
+ buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
3836
+ ]);
3837
+ if (requestCanonicalHumanMessageKey === canonicalHumanMessageKey) {
3838
+ return true;
3839
+ }
3840
+ }
3841
+ return (
3842
+ messageID > 0
3843
+ && (
3844
+ intFromRawAllowZero(entry.source_message_id, 0) === messageID
3845
+ || intFromRawAllowZero(entry.last_source_message_id, 0) === messageID
3846
+ )
3847
+ );
3848
+ });
3849
+ }
3828
3850
 
3829
3851
  function sortRunnerRequestEntriesNewestFirst(entries = []) {
3830
3852
  return ensureArray(entries).slice().sort((leftRaw, rightRaw) => {
@@ -3839,24 +3861,26 @@ function sortRunnerRequestEntriesNewestFirst(entries = []) {
3839
3861
  });
3840
3862
  }
3841
3863
 
3842
- async function findServerRunnerRequestForMessageID({
3843
- normalizedRoute,
3844
- runtime,
3845
- chatID,
3846
- messageID,
3847
- }) {
3864
+ async function findServerRunnerRequestForMessageID({
3865
+ normalizedRoute,
3866
+ runtime,
3867
+ chatID,
3868
+ messageID,
3869
+ canonicalHumanMessageKey = "",
3870
+ }) {
3848
3871
  const projectID = String(normalizedRoute?.projectID || "").trim();
3849
3872
  const provider = String(normalizedRoute?.provider || "").trim();
3850
- const normalizedChatID = String(chatID || "").trim();
3851
- const normalizedMessageID = intFromRawAllowZero(messageID, 0);
3852
- if (
3853
- !projectID
3854
- || !provider
3855
- || !normalizedChatID
3856
- || normalizedMessageID <= 0
3857
- || !runtime?.baseURL
3858
- || !runtime?.token
3859
- ) {
3873
+ const normalizedChatID = String(chatID || "").trim();
3874
+ const normalizedMessageID = intFromRawAllowZero(messageID, 0);
3875
+ const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
3876
+ if (
3877
+ !projectID
3878
+ || !provider
3879
+ || !normalizedChatID
3880
+ || (normalizedMessageID <= 0 && !normalizedCanonicalHumanMessageKey)
3881
+ || !runtime?.baseURL
3882
+ || !runtime?.token
3883
+ ) {
3860
3884
  return null;
3861
3885
  }
3862
3886
  try {
@@ -3869,18 +3893,29 @@ async function findServerRunnerRequestForMessageID({
3869
3893
  limit: 500,
3870
3894
  offset: 0,
3871
3895
  });
3872
- const matched = sortRunnerRequestEntriesNewestFirst(serverRequests.filter((entryRaw) => {
3873
- const entry = safeObject(entryRaw);
3874
- return (
3875
- String(entry.project_id || "").trim() === projectID
3876
- && String(entry.provider || "").trim() === provider
3877
- && String(entry.chat_id || "").trim() === normalizedChatID
3878
- && (
3879
- intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
3880
- || intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
3881
- )
3882
- );
3883
- }));
3896
+ const matched = sortRunnerRequestEntriesNewestFirst(serverRequests.filter((entryRaw) => {
3897
+ const entry = safeObject(entryRaw);
3898
+ const requestCanonicalHumanMessageKey = firstNonEmptyString([
3899
+ entry.canonical_human_message_key,
3900
+ safeObject(entry.source_message_envelope).canonical_human_message_key,
3901
+ buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
3902
+ ]);
3903
+ return (
3904
+ String(entry.project_id || "").trim() === projectID
3905
+ && String(entry.provider || "").trim() === provider
3906
+ && String(entry.chat_id || "").trim() === normalizedChatID
3907
+ && (
3908
+ (normalizedCanonicalHumanMessageKey && requestCanonicalHumanMessageKey === normalizedCanonicalHumanMessageKey)
3909
+ || (
3910
+ normalizedMessageID > 0
3911
+ && (
3912
+ intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
3913
+ || intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
3914
+ )
3915
+ )
3916
+ )
3917
+ );
3918
+ }));
3884
3919
  return safeObject(matched[0]);
3885
3920
  } catch {
3886
3921
  return null;
@@ -3919,7 +3954,6 @@ function runnerRequestPreferredExecutionContractType(entryRaw) {
3919
3954
  return String(
3920
3955
  decisionBundle.execution_contract_type
3921
3956
  || entry.execution_contract_type
3922
- || entry.followup_execution_contract_type
3923
3957
  || entry.root_execution_contract_type
3924
3958
  || "",
3925
3959
  ).trim().toLowerCase();
@@ -3939,14 +3973,12 @@ function runnerRequestPreferredExecutionContractTargets(entryRaw) {
3939
3973
  ? decisionBundle.execution_contract_targets
3940
3974
  : ensureArray(entry.execution_contract_targets).length
3941
3975
  ? entry.execution_contract_targets
3942
- : ensureArray(entry.followup_execution_contract_targets).length
3943
- ? entry.followup_execution_contract_targets
3944
- : ensureArray(entry.root_execution_contract_targets).length
3945
- ? entry.root_execution_contract_targets
3946
- : [],
3947
- normalizeTelegramMentionUsername,
3948
- );
3949
- }
3976
+ : ensureArray(entry.root_execution_contract_targets).length
3977
+ ? entry.root_execution_contract_targets
3978
+ : [],
3979
+ normalizeTelegramMentionUsername,
3980
+ );
3981
+ }
3950
3982
 
3951
3983
  function runnerRequestPreferredNextExpectedResponders(entryRaw) {
3952
3984
  const entry = safeObject(entryRaw);
@@ -3956,14 +3988,12 @@ function runnerRequestPreferredNextExpectedResponders(entryRaw) {
3956
3988
  ? decisionBundle.next_expected_responders
3957
3989
  : ensureArray(entry.next_expected_responders).length
3958
3990
  ? entry.next_expected_responders
3959
- : ensureArray(entry.followup_next_expected_responders).length
3960
- ? entry.followup_next_expected_responders
3961
- : ensureArray(entry.root_next_expected_responders).length
3962
- ? entry.root_next_expected_responders
3963
- : [],
3964
- normalizeTelegramMentionUsername,
3965
- );
3966
- }
3991
+ : ensureArray(entry.root_next_expected_responders).length
3992
+ ? entry.root_next_expected_responders
3993
+ : [],
3994
+ normalizeTelegramMentionUsername,
3995
+ );
3996
+ }
3967
3997
 
3968
3998
  function runnerRequestPreferredAuthoritySelectedBotUsernames(entryRaw) {
3969
3999
  const entry = safeObject(entryRaw);
@@ -4326,25 +4356,27 @@ function pickRunnerSharedConversationSourceRequest(entries = [], excludeRequestK
4326
4356
  return safeObject(matched[0]);
4327
4357
  }
4328
4358
 
4329
- async function findServerRunnerConversationSourceRequestForMessageID({
4330
- normalizedRoute,
4331
- runtime,
4332
- chatID,
4333
- messageID,
4334
- excludeRequestKey = "",
4335
- }) {
4359
+ async function findServerRunnerConversationSourceRequestForMessageID({
4360
+ normalizedRoute,
4361
+ runtime,
4362
+ chatID,
4363
+ messageID,
4364
+ canonicalHumanMessageKey = "",
4365
+ excludeRequestKey = "",
4366
+ }) {
4336
4367
  const projectID = String(normalizedRoute?.projectID || "").trim();
4337
4368
  const provider = String(normalizedRoute?.provider || "").trim();
4338
- const normalizedChatID = String(chatID || "").trim();
4339
- const normalizedMessageID = intFromRawAllowZero(messageID, 0);
4340
- if (
4341
- !projectID
4342
- || !provider
4343
- || !normalizedChatID
4344
- || normalizedMessageID <= 0
4345
- || !runtime?.baseURL
4346
- || !runtime?.token
4347
- ) {
4369
+ const normalizedChatID = String(chatID || "").trim();
4370
+ const normalizedMessageID = intFromRawAllowZero(messageID, 0);
4371
+ const normalizedCanonicalHumanMessageKey = String(canonicalHumanMessageKey || "").trim();
4372
+ if (
4373
+ !projectID
4374
+ || !provider
4375
+ || !normalizedChatID
4376
+ || (normalizedMessageID <= 0 && !normalizedCanonicalHumanMessageKey)
4377
+ || !runtime?.baseURL
4378
+ || !runtime?.token
4379
+ ) {
4348
4380
  return null;
4349
4381
  }
4350
4382
  try {
@@ -4357,18 +4389,29 @@ async function findServerRunnerConversationSourceRequestForMessageID({
4357
4389
  limit: 500,
4358
4390
  offset: 0,
4359
4391
  });
4360
- const matched = serverRequests.filter((entryRaw) => {
4361
- const entry = safeObject(entryRaw);
4362
- return (
4363
- String(entry.project_id || "").trim() === projectID
4364
- && String(entry.provider || "").trim() === provider
4365
- && String(entry.chat_id || "").trim() === normalizedChatID
4366
- && (
4367
- intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
4368
- || intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
4369
- )
4370
- );
4371
- });
4392
+ const matched = serverRequests.filter((entryRaw) => {
4393
+ const entry = safeObject(entryRaw);
4394
+ const requestCanonicalHumanMessageKey = firstNonEmptyString([
4395
+ entry.canonical_human_message_key,
4396
+ safeObject(entry.source_message_envelope).canonical_human_message_key,
4397
+ buildRunnerCanonicalHumanInboundKey(safeObject(entry.source_message_envelope)),
4398
+ ]);
4399
+ return (
4400
+ String(entry.project_id || "").trim() === projectID
4401
+ && String(entry.provider || "").trim() === provider
4402
+ && String(entry.chat_id || "").trim() === normalizedChatID
4403
+ && (
4404
+ (normalizedCanonicalHumanMessageKey && requestCanonicalHumanMessageKey === normalizedCanonicalHumanMessageKey)
4405
+ || (
4406
+ normalizedMessageID > 0
4407
+ && (
4408
+ intFromRawAllowZero(entry.source_message_id, 0) === normalizedMessageID
4409
+ || intFromRawAllowZero(entry.last_source_message_id, 0) === normalizedMessageID
4410
+ )
4411
+ )
4412
+ )
4413
+ );
4414
+ });
4372
4415
  return pickRunnerSharedConversationSourceRequest(matched, excludeRequestKey);
4373
4416
  } catch {
4374
4417
  return null;
@@ -5031,13 +5074,14 @@ async function claimRunnerRequestForHumanComment({
5031
5074
  runtime,
5032
5075
  archiveThreadID,
5033
5076
  });
5034
- const replyChainContext = safeObject(replyChainResolution.replyChainContext);
5077
+ const replyChainContext = safeObject(replyChainResolution.replyChainContext);
5035
5078
  const referencedRequest = safeObject(replyChainContext.referencedRequest);
5036
5079
  const resolvedNormalizedIntent = resolveRunnerRequestClaimIntent({
5037
5080
  normalizedIntent,
5038
5081
  });
5039
- let stateForClaim = safeObject(replyChainResolution.state);
5040
- const normalizedSharedHumanIntent = safeObject(sharedHumanIntent);
5082
+ const canonicalHumanMessageKey = buildRunnerCanonicalHumanInboundKey(parsed);
5083
+ let stateForClaim = safeObject(replyChainResolution.state);
5084
+ const normalizedSharedHumanIntent = safeObject(sharedHumanIntent);
5041
5085
  const provisionalConversationID = String(
5042
5086
  parsed.conversationID
5043
5087
  || replyChainContext.conversationID
@@ -5072,29 +5116,31 @@ async function claimRunnerRequestForHumanComment({
5072
5116
  };
5073
5117
  }
5074
5118
  const currentMessageID = intFromRawAllowZero(parsed.messageID, 0);
5075
- let sharedConversationSource = currentMessageID > 0
5076
- ? pickRunnerSharedConversationSourceRequest(
5077
- findRunnerRequestsForMessageID(stateForClaim, normalizedRoute, {
5078
- chatID: String(parsed.chatID || parsed.chatId || "").trim(),
5079
- messageID: currentMessageID,
5080
- }),
5081
- provisionalRequestKey,
5082
- )
5083
- : {};
5119
+ let sharedConversationSource = currentMessageID > 0
5120
+ ? pickRunnerSharedConversationSourceRequest(
5121
+ findRunnerRequestsForMessageID(stateForClaim, normalizedRoute, {
5122
+ chatID: String(parsed.chatID || parsed.chatId || "").trim(),
5123
+ messageID: currentMessageID,
5124
+ canonicalHumanMessageKey,
5125
+ }),
5126
+ provisionalRequestKey,
5127
+ )
5128
+ : {};
5084
5129
  if (
5085
5130
  !Object.keys(sharedConversationSource).length
5086
5131
  && currentMessageID > 0
5087
5132
  && runtime?.baseURL
5088
5133
  && runtime?.token
5089
5134
  ) {
5090
- sharedConversationSource = safeObject(await findServerRunnerConversationSourceRequestForMessageID({
5091
- normalizedRoute,
5092
- runtime,
5093
- chatID: String(parsed.chatID || parsed.chatId || "").trim(),
5094
- messageID: currentMessageID,
5095
- excludeRequestKey: provisionalRequestKey,
5096
- }));
5097
- }
5135
+ sharedConversationSource = safeObject(await findServerRunnerConversationSourceRequestForMessageID({
5136
+ normalizedRoute,
5137
+ runtime,
5138
+ chatID: String(parsed.chatID || parsed.chatId || "").trim(),
5139
+ messageID: currentMessageID,
5140
+ canonicalHumanMessageKey,
5141
+ excludeRequestKey: provisionalRequestKey,
5142
+ }));
5143
+ }
5098
5144
  const authorityContext = resolveRunnerHumanCommentAuthorityContext({
5099
5145
  normalizedRoute,
5100
5146
  selectedRecord,
@@ -5182,14 +5228,16 @@ async function claimRunnerRequestForHumanComment({
5182
5228
  ensureArray(authoritativeDecisionBundle.allowed_responders),
5183
5229
  normalizeTelegramMentionUsername,
5184
5230
  );
5231
+ const hasAuthoritativeConversationDecision = Object.keys(authoritativeDecisionBundle).length > 0;
5185
5232
  const { requests: nextRequests, request } = upsertRunnerRequest(stateForClaim, requestKey, {
5186
5233
  project_id: String(normalizedRoute?.projectID || "").trim(),
5187
5234
  provider: String(normalizedRoute?.provider || "").trim(),
5188
5235
  chat_id: String(parsed.chatID || parsed.chatId || "").trim(),
5189
5236
  source_message_id: intFromRawAllowZero(parsed.messageID, 0) || undefined,
5190
- source_message_thread_id: intFromRawAllowZero(parsed.messageThreadID, 0) || undefined,
5191
- source_message_body: String(parsed.body || "").trim(),
5192
- source_message_origin: String(sourceMessageEnvelope.source_origin || "").trim().toLowerCase(),
5237
+ source_message_thread_id: intFromRawAllowZero(parsed.messageThreadID, 0) || undefined,
5238
+ source_message_body: String(parsed.body || "").trim(),
5239
+ canonical_human_message_key: canonicalHumanMessageKey,
5240
+ source_message_origin: String(sourceMessageEnvelope.source_origin || "").trim().toLowerCase(),
5193
5241
  source_message_route_key: String(sourceMessageEnvelope.source_route_key || "").trim(),
5194
5242
  source_message_bot_username: normalizeTelegramMentionUsername(sourceMessageEnvelope.source_bot_username),
5195
5243
  source_message_envelope: sourceMessageEnvelope,
@@ -5202,26 +5250,32 @@ async function claimRunnerRequestForHumanComment({
5202
5250
  decision_bundle_validation_status: String(decisionBundleValidation.status || "").trim(),
5203
5251
  decision_bundle_validation_reason: String(decisionBundleValidation.reason || "").trim(),
5204
5252
  conversation_intent_mode: String(
5205
- authoritativeDecisionBundle.conversation_intent_mode
5253
+ (hasAuthoritativeConversationDecision
5254
+ ? authoritativeDecisionBundle.conversation_intent_mode
5255
+ : "")
5206
5256
  || normalizedSharedHumanIntent.intentMode
5207
5257
  || existing.conversation_intent_mode
5208
5258
  || authoritySource.conversation_intent_mode
5209
5259
  || "",
5210
5260
  ).trim().toLowerCase(),
5211
5261
  conversation_lead_bot: normalizeTelegramMentionUsername(
5212
- authoritativeDecisionBundle.conversation_lead_bot
5262
+ (hasAuthoritativeConversationDecision
5263
+ ? authoritativeDecisionBundle.conversation_lead_bot
5264
+ : "")
5213
5265
  || normalizedSharedHumanIntent.leadBotSelector
5214
5266
  || existing.conversation_lead_bot
5215
5267
  || authoritySource.conversation_lead_bot,
5216
5268
  ),
5217
5269
  conversation_summary_bot: normalizeTelegramMentionUsername(
5218
- authoritativeDecisionBundle.conversation_summary_bot
5270
+ (hasAuthoritativeConversationDecision
5271
+ ? authoritativeDecisionBundle.conversation_summary_bot
5272
+ : "")
5219
5273
  || normalizedSharedHumanIntent.summaryBotSelector
5220
5274
  || existing.conversation_summary_bot
5221
5275
  || authoritySource.conversation_summary_bot,
5222
5276
  ),
5223
5277
  conversation_participants: uniqueOrderedStrings(
5224
- decisionConversationParticipants.length
5278
+ hasAuthoritativeConversationDecision && decisionConversationParticipants.length
5225
5279
  ? decisionConversationParticipants
5226
5280
  : ensureArray(normalizedSharedHumanIntent.participantSelectors).length
5227
5281
  ? normalizedSharedHumanIntent.participantSelectors
@@ -5233,7 +5287,7 @@ async function claimRunnerRequestForHumanComment({
5233
5287
  normalizeTelegramMentionUsername,
5234
5288
  ),
5235
5289
  conversation_initial_responders: uniqueOrderedStrings(
5236
- decisionInitialResponders.length
5290
+ hasAuthoritativeConversationDecision && decisionInitialResponders.length
5237
5291
  ? decisionInitialResponders
5238
5292
  : ensureArray(normalizedSharedHumanIntent.initialResponderSelectors).length
5239
5293
  ? normalizedSharedHumanIntent.initialResponderSelectors
@@ -5245,7 +5299,7 @@ async function claimRunnerRequestForHumanComment({
5245
5299
  normalizeTelegramMentionUsername,
5246
5300
  ),
5247
5301
  conversation_allowed_responders: uniqueOrderedStrings(
5248
- decisionAllowedResponders.length
5302
+ hasAuthoritativeConversationDecision && decisionAllowedResponders.length
5249
5303
  ? decisionAllowedResponders
5250
5304
  : ensureArray(normalizedSharedHumanIntent.allowedResponderSelectors).length
5251
5305
  ? normalizedSharedHumanIntent.allowedResponderSelectors
@@ -5254,30 +5308,38 @@ async function claimRunnerRequestForHumanComment({
5254
5308
  : ensureArray(authoritySource.conversation_allowed_responders).length
5255
5309
  ? authoritySource.conversation_allowed_responders
5256
5310
  : [],
5257
- normalizeTelegramMentionUsername,
5311
+ normalizeTelegramMentionUsername,
5258
5312
  ),
5259
- conversation_allow_bot_to_bot: authoritativeDecisionBundle.allow_bot_to_bot === true
5313
+ conversation_allow_bot_to_bot: (hasAuthoritativeConversationDecision
5314
+ ? authoritativeDecisionBundle.allow_bot_to_bot === true
5315
+ : false)
5260
5316
  || normalizedSharedHumanIntent.allowBotToBot === true
5261
5317
  || existing.conversation_allow_bot_to_bot === true
5262
5318
  || authoritySource.conversation_allow_bot_to_bot === true,
5263
5319
  conversation_reply_expectation: String(
5264
- authoritativeDecisionBundle.conversation_reply_expectation
5320
+ (hasAuthoritativeConversationDecision
5321
+ ? authoritativeDecisionBundle.conversation_reply_expectation
5322
+ : "")
5265
5323
  || normalizedSharedHumanIntent.replyExpectation
5266
5324
  || existing.conversation_reply_expectation
5267
5325
  || authoritySource.conversation_reply_expectation
5268
5326
  || "",
5269
5327
  ).trim().toLowerCase(),
5270
5328
  execution_contract_type: String(
5271
- authoritativeDecisionBundle.execution_contract_type
5329
+ (hasAuthoritativeConversationDecision
5330
+ ? authoritativeDecisionBundle.execution_contract_type
5331
+ : "")
5272
5332
  || runnerRequestPreferredExecutionContractType(existing)
5273
5333
  || runnerRequestPreferredExecutionContractType(authoritySource)
5274
5334
  || "",
5275
5335
  ).trim().toLowerCase(),
5276
- execution_contract_actionable: authoritativeDecisionBundle.execution_contract_actionable === true
5336
+ execution_contract_actionable: (hasAuthoritativeConversationDecision
5337
+ ? authoritativeDecisionBundle.execution_contract_actionable === true
5338
+ : false)
5277
5339
  || runnerRequestPreferredExecutionContractActionable(existing)
5278
5340
  || runnerRequestPreferredExecutionContractActionable(authoritySource),
5279
5341
  execution_contract_targets: uniqueOrderedStrings(
5280
- ensureArray(authoritativeDecisionBundle.execution_contract_targets).length
5342
+ hasAuthoritativeConversationDecision && ensureArray(authoritativeDecisionBundle.execution_contract_targets).length
5281
5343
  ? authoritativeDecisionBundle.execution_contract_targets
5282
5344
  : runnerRequestPreferredExecutionContractTargets(existing).length
5283
5345
  ? runnerRequestPreferredExecutionContractTargets(existing)
@@ -5285,7 +5347,7 @@ async function claimRunnerRequestForHumanComment({
5285
5347
  normalizeTelegramMentionUsername,
5286
5348
  ),
5287
5349
  next_expected_responders: uniqueOrderedStrings(
5288
- ensureArray(authoritativeDecisionBundle.next_expected_responders).length
5350
+ hasAuthoritativeConversationDecision && ensureArray(authoritativeDecisionBundle.next_expected_responders).length
5289
5351
  ? authoritativeDecisionBundle.next_expected_responders
5290
5352
  : runnerRequestPreferredNextExpectedResponders(existing).length
5291
5353
  ? runnerRequestPreferredNextExpectedResponders(existing)
@@ -6428,23 +6490,33 @@ function markRunnerRequestLifecycle({
6428
6490
  ],
6429
6491
  normalizeTelegramMentionUsername,
6430
6492
  ).filter((selector) => selector && selector !== normalizedCurrentBotSelector);
6493
+ const nextExecutionContractType = String(
6494
+ authoritativeDecisionBundle.execution_contract_type
6495
+ || executionContractType
6496
+ || existing.execution_contract_type
6497
+ || "",
6498
+ ).trim().toLowerCase();
6499
+ const normalizedOutcome = String(outcome || "").trim().toLowerCase();
6431
6500
  const shouldRemainRunningAfterReply = authoritativeDecisionBundle.should_close_after_reply === true
6432
6501
  ? false
6433
6502
  : authoritativeDecisionBundle.should_close_after_reply === false
6434
6503
  ? true
6435
6504
  : continuationSelectors.length > 0;
6505
+ const shouldRemainRunningAfterSkip = normalizedOutcome === "skipped"
6506
+ && parsedKind === "bot_reply"
6507
+ && authoritativeDecisionBundle.should_close_after_reply !== true
6508
+ && (
6509
+ nextExecutionContractType === "delegation"
6510
+ || rootEffectiveExecutionContractTargets.length > 0
6511
+ || rootEffectiveNextExpectedResponders.length > 0
6512
+ || continuationSelectors.length > 0
6513
+ );
6436
6514
  const nextConversationIntentMode = String(
6437
6515
  authoritativeDecisionBundle.conversation_intent_mode
6438
6516
  || conversationIntentMode
6439
6517
  || existing.conversation_intent_mode
6440
6518
  || "",
6441
6519
  ).trim().toLowerCase();
6442
- const nextExecutionContractType = String(
6443
- authoritativeDecisionBundle.execution_contract_type
6444
- || executionContractType
6445
- || existing.execution_contract_type
6446
- || "",
6447
- ).trim().toLowerCase();
6448
6520
  const nextNormalizedIntent = (() => {
6449
6521
  const explicitIntent = String(
6450
6522
  authoritativeDecisionBundle.normalized_intent || normalizedIntent || "",
@@ -6454,10 +6526,9 @@ function markRunnerRequestLifecycle({
6454
6526
  }
6455
6527
  if (nextConversationIntentMode && !nextExecutionContractType) {
6456
6528
  return "";
6457
- }
6458
- return String(existing.normalized_intent || "").trim().toLowerCase();
6459
- })();
6460
- const normalizedOutcome = String(outcome || "").trim().toLowerCase();
6529
+ }
6530
+ return String(existing.normalized_intent || "").trim().toLowerCase();
6531
+ })();
6461
6532
  const nextStatus = (() => {
6462
6533
  if (normalizedOutcome === "claimed") return "claimed";
6463
6534
  if (normalizedOutcome === "running") return "running";
@@ -6467,9 +6538,11 @@ function markRunnerRequestLifecycle({
6467
6538
  }
6468
6539
  if (normalizedOutcome === "loop_closed") return "loop_closed";
6469
6540
  if (normalizedOutcome === "expired") return "expired";
6541
+ if (normalizedOutcome === "skipped") {
6542
+ return shouldRemainRunningAfterSkip ? "running" : "closed";
6543
+ }
6470
6544
  if (
6471
6545
  normalizedOutcome === "error"
6472
- || normalizedOutcome === "skipped"
6473
6546
  || normalizedOutcome === "closed"
6474
6547
  || normalizedOutcome === "execution_failed"
6475
6548
  || normalizedOutcome === "policy_violation"