惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
月光博客
月光博客
MyScale Blog
MyScale Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
爱范儿
爱范儿
P
Proofpoint News Feed
人人都是产品经理
人人都是产品经理
Last Week in AI
Last Week in AI
罗磊的独立博客
G
Google Developers Blog
Y
Y Combinator Blog
博客园 - 【当耐特】
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
J
Java Code Geeks
酷 壳 – CoolShell
酷 壳 – CoolShell
V
Visual Studio Blog
美团技术团队
宝玉的分享
宝玉的分享
Jina AI
Jina AI
小众软件
小众软件
T
Tailwind CSS Blog
A
About on SuperTechFans

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(cron): require explicit message target proof (#92318)...
hxy91819 · 2026-06-15 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -347,6 +347,7 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {

347347

},

348348

messageToolEnabled: true,

349349

messageToolForced: false,

350+

requireExplicitMessageTargetEvidence: true,

350351

directFallback: true,

351352

}),

352353

skillsSnapshot: emptySkillsSnapshot,

@@ -1072,14 +1073,35 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {

10721073

});

10731074

});

10741075
1075-

it("skips cron fallback delivery when the message tool sends to the bound target", async () => {

1076-

await expectCronFallbackSkippedForMessageToolDelivery({

1077-

sentTargets: [],

1078-

job: {

1079-

id: "message-tool-bound-target",

1080-

name: "Message Tool Bound Target",

1076+

it("uses cron fallback delivery when the message tool returns no target evidence", async () => {

1077+

mockRunCronFallbackPassthrough();

1078+

resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan());

1079+

runEmbeddedAgentMock.mockResolvedValue(makeMessageToolRunResult([]));

1080+
1081+

const result = await runCronIsolatedAgentTurn({

1082+

...makeParams(),

1083+

job: makeAnnounceMessageToolJob({

1084+

id: "message-tool-no-target-evidence",

1085+

name: "Message Tool No Target Evidence",

1086+

}),

1087+

});

1088+
1089+

expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1);

1090+

expectDispatchFields({

1091+

deliveryRequested: true,

1092+

sourceDeliveryOutcome: {

1093+

visibleDeliveries: [],

1094+

verifiedMessageToolDelivery: false,

1095+

satisfiesSourceDelivery: false,

1096+

unverifiedMessageToolDelivery: false,

10811097

},

10821098

});

1099+

expectDeliveryFields(result.delivery, {

1100+

intended: { channel: "messagechat", to: "123", source: "explicit" },

1101+

resolved: { ok: true, channel: "messagechat", to: "123", source: "explicit" },

1102+

fallbackUsed: true,

1103+

delivered: true,

1104+

});

10831105

});

10841106
10851107

it("rewrites generic message provider to resolved channel in delivery trace", async () => {

Original file line numberDiff line numberDiff line change

@@ -341,6 +341,7 @@ function resolveCronSourceDeliveryPlan(params: {

341341

target,

342342

messageToolEnabled: true,

343343

messageToolForced: false,

344+

requireExplicitMessageTargetEvidence: true,

344345

directFallback: true,

345346

skipFallbackWhenMessageToolSentToTarget: params.resolvedDelivery.ok,

346347

});

Original file line numberDiff line numberDiff line change

@@ -145,6 +145,46 @@ describe("source delivery plan", () => {

145145

expect(outcome.unverifiedMessageToolDelivery).toBe(false);

146146

});

147147
148+

it("synthesizes the planned target for legacy message-tool sends by default", () => {

149+

const contract = createSourceDeliveryPlan({

150+

owner: "message_tool_then_direct_fallback",

151+

reason: "cron_announce",

152+

target: { channel: "slack", to: "channel:C1" },

153+

});

154+
155+

const outcome = resolveSourceDeliveryOutcome(contract, {

156+

didSendViaMessageTool: true,

157+

});

158+
159+

expect(outcome.visibleDeliveries).toEqual([

160+

{

161+

via: "message_tool",

162+

verifiedTarget: true,

163+

target: { tool: "message", provider: "slack", to: "channel:C1" },

164+

},

165+

]);

166+

expect(outcome.verifiedMessageToolDelivery).toBe(true);

167+

expect(outcome.satisfiesSourceDelivery).toBe(true);

168+

});

169+
170+

it("does not synthesize the planned target when explicit target evidence is required", () => {

171+

const contract = createSourceDeliveryPlan({

172+

owner: "message_tool_then_direct_fallback",

173+

reason: "cron_announce",

174+

target: { channel: "slack", to: "channel:C1" },

175+

requireExplicitMessageTargetEvidence: true,

176+

});

177+
178+

const outcome = resolveSourceDeliveryOutcome(contract, {

179+

didSendViaMessageTool: true,

180+

});

181+
182+

expect(outcome.visibleDeliveries).toEqual([]);

183+

expect(outcome.verifiedMessageToolDelivery).toBe(false);

184+

expect(outcome.satisfiesSourceDelivery).toBe(false);

185+

expect(outcome.unverifiedMessageToolDelivery).toBe(false);

186+

});

187+
148188

it("does not synthesize an implicit target without a concrete recipient", () => {

149189

const contract = createSourceDeliveryPlan({

150190

owner: "direct_fallback",

Original file line numberDiff line numberDiff line change

@@ -69,6 +69,7 @@ export type SourceDeliveryPlan = {

6969

enabled: boolean;

7070

force: boolean;

7171

requireExplicitTarget: boolean;

72+

requireExplicitTargetEvidence: boolean;

7273

defaultTarget: boolean;

7374

};

7475

fallback: {

@@ -174,6 +175,7 @@ export function createSourceDeliveryPlan(params: {

174175

messageToolEnabled?: boolean;

175176

messageToolForced?: boolean;

176177

requireExplicitMessageTarget?: boolean;

178+

requireExplicitMessageTargetEvidence?: boolean;

177179

directFallback?: boolean;

178180

skipFallbackWhenMessageToolSentToTarget?: boolean;

179181

fallbackBestEffort?: boolean;

@@ -197,6 +199,7 @@ export function createSourceDeliveryPlan(params: {

197199

enabled: params.messageToolEnabled ?? messageToolOwnsDelivery,

198200

force: params.messageToolForced ?? messageToolOwnsDelivery,

199201

requireExplicitTarget: params.requireExplicitMessageTarget ?? false,

202+

requireExplicitTargetEvidence: params.requireExplicitMessageTargetEvidence ?? false,

200203

defaultTarget: Boolean(params.target?.channel || params.target?.to),

201204

},

202205

fallback: {

@@ -239,11 +242,12 @@ export function resolveSourceDeliveryOutcome(

239242

): SourceDeliveryOutcome {

240243

const didSendViaMessageTool = params.didSendViaMessageTool === true;

241244

const explicitTargets = params.messageToolSentTargets ?? [];

242-

// A send without explicit target metadata still counts when the plan has a default target.

245+

// Cron completion accounting needs concrete target evidence. Legacy

246+

// message-tool-owned flows may still use the plan target as the implicit send.

243247

const sentTargets =

244248

explicitTargets.length > 0

245249

? explicitTargets

246-

: didSendViaMessageTool

250+

: didSendViaMessageTool && !plan.messageTool.requireExplicitTargetEvidence

247251

? [resolveImplicitMessageToolDeliveryTarget(plan)].filter(

248252

(target): target is SourceDeliveryMessageToolTarget => Boolean(target),

249253

)