omnius 1.0.669 → 1.0.671

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/dist/index.js CHANGED
@@ -625936,6 +625936,7 @@ function recordCompletionEvidence(ledger, evidence) {
625936
625936
  ...evidence.verificationImpact ? { verificationImpact: evidence.verificationImpact } : {},
625937
625937
  ...evidence.metrics ? { metrics: evidence.metrics } : {},
625938
625938
  ...evidence.receipt ? { receipt: evidence.receipt } : {},
625939
+ ...evidence.deliveryReceipt ? { deliveryReceipt: evidence.deliveryReceipt } : {},
625939
625940
  ...evidence.progressClass ? { progressClass: evidence.progressClass } : {}
625940
625941
  };
625941
625942
  return {
@@ -625963,6 +625964,7 @@ function recordToolEvidence(ledger, input) {
625963
625964
  verificationImpact: input.verificationImpact,
625964
625965
  metrics: input.metrics,
625965
625966
  receipt: input.receipt,
625967
+ deliveryReceipt: input.deliveryReceipt,
625966
625968
  progressClass: input.progressClass
625967
625969
  });
625968
625970
  }
@@ -629782,13 +629784,19 @@ function selectedEvidence(ledger) {
629782
629784
  return {
629783
629785
  evidenceIds: [],
629784
629786
  commandReceipts: [],
629787
+ deliveryReceipts: [],
629785
629788
  artifactHashes: []
629786
629789
  };
629787
629790
  }
629788
- const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation" || isValidObservationReceipt(entry))).slice(-16);
629791
+ const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation" || entry.role === "delivery" && Boolean(entry.deliveryReceipt) || isValidObservationReceipt(entry))).slice(-16);
629789
629792
  const artifacts = /* @__PURE__ */ new Map();
629793
+ const deliveries = /* @__PURE__ */ new Map();
629790
629794
  const commandReceipts = [];
629791
629795
  for (const entry of candidates) {
629796
+ if (entry.deliveryReceipt) {
629797
+ const key = `${entry.deliveryReceipt.provider}\0${entry.deliveryReceipt.receiptId}`;
629798
+ deliveries.set(key, entry.deliveryReceipt);
629799
+ }
629792
629800
  for (const item of entry.receipt?.artifactHashes ?? []) {
629793
629801
  if (item.path && item.sha256)
629794
629802
  artifacts.set(item.path, item.sha256);
@@ -629814,6 +629822,7 @@ function selectedEvidence(ledger) {
629814
629822
  return {
629815
629823
  evidenceIds: candidates.map((entry) => entry.id),
629816
629824
  commandReceipts,
629825
+ deliveryReceipts: [...deliveries.values()],
629817
629826
  artifactHashes: [...artifacts.entries()].map(([path16, sha25610]) => ({
629818
629827
  path: path16,
629819
629828
  sha256: sha25610
@@ -629823,11 +629832,21 @@ function selectedEvidence(ledger) {
629823
629832
  function buildCompletionFinalizationRecord(input) {
629824
629833
  const committedAtIso = input.committedAtIso ?? (/* @__PURE__ */ new Date()).toISOString();
629825
629834
  const evidence = selectedEvidence(input.ledger ?? void 0);
629835
+ const deliveries = /* @__PURE__ */ new Map();
629836
+ for (const receipt2 of [
629837
+ ...evidence.deliveryReceipts,
629838
+ ...input.deliveryReceipts ?? []
629839
+ ]) {
629840
+ deliveries.set(`${receipt2.provider}\0${receipt2.receiptId}`, receipt2);
629841
+ }
629842
+ const deliveryReceipts = [...deliveries.values()];
629826
629843
  const identity3 = [
629827
629844
  input.runId,
629828
629845
  input.taskEpoch ?? "",
629829
629846
  input.status,
629847
+ input.expectedOutcomeContract ? JSON.stringify(input.expectedOutcomeContract) : "",
629830
629848
  evidence.evidenceIds.join(","),
629849
+ deliveryReceipts.map((receipt2) => `${receipt2.provider}:${receipt2.receiptId}`).join(","),
629831
629850
  committedAtIso
629832
629851
  ].join("\0");
629833
629852
  return {
@@ -629839,10 +629858,13 @@ function buildCompletionFinalizationRecord(input) {
629839
629858
  status: input.status,
629840
629859
  ...input.ledger ? { ledgerStatus: input.ledger.status } : {},
629841
629860
  summary: clean4(input.summary, 4e3),
629861
+ ...input.expectedOutcomeContract ? { expectedOutcomeContract: input.expectedOutcomeContract } : {},
629862
+ ...input.expectedOutcomeAssessment ? { expectedOutcomeAssessment: input.expectedOutcomeAssessment } : {},
629842
629863
  committedAtIso,
629843
629864
  runtimeProvenance: captureCompletionRuntimeProvenance(),
629844
629865
  evidenceIds: evidence.evidenceIds,
629845
629866
  commandReceipts: evidence.commandReceipts,
629867
+ deliveryReceipts,
629846
629868
  artifactHashes: evidence.artifactHashes,
629847
629869
  projections: {
629848
629870
  ledger: "pending",
@@ -629902,7 +629924,10 @@ function commitTerminalTrajectoryProjection(stateDir, record, payload) {
629902
629924
  function loadCompletionFinalization(stateDir, runId) {
629903
629925
  try {
629904
629926
  const loaded = JSON.parse(readFileSync77(completionFinalizationPath(stateDir, runId), "utf8"));
629905
- return loaded.phase === "committed" ? loaded : null;
629927
+ return loaded.phase === "committed" ? {
629928
+ ...loaded,
629929
+ deliveryReceipts: Array.isArray(loaded.deliveryReceipts) ? loaded.deliveryReceipts : []
629930
+ } : null;
629906
629931
  } catch {
629907
629932
  return null;
629908
629933
  }
@@ -629913,6 +629938,465 @@ var init_completionFinalization = __esm({
629913
629938
  }
629914
629939
  });
629915
629940
 
629941
+ // packages/orchestrator/dist/expectedOutcomeContract.js
629942
+ function cleanId(value2, max = 240) {
629943
+ if (typeof value2 !== "string")
629944
+ return void 0;
629945
+ const clean7 = value2.trim().slice(0, max);
629946
+ return clean7 || void 0;
629947
+ }
629948
+ function normalizeExpectedOutcomeContractV1(value2) {
629949
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2))
629950
+ return null;
629951
+ const record = value2;
629952
+ if (record["schema"] !== "omnius.expected-outcome-contract.v1")
629953
+ return null;
629954
+ const route = record["route"];
629955
+ const continuity = record["continuity"];
629956
+ const planningMode = record["planningMode"];
629957
+ if (!ROUTES.has(route) || !CONTINUITIES.has(continuity))
629958
+ return null;
629959
+ if (!PLANNING_MODES.has(planningMode))
629960
+ return null;
629961
+ const confidence2 = record["confidence"];
629962
+ const reason = cleanId(record["reason"], 1e3);
629963
+ if (typeof confidence2 !== "number" || !Number.isFinite(confidence2) || confidence2 < 0 || confidence2 > 1 || !reason || !Array.isArray(record["citedEvidenceIds"])) {
629964
+ return null;
629965
+ }
629966
+ const citedEvidenceIds = [
629967
+ ...new Set(record["citedEvidenceIds"].map((value3) => cleanId(value3, 500)).filter((value3) => Boolean(value3)))
629968
+ ].slice(0, 64);
629969
+ if (citedEvidenceIds.length !== record["citedEvidenceIds"].length)
629970
+ return null;
629971
+ const outcome = record["outcome"];
629972
+ if (!OUTCOMES.has(outcome))
629973
+ return null;
629974
+ if (!Array.isArray(record["requiredEffects"]))
629975
+ return null;
629976
+ const requiredEffects = [
629977
+ ...new Set(record["requiredEffects"].filter((effect) => typeof effect === "string" && EFFECTS.has(effect)))
629978
+ ];
629979
+ if (requiredEffects.length !== record["requiredEffects"].length || !requiredEffects.includes(CORE_EFFECT[outcome])) {
629980
+ return null;
629981
+ }
629982
+ const activeScopeId = cleanId(record["activeScopeId"], 500);
629983
+ const inputId = cleanId(record["inputId"]);
629984
+ const decisionId = cleanId(record["decisionId"]);
629985
+ return {
629986
+ schema: "omnius.expected-outcome-contract.v1",
629987
+ route,
629988
+ continuity,
629989
+ ...activeScopeId ? { activeScopeId } : {},
629990
+ citedEvidenceIds,
629991
+ confidence: confidence2,
629992
+ reason,
629993
+ planningMode,
629994
+ outcome,
629995
+ requiredEffects,
629996
+ ...inputId ? { inputId } : {},
629997
+ ...decisionId ? { decisionId } : {}
629998
+ };
629999
+ }
630000
+ function assessExpectedOutcomeContractV1(contract, observed) {
630001
+ const observedSet = new Set(observed);
630002
+ const observedEffects = [...EFFECTS].filter((effect) => observedSet.has(effect));
630003
+ const missingEffects = contract.requiredEffects.filter((effect) => !observedSet.has(effect));
630004
+ return {
630005
+ schema: "omnius.expected-outcome-assessment.v1",
630006
+ outcome: contract.outcome,
630007
+ requiredEffects: [...contract.requiredEffects],
630008
+ observedEffects,
630009
+ missingEffects,
630010
+ satisfied: missingEffects.length === 0
630011
+ };
630012
+ }
630013
+ function expectedOutcomeAllowsTextOnlyCompletion(contract) {
630014
+ return Boolean(contract && contract.route === "chat" && contract.outcome === "conversation" && contract.requiredEffects.length === 1 && contract.requiredEffects[0] === "visible_response");
630015
+ }
630016
+ function normalizeCompletionDeliveryReceipt(value2) {
630017
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2))
630018
+ return null;
630019
+ const record = value2;
630020
+ if (record["schema"] !== "omnius.completion-delivery-receipt.v1")
630021
+ return null;
630022
+ const provider = cleanId(record["provider"], 120);
630023
+ const target = cleanId(record["target"], 500);
630024
+ const receiptId = cleanId(record["receiptId"], 500);
630025
+ const deliveredAtIso = cleanId(record["deliveredAtIso"], 80);
630026
+ if (!provider || !target || !receiptId || !deliveredAtIso)
630027
+ return null;
630028
+ const artifactPaths = Array.isArray(record["artifactPaths"]) ? [
630029
+ ...new Set(record["artifactPaths"].filter((path16) => typeof path16 === "string").map((path16) => path16.trim().slice(0, 1e3)).filter(Boolean))
630030
+ ].slice(0, 32) : void 0;
630031
+ return {
630032
+ schema: "omnius.completion-delivery-receipt.v1",
630033
+ provider,
630034
+ target,
630035
+ receiptId,
630036
+ deliveredAtIso,
630037
+ ...artifactPaths?.length ? { artifactPaths } : {}
630038
+ };
630039
+ }
630040
+ var OUTCOMES, ROUTES, CONTINUITIES, PLANNING_MODES, EFFECTS, CORE_EFFECT;
630041
+ var init_expectedOutcomeContract = __esm({
630042
+ "packages/orchestrator/dist/expectedOutcomeContract.js"() {
630043
+ "use strict";
630044
+ OUTCOMES = /* @__PURE__ */ new Set([
630045
+ "conversation",
630046
+ "read_only",
630047
+ "mutation",
630048
+ "delivery"
630049
+ ]);
630050
+ ROUTES = /* @__PURE__ */ new Set(["chat", "action"]);
630051
+ CONTINUITIES = /* @__PURE__ */ new Set([
630052
+ "new",
630053
+ "continue_active",
630054
+ "status_probe",
630055
+ "replace"
630056
+ ]);
630057
+ PLANNING_MODES = /* @__PURE__ */ new Set([
630058
+ "none",
630059
+ "checklist"
630060
+ ]);
630061
+ EFFECTS = /* @__PURE__ */ new Set([
630062
+ "visible_response",
630063
+ "observation",
630064
+ "mutation",
630065
+ "verification",
630066
+ "delivery"
630067
+ ]);
630068
+ CORE_EFFECT = {
630069
+ conversation: "visible_response",
630070
+ read_only: "observation",
630071
+ mutation: "mutation",
630072
+ delivery: "delivery"
630073
+ };
630074
+ }
630075
+ });
630076
+
630077
+ // packages/orchestrator/dist/todoObservability.js
630078
+ function emptyStatusCounts() {
630079
+ return { pending: 0, inProgress: 0, completed: 0, blocked: 0 };
630080
+ }
630081
+ function incrementStatus(counts, status) {
630082
+ if (status === "in_progress")
630083
+ counts.inProgress += 1;
630084
+ else
630085
+ counts[status] += 1;
630086
+ }
630087
+ function copyStrings(values) {
630088
+ return values ? Array.from(values) : void 0;
630089
+ }
630090
+ function copyItem(todo, sourceOrdinal) {
630091
+ return {
630092
+ id: todo.id,
630093
+ content: todo.content,
630094
+ status: todo.status,
630095
+ sourceOrdinal,
630096
+ ...todo.activeForm !== void 0 ? { activeForm: todo.activeForm } : {},
630097
+ ...todo.parentId !== void 0 ? { parentId: todo.parentId } : {},
630098
+ ...todo.blocker !== void 0 ? { blocker: todo.blocker } : {},
630099
+ ...todo.owner !== void 0 ? { owner: todo.owner } : {},
630100
+ ...todo.blocks !== void 0 ? { blocks: copyStrings(todo.blocks) } : {},
630101
+ ...todo.blockedBy !== void 0 ? { blockedBy: copyStrings(todo.blockedBy) } : {},
630102
+ ...todo.createdAt !== void 0 ? { createdAt: todo.createdAt } : {},
630103
+ ...todo.updatedAt !== void 0 ? { updatedAt: todo.updatedAt } : {},
630104
+ ...todo.completedAt !== void 0 ? { completedAt: todo.completedAt } : {}
630105
+ };
630106
+ }
630107
+ function validateSnapshotInput(input) {
630108
+ if (!input.sessionId.trim())
630109
+ throw new Error("Todo snapshot sessionId must not be empty");
630110
+ if (!Number.isSafeInteger(input.revision) || input.revision < 0) {
630111
+ throw new Error("Todo snapshot revision must be a non-negative safe integer");
630112
+ }
630113
+ const ids = /* @__PURE__ */ new Set();
630114
+ for (const todo of input.todos) {
630115
+ if (!todo.id.trim())
630116
+ throw new Error("Todo snapshot item id must not be empty");
630117
+ if (ids.has(todo.id))
630118
+ throw new Error(`Duplicate todo id '${todo.id}'`);
630119
+ ids.add(todo.id);
630120
+ }
630121
+ }
630122
+ function buildHierarchy(items) {
630123
+ const byId = new Map(items.map((item) => [item.id, item]));
630124
+ const invalidParents = /* @__PURE__ */ new Set();
630125
+ const issues = [];
630126
+ for (const item of items) {
630127
+ if (!item.parentId)
630128
+ continue;
630129
+ if (item.parentId === item.id) {
630130
+ invalidParents.add(item.id);
630131
+ issues.push({ code: "self_parent", todoId: item.id, parentId: item.parentId });
630132
+ } else if (!byId.has(item.parentId)) {
630133
+ invalidParents.add(item.id);
630134
+ issues.push({ code: "missing_parent", todoId: item.id, parentId: item.parentId });
630135
+ }
630136
+ }
630137
+ const visitState = /* @__PURE__ */ new Map();
630138
+ const stack = [];
630139
+ const visit = (id2) => {
630140
+ const state5 = visitState.get(id2);
630141
+ if (state5 === "visited")
630142
+ return;
630143
+ if (state5 === "visiting") {
630144
+ const start2 = stack.lastIndexOf(id2);
630145
+ for (const cycleId of stack.slice(Math.max(0, start2))) {
630146
+ const cycleItem = byId.get(cycleId);
630147
+ if (!cycleItem?.parentId || invalidParents.has(cycleId))
630148
+ continue;
630149
+ invalidParents.add(cycleId);
630150
+ issues.push({
630151
+ code: "cyclic_parent",
630152
+ todoId: cycleId,
630153
+ parentId: cycleItem.parentId
630154
+ });
630155
+ }
630156
+ return;
630157
+ }
630158
+ visitState.set(id2, "visiting");
630159
+ stack.push(id2);
630160
+ const parentId = byId.get(id2)?.parentId;
630161
+ if (parentId && byId.has(parentId) && parentId !== id2)
630162
+ visit(parentId);
630163
+ stack.pop();
630164
+ visitState.set(id2, "visited");
630165
+ };
630166
+ for (const item of items)
630167
+ visit(item.id);
630168
+ const children2 = /* @__PURE__ */ new Map();
630169
+ const resolvedParent = /* @__PURE__ */ new Map();
630170
+ const roots = [];
630171
+ for (const item of items) {
630172
+ const parentId = item.parentId;
630173
+ if (!parentId || invalidParents.has(item.id) || !byId.has(parentId)) {
630174
+ roots.push(item);
630175
+ continue;
630176
+ }
630177
+ resolvedParent.set(item.id, parentId);
630178
+ const bucket2 = children2.get(parentId) ?? [];
630179
+ bucket2.push(item);
630180
+ children2.set(parentId, bucket2);
630181
+ }
630182
+ return { byId, children: children2, roots, resolvedParent, issues };
630183
+ }
630184
+ function snapshotCounts(items) {
630185
+ const hierarchy = buildHierarchy(items);
630186
+ const status = emptyStatusCounts();
630187
+ const leafStatus = emptyStatusCounts();
630188
+ let leaves = 0;
630189
+ for (const item of items) {
630190
+ incrementStatus(status, item.status);
630191
+ if ((hierarchy.children.get(item.id)?.length ?? 0) === 0) {
630192
+ leaves += 1;
630193
+ incrementStatus(leafStatus, item.status);
630194
+ }
630195
+ }
630196
+ return {
630197
+ total: items.length,
630198
+ roots: hierarchy.roots.length,
630199
+ leaves,
630200
+ open: items.length - status.completed,
630201
+ openLeaves: leaves - leafStatus.completed,
630202
+ status,
630203
+ leafStatus
630204
+ };
630205
+ }
630206
+ function createTodoSnapshot(input) {
630207
+ validateSnapshotInput(input);
630208
+ const items = input.todos.map((todo, index) => copyItem(todo, index));
630209
+ return {
630210
+ schemaVersion: 1,
630211
+ sessionId: input.sessionId,
630212
+ ...input.taskEpoch !== void 0 ? { taskEpoch: input.taskEpoch } : {},
630213
+ revision: input.revision,
630214
+ observedAt: input.observedAt,
630215
+ items,
630216
+ counts: snapshotCounts(items)
630217
+ };
630218
+ }
630219
+ function descendantStats(item, hierarchy) {
630220
+ const children2 = hierarchy.children.get(item.id) ?? [];
630221
+ if (children2.length === 0) {
630222
+ const leafCounts2 = emptyStatusCounts();
630223
+ incrementStatus(leafCounts2, item.status);
630224
+ return { descendantCount: 0, leafCounts: leafCounts2, displayStatus: item.status };
630225
+ }
630226
+ let descendantCount = 0;
630227
+ const leafCounts = emptyStatusCounts();
630228
+ for (const child2 of children2) {
630229
+ const childStats = descendantStats(child2, hierarchy);
630230
+ descendantCount += 1 + childStats.descendantCount;
630231
+ leafCounts.pending += childStats.leafCounts.pending;
630232
+ leafCounts.inProgress += childStats.leafCounts.inProgress;
630233
+ leafCounts.completed += childStats.leafCounts.completed;
630234
+ leafCounts.blocked += childStats.leafCounts.blocked;
630235
+ }
630236
+ const displayStatus = leafCounts.blocked > 0 ? "blocked" : leafCounts.inProgress > 0 ? "in_progress" : leafCounts.pending > 0 ? item.status === "completed" ? "in_progress" : item.status : "completed";
630237
+ return { descendantCount, leafCounts, displayStatus };
630238
+ }
630239
+ function buildTodoRenderModel(snapshot) {
630240
+ const hierarchy = buildHierarchy(snapshot.items);
630241
+ const rows = [];
630242
+ const seen = /* @__PURE__ */ new Set();
630243
+ const visit = (item, depth) => {
630244
+ if (seen.has(item.id))
630245
+ return;
630246
+ seen.add(item.id);
630247
+ const stats = descendantStats(item, hierarchy);
630248
+ const resolvedParentId = hierarchy.resolvedParent.get(item.id);
630249
+ rows.push({
630250
+ ...item,
630251
+ ordinal: rows.length,
630252
+ depth,
630253
+ ...resolvedParentId ? { resolvedParentId } : {},
630254
+ displayStatus: stats.displayStatus,
630255
+ directChildCount: hierarchy.children.get(item.id)?.length ?? 0,
630256
+ descendantCount: stats.descendantCount,
630257
+ leafCounts: stats.leafCounts
630258
+ });
630259
+ for (const child2 of hierarchy.children.get(item.id) ?? [])
630260
+ visit(child2, depth + 1);
630261
+ };
630262
+ for (const root of hierarchy.roots)
630263
+ visit(root, 0);
630264
+ for (const item of snapshot.items)
630265
+ visit(item, 0);
630266
+ const activeTodoIds = rows.filter((row2) => row2.status === "in_progress").map((row2) => row2.id);
630267
+ const blockedTodoIds = rows.filter((row2) => row2.status === "blocked").map((row2) => row2.id);
630268
+ const state5 = rows.length === 0 ? "empty" : blockedTodoIds.length > 0 ? "blocked" : snapshot.counts.openLeaves === 0 ? "completed" : "active";
630269
+ return {
630270
+ schemaVersion: 1,
630271
+ sessionId: snapshot.sessionId,
630272
+ ...snapshot.taskEpoch !== void 0 ? { taskEpoch: snapshot.taskEpoch } : {},
630273
+ revision: snapshot.revision,
630274
+ observedAt: snapshot.observedAt,
630275
+ state: state5,
630276
+ counts: snapshot.counts,
630277
+ activeTodoIds,
630278
+ blockedTodoIds,
630279
+ rows,
630280
+ hierarchyIssues: hierarchy.issues
630281
+ };
630282
+ }
630283
+ function sameStrings(a2, b) {
630284
+ if (a2 === b)
630285
+ return true;
630286
+ if (!a2 || !b || a2.length !== b.length)
630287
+ return false;
630288
+ return a2.every((value2, index) => value2 === b[index]);
630289
+ }
630290
+ function detailChanges(previous, current) {
630291
+ const fields = [];
630292
+ if (previous.activeForm !== current.activeForm)
630293
+ fields.push("activeForm");
630294
+ if (previous.blocker !== current.blocker)
630295
+ fields.push("blocker");
630296
+ if (previous.owner !== current.owner)
630297
+ fields.push("owner");
630298
+ if (!sameStrings(previous.blocks, current.blocks))
630299
+ fields.push("blocks");
630300
+ if (!sameStrings(previous.blockedBy, current.blockedBy))
630301
+ fields.push("blockedBy");
630302
+ return fields;
630303
+ }
630304
+ function transitionBase(previous, current, todoId) {
630305
+ return {
630306
+ sessionId: current.sessionId,
630307
+ ...current.taskEpoch !== void 0 ? { taskEpoch: current.taskEpoch } : {},
630308
+ fromRevision: previous.revision,
630309
+ toRevision: current.revision,
630310
+ observedAt: current.observedAt,
630311
+ todoId
630312
+ };
630313
+ }
630314
+ function diffTodoSnapshots(previous, current) {
630315
+ if (previous.sessionId !== current.sessionId) {
630316
+ throw new Error("Cannot diff todo snapshots from different sessions");
630317
+ }
630318
+ if (previous.taskEpoch !== current.taskEpoch) {
630319
+ throw new Error("Cannot diff todo snapshots from different task epochs");
630320
+ }
630321
+ if (current.revision <= previous.revision) {
630322
+ throw new Error("Todo snapshot revision must increase when diffing");
630323
+ }
630324
+ const previousById = new Map(previous.items.map((item) => [item.id, item]));
630325
+ const currentById = new Map(current.items.map((item) => [item.id, item]));
630326
+ const transitions = [];
630327
+ for (const item of current.items) {
630328
+ const prior = previousById.get(item.id);
630329
+ const base3 = transitionBase(previous, current, item.id);
630330
+ if (!prior) {
630331
+ transitions.push({ ...base3, kind: "created", item });
630332
+ continue;
630333
+ }
630334
+ if (prior.status !== item.status) {
630335
+ transitions.push({
630336
+ ...base3,
630337
+ kind: "status_changed",
630338
+ from: prior.status,
630339
+ to: item.status,
630340
+ item
630341
+ });
630342
+ }
630343
+ if (prior.parentId !== item.parentId) {
630344
+ transitions.push({
630345
+ ...base3,
630346
+ kind: "reparented",
630347
+ fromParentId: prior.parentId ?? null,
630348
+ toParentId: item.parentId ?? null,
630349
+ item
630350
+ });
630351
+ }
630352
+ if (prior.content !== item.content) {
630353
+ transitions.push({
630354
+ ...base3,
630355
+ kind: "content_changed",
630356
+ from: prior.content,
630357
+ to: item.content,
630358
+ item
630359
+ });
630360
+ }
630361
+ const fields = detailChanges(prior, item);
630362
+ if (fields.length > 0) {
630363
+ transitions.push({ ...base3, kind: "details_changed", fields, item });
630364
+ }
630365
+ }
630366
+ for (const prior of previous.items) {
630367
+ if (currentById.has(prior.id))
630368
+ continue;
630369
+ transitions.push({
630370
+ ...transitionBase(previous, current, prior.id),
630371
+ kind: "deleted",
630372
+ previous: prior
630373
+ });
630374
+ }
630375
+ return transitions;
630376
+ }
630377
+ function createTodoSnapshotEvent(runId, snapshot) {
630378
+ return {
630379
+ type: "todo_snapshot",
630380
+ runId,
630381
+ snapshot,
630382
+ timestamp: snapshot.observedAt
630383
+ };
630384
+ }
630385
+ function createTodoTransitionEvents(runId, previous, current) {
630386
+ return diffTodoSnapshots(previous, current).map((transition2) => ({
630387
+ type: "todo_transition",
630388
+ runId,
630389
+ transition: transition2,
630390
+ snapshotRevision: current.revision,
630391
+ timestamp: current.observedAt
630392
+ }));
630393
+ }
630394
+ var init_todoObservability = __esm({
630395
+ "packages/orchestrator/dist/todoObservability.js"() {
630396
+ "use strict";
630397
+ }
630398
+ });
630399
+
629916
630400
  // packages/orchestrator/dist/verificationCommand.js
629917
630401
  function exactTrailingExitReporterPrimary(command) {
629918
630402
  let quote = null;
@@ -652897,6 +653381,8 @@ var init_agenticRunner = __esm({
652897
653381
  init_verification_ledger();
652898
653382
  init_completionAutoFinalize();
652899
653383
  init_completionFinalization();
653384
+ init_expectedOutcomeContract();
653385
+ init_todoObservability();
652900
653386
  init_verificationCommand();
652901
653387
  init_completionContract();
652902
653388
  init_dist6();
@@ -653244,6 +653730,10 @@ ${loadPrompt("agentic/system-small.md")}`;
653244
653730
  _consecutiveEnoent = 0;
653245
653731
  _assistantTextEmitted = false;
653246
653732
  // WO-E26: prevent double-emit
653733
+ _expectedOutcomeObservedEffects = /* @__PURE__ */ new Set();
653734
+ _completionDeliveryReceipts = /* @__PURE__ */ new Map();
653735
+ _todoObservabilitySnapshot;
653736
+ _todoObservabilityRevision = 0;
653247
653737
  _recentEnoents = [];
653248
653738
  // sliding window of last 8 tool calls
653249
653739
  _microcompactHintEmitted = false;
@@ -654942,6 +655432,22 @@ ${parts.join("\n")}
654942
655432
  } catch {
654943
655433
  }
654944
655434
  }
655435
+ _observeExpectedOutcomeEffect(effect) {
655436
+ if (this.options.expectedOutcomeContract) {
655437
+ this._expectedOutcomeObservedEffects.add(effect);
655438
+ }
655439
+ }
655440
+ _recordCompletionDeliveryReceipt(value2) {
655441
+ const receipt2 = normalizeCompletionDeliveryReceipt(value2);
655442
+ if (!receipt2)
655443
+ return null;
655444
+ this._completionDeliveryReceipts.set(`${receipt2.provider}\0${receipt2.receiptId}`, receipt2);
655445
+ this._observeExpectedOutcomeEffect("delivery");
655446
+ return receipt2;
655447
+ }
655448
+ _currentExpectedOutcomeAssessment() {
655449
+ return this.options.expectedOutcomeContract ? assessExpectedOutcomeContractV1(this.options.expectedOutcomeContract, this._expectedOutcomeObservedEffects) : void 0;
655450
+ }
654945
655451
  /**
654946
655452
  * Commit one authoritative terminal receipt before emitting a result to the
654947
655453
  * TUI. The receipt is the source of truth; ledger/workboard/debug/trajectory
@@ -654956,6 +655462,9 @@ ${parts.join("\n")}
654956
655462
  taskEpoch: this._taskEpoch,
654957
655463
  status: input.status,
654958
655464
  summary: input.summary,
655465
+ expectedOutcomeContract: this.options.expectedOutcomeContract,
655466
+ expectedOutcomeAssessment: input.expectedOutcomeAssessment,
655467
+ deliveryReceipts: [...this._completionDeliveryReceipts.values()],
654959
655468
  ledger: this._completionLedger,
654960
655469
  workboardPresent: Boolean(this._workboard)
654961
655470
  });
@@ -655063,11 +655572,16 @@ runtime_module_sha256=${record.runtimeProvenance.module.sha256 ?? "unknown"}`
655063
655572
  constructor(backend, options2) {
655064
655573
  const adversaryMode = options2?.adversaryMode ?? options2?.observerMode ?? "both";
655065
655574
  const disableAdversaryCritic = options2?.disableAdversaryCritic ?? options2?.disableStepCritic ?? true;
655575
+ const expectedOutcomeContract = options2?.expectedOutcomeContract ? normalizeExpectedOutcomeContractV1(options2.expectedOutcomeContract) : void 0;
655576
+ if (options2?.expectedOutcomeContract && !expectedOutcomeContract) {
655577
+ throw new TypeError("Invalid ExpectedOutcomeContractV1");
655578
+ }
655066
655579
  this.backend = backend;
655067
655580
  this._explicitCompactionThreshold = typeof options2?.compactionThreshold === "number";
655068
655581
  this.options = {
655069
655582
  maxTurns: options2?.maxTurns ?? 60,
655070
655583
  acceptTextOnlyCompletion: options2?.acceptTextOnlyCompletion ?? false,
655584
+ expectedOutcomeContract,
655071
655585
  maxTokens: options2?.maxTokens ?? 16384,
655072
655586
  temperature: options2?.temperature ?? 0,
655073
655587
  requestTimeoutMs: options2?.requestTimeoutMs ?? 3e5,
@@ -657774,6 +658288,29 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
657774
658288
  return null;
657775
658289
  }
657776
658290
  }
658291
+ _emitTodoObservabilitySnapshot() {
658292
+ if (!this._onTypedEvent)
658293
+ return;
658294
+ const todos = this.readSessionTodos();
658295
+ if (!todos)
658296
+ return;
658297
+ const observedAt = (/* @__PURE__ */ new Date()).toISOString();
658298
+ const next = createTodoSnapshot({
658299
+ sessionId: this._sessionId || process.env["OMNIUS_SESSION_ID"] || "default",
658300
+ taskEpoch: this._taskEpoch,
658301
+ revision: ++this._todoObservabilityRevision,
658302
+ observedAt,
658303
+ todos
658304
+ });
658305
+ const runId = this.currentArtifactRunId();
658306
+ if (this._todoObservabilitySnapshot) {
658307
+ for (const event of createTodoTransitionEvents(runId, this._todoObservabilitySnapshot, next)) {
658308
+ this._onTypedEvent(event);
658309
+ }
658310
+ }
658311
+ this._todoObservabilitySnapshot = next;
658312
+ this._onTypedEvent(createTodoSnapshotEvent(runId, next));
658313
+ }
657777
658314
  _operationalWorkGraphPersistenceKey() {
657778
658315
  const session = this._sessionId || process.env["OMNIUS_SESSION_ID"] || "default";
657779
658316
  return `${session}-run-${this.quickHash(this._activeRunId || "inactive")}-task-epoch-${this._taskEpoch}`;
@@ -657852,8 +658389,6 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
657852
658389
  messages2.splice(index, 1);
657853
658390
  }
657854
658391
  }
657855
- if (!this.writesUserTaskArtifacts())
657856
- return;
657857
658392
  if (!this.tools.has("task_complete"))
657858
658393
  return;
657859
658394
  const openItems = openTodoLeaves(this._normalizeTodosForPrompt(this.readSessionTodos() ?? []));
@@ -659044,7 +659579,10 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
659044
659579
  return kept.length > 0 ? kept.join(" | ") : null;
659045
659580
  }
659046
659581
  _recordCompletionToolEvidenceFromResult(input) {
659047
- if (!this._completionLedger || input.toolName === "task_complete")
659582
+ if (!this._completionLedger)
659583
+ return;
659584
+ const deliveryReceipt = input.result.success === true ? normalizeCompletionDeliveryReceipt(input.result.completionDeliveryReceipt) : null;
659585
+ if (input.toolName === "task_complete" && !deliveryReceipt)
659048
659586
  return;
659049
659587
  const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
659050
659588
  const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
@@ -659076,11 +659614,12 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
659076
659614
  outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result, void 0, 1200, input.toolName)).toString().slice(0, input.toolName === "audio_analyze" || input.toolName === "video_understand" ? 1200 : 500),
659077
659615
  argsKey: input.argsKey.slice(0, 300),
659078
659616
  targetPaths: evidenceTargetPaths2,
659079
- role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : input.result.success === true ? "observation" : void 0),
659617
+ role: input.result.completionEvidenceRole ?? (deliveryReceipt ? "delivery" : input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : input.result.success === true ? "observation" : void 0),
659080
659618
  family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true && !shellVerification ? "runtime_control" : shellVerification ? shellVerificationFamily : void 0),
659081
659619
  verificationImpact: input.result.completionVerificationImpact ?? (input.result.alreadyApplied === true ? "neutral" : realFileMutation ? "invalidates" : void 0),
659082
659620
  metrics: input.result.completionEvidenceMetrics,
659083
- receipt: receipt2
659621
+ receipt: receipt2,
659622
+ deliveryReceipt: deliveryReceipt ?? void 0
659084
659623
  });
659085
659624
  if (realFileMutation && realMutationPaths.length > 0) {
659086
659625
  for (const filePath of realMutationPaths) {
@@ -663445,6 +663984,11 @@ Rewrite it now for ${ctx3.model}.`;
663445
663984
  */
663446
663985
  prepareReusableRun(configuration) {
663447
663986
  this.options.dynamicContext = String(configuration.dynamicContext ?? "");
663987
+ const expectedOutcomeContract = configuration.expectedOutcomeContract ? normalizeExpectedOutcomeContractV1(configuration.expectedOutcomeContract) : void 0;
663988
+ if (configuration.expectedOutcomeContract && !expectedOutcomeContract) {
663989
+ throw new TypeError("Invalid ExpectedOutcomeContractV1");
663990
+ }
663991
+ this.options.expectedOutcomeContract = expectedOutcomeContract ?? void 0;
663448
663992
  this.tools.clear();
663449
663993
  this._activatedTools.clear();
663450
663994
  this._toolLastUsedTurn.clear();
@@ -666686,6 +667230,11 @@ ${dynamicProjectContext}`
666686
667230
  let acceptedTaskCompleteStatus;
666687
667231
  let bruteForceCycle = 0;
666688
667232
  this._assistantTextEmitted = false;
667233
+ this._expectedOutcomeObservedEffects.clear();
667234
+ this._completionDeliveryReceipts.clear();
667235
+ this._todoObservabilitySnapshot = void 0;
667236
+ this._todoObservabilityRevision = 0;
667237
+ this._emitTodoObservabilitySnapshot();
666689
667238
  this._microcompactHintEmitted = false;
666690
667239
  this._hookDenyHintCount = 0;
666691
667240
  this._selfConsistencyVotes = 0;
@@ -667291,6 +667840,8 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
667291
667840
  this._completionLedger = reconcileClaimsWithEvidence(this._completionLedger);
667292
667841
  this._refreshIntegrationClosure();
667293
667842
  }
667843
+ if (this.options.expectedOutcomeContract)
667844
+ return false;
667294
667845
  const authoritativeDeficit = authoritativeCompletionDeficit(turn);
667295
667846
  if (authoritativeDeficit) {
667296
667847
  return holdAuthoritativeCompletionDeficit(authoritativeDeficit, args, turn);
@@ -668887,6 +669438,7 @@ ${memoryLines.join("\n")}`
668887
669438
  const { maxOutputTokens: effectiveMaxTokens } = this.contextLimits();
668888
669439
  this.gcSystemMessages(requestMessages2);
668889
669440
  requestMessages2 = this._prepareModelFacingMessages(requestMessages2, turn);
669441
+ this._injectTaskCloseoutReconciliationContext(requestMessages2);
668890
669442
  const echoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
668891
669443
  if (this._echoTempBoostTurns > 0)
668892
669444
  this._echoTempBoostTurns--;
@@ -670732,6 +671284,21 @@ ${diagnostic}`;
670732
671284
  }
670733
671285
  const realFileMutation = this._isRealProjectMutation(tc.name, result);
670734
671286
  const observedStateMutation = realFileMutation || shellFilesystemMutation || result.success === true && result.mutated === true;
671287
+ if (result.success === true && (observedStateMutation || result.alreadyApplied === true)) {
671288
+ this._observeExpectedOutcomeEffect("mutation");
671289
+ }
671290
+ if (result.success === true && result.runtimeAuthored !== true && (isReadLike && !result.completionEvidenceRole || result.completionEvidenceRole === "observation" || result.completionEvidenceRole === "verification")) {
671291
+ this._observeExpectedOutcomeEffect("observation");
671292
+ }
671293
+ if (result.success === true && result.runtimeAuthored !== true && result.completionEvidenceRole === "verification") {
671294
+ this._observeExpectedOutcomeEffect("verification");
671295
+ }
671296
+ if (result.success === true && result.completionDeliveryReceipt) {
671297
+ this._recordCompletionDeliveryReceipt(result.completionDeliveryReceipt);
671298
+ }
671299
+ if (result.success === true && result.completionVisibleResponse === true) {
671300
+ this._observeExpectedOutcomeEffect("visible_response");
671301
+ }
670735
671302
  const realMutationPaths = realFileMutation ? this._extractToolTargetPaths(tc.name, tc.arguments, result) : shellFilesystemMutation ? shellMutationPaths : [];
670736
671303
  this._recordRecentToolOutcomeForWorldState({
670737
671304
  turn,
@@ -670817,6 +671384,7 @@ ${diagnostic}`;
670817
671384
  }
670818
671385
  this._writesSinceLastTodoWrite = 0;
670819
671386
  this._progressGateActive = false;
671387
+ this._emitTodoObservabilitySnapshot();
670820
671388
  }
670821
671389
  if (tc.name === "file_read") {
670822
671390
  const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
@@ -673037,6 +673605,7 @@ Only call task_complete when the task is actually complete and the evidence is f
673037
673605
  });
673038
673606
  const cleanNonStream = content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
673039
673607
  if (cleanNonStream) {
673608
+ this._observeExpectedOutcomeEffect("visible_response");
673040
673609
  this.emit({
673041
673610
  type: "assistant_text",
673042
673611
  content: cleanNonStream,
@@ -673044,7 +673613,7 @@ Only call task_complete when the task is actually complete and the evidence is f
673044
673613
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
673045
673614
  });
673046
673615
  }
673047
- if (this.options.acceptTextOnlyCompletion && cleanNonStream) {
673616
+ if (this.options.acceptTextOnlyCompletion && expectedOutcomeAllowsTextOnlyCompletion(this.options.expectedOutcomeContract) && cleanNonStream) {
673048
673617
  completed = true;
673049
673618
  summary = cleanNonStream;
673050
673619
  this._onTypedEvent?.({
@@ -673057,24 +673626,6 @@ Only call task_complete when the task is actually complete and the evidence is f
673057
673626
  break;
673058
673627
  }
673059
673628
  this.adversaryObserve(messages2, turn);
673060
- if (/task.?complete|all tests pass/i.test(content)) {
673061
- const completionArgs = { summary: content };
673062
- if (holdTaskCompleteGates(completionArgs, turn)) {
673063
- if (this._completionIncompleteVerification)
673064
- break;
673065
- continue;
673066
- }
673067
- completed = true;
673068
- summary = content;
673069
- this._onTypedEvent?.({
673070
- type: "completion_requested",
673071
- runId: this.currentArtifactRunId(),
673072
- summary: content.slice(0, 500),
673073
- sourcePath: this.options.streamEnabled ? "stream" : "batch",
673074
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
673075
- });
673076
- break;
673077
- }
673078
673629
  if (isThinkOnly) {
673079
673630
  if (consecutiveThinkOnly >= MAX_CONSECUTIVE_THINK_ONLY) {
673080
673631
  const recentSuccesses = this._adversaryToolOutcomes.slice(-3).filter((o2) => o2.succeeded);
@@ -673412,6 +673963,7 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
673412
673963
  this._insertContextFrame(compactedMsgs, await this._buildTurnContextFrame(turn, compactedMsgs, void 0, bfEnvironmentBlock));
673413
673964
  this.gcSystemMessages(compactedMsgs);
673414
673965
  const modelFacingMessages = this._prepareModelFacingMessages(compactedMsgs, turn);
673966
+ this._injectTaskCloseoutReconciliationContext(modelFacingMessages);
673415
673967
  const bfEchoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
673416
673968
  if (this._echoTempBoostTurns > 0)
673417
673969
  this._echoTempBoostTurns--;
@@ -673943,10 +674495,34 @@ ${terminalFeedback.slice(0, 4e3)}`,
673943
674495
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
673944
674496
  });
673945
674497
  }
674498
+ const expectedOutcomeAssessment = this._currentExpectedOutcomeAssessment();
674499
+ if (completed && !declaredDegradedCompletion && expectedOutcomeAssessment && !expectedOutcomeAssessment.satisfied) {
674500
+ const attemptedSummary = summary.trim();
674501
+ const missing = expectedOutcomeAssessment.missingEffects.join(", ");
674502
+ const observed = expectedOutcomeAssessment.observedEffects.join(", ") || "none";
674503
+ completed = false;
674504
+ summary = [
674505
+ "INCOMPLETE_VERIFICATION: declared success did not satisfy the host-bound expected outcome.",
674506
+ `Outcome: ${expectedOutcomeAssessment.outcome}`,
674507
+ `Missing effects: ${missing}`,
674508
+ `Observed effects: ${observed}`,
674509
+ ...attemptedSummary ? [`Attempted terminal summary: ${attemptedSummary.slice(0, 1200)}`] : []
674510
+ ].join("\n");
674511
+ this._completionIncompleteVerification = {
674512
+ reason: "completion_evidence_missing",
674513
+ summary
674514
+ };
674515
+ this.emit({
674516
+ type: "status",
674517
+ content: `expected outcome not satisfied; terminal success downgraded without retry (missing: ${missing})`,
674518
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
674519
+ });
674520
+ }
673946
674521
  let runStatus = declaredDegradedCompletion ? "incomplete" : completed ? "completed" : this._completionLedger?.status === "blocked" || this._completionLedger?.status === "request_changes" || this._completionLedger?.status === "incomplete_verification" ? "incomplete_verification" : this._completionIncompleteVerification ? "incomplete_verification" : "incomplete";
673947
674522
  const terminalReceipt = this._commitTerminalFinalization({
673948
674523
  status: runStatus,
673949
674524
  summary,
674525
+ expectedOutcomeAssessment,
673950
674526
  trajectoryPayload: {
673951
674527
  task: persistentTaskGoal.slice(0, 1e3),
673952
674528
  outcome: completed ? "pass" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "incomplete",
@@ -673961,7 +674537,9 @@ ${terminalFeedback.slice(0, 4e3)}`,
673961
674537
  totalToolCalls: toolCallCount,
673962
674538
  totalTokens,
673963
674539
  filesModified: [...this._taskState.modifiedFiles.keys()],
673964
- durationMs
674540
+ durationMs,
674541
+ expectedOutcomeContract: this.options.expectedOutcomeContract,
674542
+ expectedOutcomeAssessment
673965
674543
  }
673966
674544
  });
673967
674545
  if (!terminalReceipt) {
@@ -674772,7 +675350,10 @@ ${detail}` : detail;
674772
675350
  testsRun,
674773
675351
  provenanceAnchors,
674774
675352
  gitProgress: this._gitProgressSummary(),
674775
- terminalReceiptId: terminalReceipt?.id
675353
+ terminalReceiptId: terminalReceipt?.id,
675354
+ expectedOutcomeContract: this.options.expectedOutcomeContract,
675355
+ expectedOutcomeAssessment,
675356
+ deliveryReceipts: [...this._completionDeliveryReceipts.values()]
674776
675357
  };
674777
675358
  }
674778
675359
  // -------------------------------------------------------------------------
@@ -680454,6 +681035,7 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
680454
681035
  const textToolParse = parseTextToolCalls(content.replace(/<think>[\s\S]*?<\/think>/g, "").trim(), modelProfile);
680455
681036
  const cleanContent = stripXmlControlBlocks(textToolParse.content, modelProfile);
680456
681037
  if (cleanContent) {
681038
+ this._observeExpectedOutcomeEffect("visible_response");
680457
681039
  this.emit({
680458
681040
  type: "assistant_text",
680459
681041
  content: cleanContent,
@@ -689223,6 +689805,7 @@ __export(dist_exports3, {
689223
689805
  applyWorldPatch: () => applyWorldPatch,
689224
689806
  arcSummary: () => arcSummary,
689225
689807
  artifactReference: () => artifactReference,
689808
+ assessExpectedOutcomeContractV1: () => assessExpectedOutcomeContractV1,
689226
689809
  auditCompletionClaims: () => auditCompletionClaims,
689227
689810
  auditPerceptionClaims: () => auditPerceptionClaims,
689228
689811
  brokerQueueDeadlineResponse: () => brokerQueueDeadlineResponse,
@@ -689257,6 +689840,7 @@ __export(dist_exports3, {
689257
689840
  buildSkillDescription: () => buildSkillDescription,
689258
689841
  buildSteeringPacket: () => buildSteeringPacket,
689259
689842
  buildSubAgentSystemPrompt: () => buildSubAgentSystemPrompt,
689843
+ buildTodoRenderModel: () => buildTodoRenderModel,
689260
689844
  buildTrajectoryCheckpoint: () => buildTrajectoryCheckpoint,
689261
689845
  buildTrajectoryGroundingPrompt: () => buildTrajectoryGroundingPrompt,
689262
689846
  buildUnitTodos: () => buildUnitTodos,
@@ -689311,6 +689895,9 @@ __export(dist_exports3, {
689311
689895
  createRootFeatureNode: () => createRootFeatureNode,
689312
689896
  createServicesManifest: () => createServicesManifest,
689313
689897
  createSteeringIngress: () => createSteeringIngress,
689898
+ createTodoSnapshot: () => createTodoSnapshot,
689899
+ createTodoSnapshotEvent: () => createTodoSnapshotEvent,
689900
+ createTodoTransitionEvents: () => createTodoTransitionEvents,
689314
689901
  createValidationContract: () => createValidationContract,
689315
689902
  criticalPathDepth: () => criticalPathDepth,
689316
689903
  debugArtifactRoot: () => debugArtifactRoot,
@@ -689329,6 +689916,7 @@ __export(dist_exports3, {
689329
689916
  detectGitProgressBaseline: () => detectGitProgressBaseline,
689330
689917
  detectPressure: () => detectPressure,
689331
689918
  detectTaskType: () => detectTaskType,
689919
+ diffTodoSnapshots: () => diffTodoSnapshots,
689332
689920
  discoverPlugins: () => discoverPlugins3,
689333
689921
  discoverSystemOllamaModelStore: () => discoverSystemOllamaModelStore,
689334
689922
  effectiveContextWindow: () => effectiveContextWindow,
@@ -689341,6 +689929,7 @@ __export(dist_exports3, {
689341
689929
  executeBatch: () => executeBatch,
689342
689930
  executeHook: () => executeHook,
689343
689931
  expandContextReference: () => expandContextReference,
689932
+ expectedOutcomeAllowsTextOnlyCompletion: () => expectedOutcomeAllowsTextOnlyCompletion,
689344
689933
  extractClaims: () => extractClaims,
689345
689934
  extractConstraint: () => extractConstraint,
689346
689935
  extractContextSpansForGroundedness: () => extractContextSpansForGroundedness,
@@ -689424,7 +690013,9 @@ __export(dist_exports3, {
689424
690013
  mintClaimScopeToken: () => mintClaimScopeToken,
689425
690014
  mintScopeToken: () => mintScopeToken,
689426
690015
  missingCapabilityRecovery: () => missingCapabilityRecovery,
690016
+ normalizeCompletionDeliveryReceipt: () => normalizeCompletionDeliveryReceipt,
689427
690017
  normalizeCompletionKey: () => normalizeCompletionKey,
690018
+ normalizeExpectedOutcomeContractV1: () => normalizeExpectedOutcomeContractV1,
689428
690019
  normalizeMemoryCompilationPlanAudit: () => normalizeMemoryCompilationPlanAudit,
689429
690020
  noteAfterTask: () => noteAfterTask,
689430
690021
  operationalWorldStatePath: () => operationalWorldStatePath,
@@ -689592,6 +690183,7 @@ var init_dist8 = __esm({
689592
690183
  init_reference_contracts();
689593
690184
  init_deliveryCoverage();
689594
690185
  init_completionFinalization();
690186
+ init_expectedOutcomeContract();
689595
690187
  init_ollama_pool();
689596
690188
  init_ollama_pool_cleanup();
689597
690189
  init_modelProfile();
@@ -689612,6 +690204,7 @@ var init_dist8 = __esm({
689612
690204
  init_completionLedger();
689613
690205
  init_integrationClosure();
689614
690206
  init_runEvents();
690207
+ init_todoObservability();
689615
690208
  init_costTracker();
689616
690209
  init_workEvaluator();
689617
690210
  init_model_router();
@@ -701364,6 +701957,7 @@ var init_steering_stream_filter = __esm({
701364
701957
  if (whitespace > 0) this.buffer = this.buffer.slice(whitespace);
701365
701958
  if (!this.buffer) break;
701366
701959
  const upper = this.buffer.toUpperCase();
701960
+ if (!final2 && upper === CLOSE_STEM) break;
701367
701961
  if (upper.startsWith(CLOSE_STEM)) {
701368
701962
  this.buffer = this.buffer.slice(CLOSE_STEM.length);
701369
701963
  if (this.buffer.startsWith("]")) this.buffer = this.buffer.slice(1);
@@ -781935,6 +782529,21 @@ function telegramInteractionDecisionResponseFormatForPacket(packet) {
781935
782529
  },
781936
782530
  maxItems: 16
781937
782531
  };
782532
+ const outcomeContract = properties.expected_outcome_contract;
782533
+ if (outcomeContract.properties) {
782534
+ outcomeContract.properties.input_id = {
782535
+ type: "string",
782536
+ enum: [packet.inputId]
782537
+ };
782538
+ outcomeContract.properties.cited_evidence_ids = {
782539
+ type: "array",
782540
+ items: {
782541
+ type: "string",
782542
+ enum: packet.evidence.map((entry) => entry.id)
782543
+ },
782544
+ maxItems: 16
782545
+ };
782546
+ }
781938
782547
  return format3;
781939
782548
  }
781940
782549
  function extractPartialTelegramReplyJson(buffer2) {
@@ -782101,6 +782710,24 @@ function telegramThinkSuppressedRequest(request) {
782101
782710
  ) : [];
782102
782711
  return { ...request, messages: messages2, think: false };
782103
782712
  }
782713
+ function parseTelegramExpectedOutcomeContract(value2) {
782714
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
782715
+ const raw = value2;
782716
+ return normalizeExpectedOutcomeContractV1({
782717
+ schema: raw["schema"],
782718
+ route: raw["route"],
782719
+ continuity: raw["continuity"],
782720
+ activeScopeId: raw["active_scope_id"] ?? raw["activeScopeId"],
782721
+ citedEvidenceIds: raw["cited_evidence_ids"] ?? raw["citedEvidenceIds"],
782722
+ confidence: raw["confidence"],
782723
+ reason: raw["reason"],
782724
+ planningMode: raw["planning_mode"] ?? raw["planningMode"],
782725
+ outcome: raw["outcome"],
782726
+ requiredEffects: raw["required_effects"] ?? raw["requiredEffects"],
782727
+ inputId: raw["input_id"] ?? raw["inputId"],
782728
+ decisionId: raw["decision_id"] ?? raw["decisionId"]
782729
+ });
782730
+ }
782104
782731
  function parseTelegramInteractionDecision(text3, forcedRoute, options2 = {}) {
782105
782732
  for (const jsonText of telegramDecisionJsonCandidates(text3)) {
782106
782733
  try {
@@ -782110,6 +782737,9 @@ function parseTelegramInteractionDecision(text3, forcedRoute, options2 = {}) {
782110
782737
  const parsedRoute = parsed["route"] === "chat" || parsed["route"] === "action" ? parsed["route"] : null;
782111
782738
  const route = forcedRoute ?? parsedRoute;
782112
782739
  if (!route) continue;
782740
+ const expectedOutcomeContract = parseTelegramExpectedOutcomeContract(
782741
+ parsed["expected_outcome_contract"] ?? parsed["expectedOutcomeContract"]
782742
+ );
782113
782743
  const shouldReplyRaw = parsed["should_reply"] ?? parsed["shouldReply"];
782114
782744
  if (options2.requireShouldReply && typeof shouldReplyRaw !== "boolean")
782115
782745
  continue;
@@ -782142,6 +782772,7 @@ function parseTelegramInteractionDecision(text3, forcedRoute, options2 = {}) {
782142
782772
  );
782143
782773
  return {
782144
782774
  route,
782775
+ ...expectedOutcomeContract ? { expectedOutcomeContract } : {},
782145
782776
  shouldReply,
782146
782777
  confidence: confidence2,
782147
782778
  reason,
@@ -782977,6 +783608,10 @@ function normalizeTelegramSubAgentLimit(value2) {
782977
783608
  );
782978
783609
  }
782979
783610
  function selectTelegramFinalResponse(args) {
783611
+ const committedTerminalReply = cleanTelegramVisibleReply(
783612
+ args.terminalUserReply || ""
783613
+ );
783614
+ if (committedTerminalReply) return committedTerminalReply;
782980
783615
  const committedVisibleReply = cleanTelegramVisibleReply(
782981
783616
  args.visibleReplyText || ""
782982
783617
  );
@@ -783040,11 +783675,58 @@ function renderTelegramLiveProgressHTML(progressLines, accumulated, steeringReco
783040
783675
  }
783041
783676
  function telegramAdminLivePanelPageLabel(page2) {
783042
783677
  if (page2 === "response") return "Reply";
783678
+ if (page2 === "tasks") return "Tasks";
783043
783679
  if (page2 === "tools") return "Tools";
783044
783680
  if (page2 === "logs") return "Activity";
783045
783681
  if (page2 === "evidence") return "Evidence";
783046
783682
  return "Context";
783047
783683
  }
783684
+ function telegramAdminTodoProgressLabel(snapshot) {
783685
+ if (!snapshot) return "Tasks";
783686
+ return `Tasks ${snapshot.counts.leafStatus.completed}/${snapshot.counts.leaves}`;
783687
+ }
783688
+ function telegramAdminTodoMarker(status) {
783689
+ if (status === "completed") return "✓";
783690
+ if (status === "in_progress") return "●";
783691
+ if (status === "blocked") return "!";
783692
+ return "○";
783693
+ }
783694
+ function telegramAdminTodoPackets(snapshot) {
783695
+ if (!snapshot) return [];
783696
+ const model = buildTodoRenderModel(snapshot);
783697
+ return model.rows.map((row2) => {
783698
+ const status = row2.directChildCount > 0 ? row2.displayStatus : row2.status;
783699
+ const indentation = " ".repeat(Math.min(6, row2.depth));
783700
+ const detail = [
783701
+ `id=${row2.id}`,
783702
+ `status=${status}`,
783703
+ row2.directChildCount > 0 ? `leaf_progress=${row2.leafCounts.completed}/${Object.values(row2.leafCounts).reduce((sum2, count) => sum2 + count, 0)}` : "",
783704
+ row2.owner ? `owner=${row2.owner}` : "",
783705
+ row2.blocker ? `blocker=${row2.blocker}` : "",
783706
+ row2.blockedBy?.length ? `blocked_by=${row2.blockedBy.join(", ")}` : ""
783707
+ ].filter(Boolean).join("\n");
783708
+ return {
783709
+ title: `${telegramAdminTodoMarker(status)} ${indentation}${row2.content}`,
783710
+ body: detail
783711
+ };
783712
+ });
783713
+ }
783714
+ function telegramAdminTodoTransitionLine(event) {
783715
+ const transition2 = event.transition;
783716
+ if (transition2.kind === "status_changed") {
783717
+ return `${telegramAdminTodoMarker(transition2.to)} ${transition2.item.content}: ${transition2.from} → ${transition2.to}`;
783718
+ }
783719
+ if (transition2.kind === "created") {
783720
+ return `○ ${transition2.item.content}: added`;
783721
+ }
783722
+ if (transition2.kind === "deleted") {
783723
+ return `○ ${transition2.previous.content}: removed`;
783724
+ }
783725
+ if (transition2.kind === "reparented") {
783726
+ return `○ ${transition2.item.content}: moved`;
783727
+ }
783728
+ return `○ ${transition2.item.content}: updated`;
783729
+ }
783048
783730
  function telegramPanelHtmlFallback(html) {
783049
783731
  const chunks = segmentTelegramHtml(html, 3600);
783050
783732
  if (chunks.length <= 1) return chunks[0] ?? "";
@@ -783202,6 +783884,7 @@ function createTelegramAdminLivePanelState(args) {
783202
783884
  activePage: "response",
783203
783885
  dirtyPages: {
783204
783886
  response: false,
783887
+ tasks: false,
783205
783888
  tools: false,
783206
783889
  logs: false,
783207
783890
  evidence: false,
@@ -783214,6 +783897,7 @@ function createTelegramAdminLivePanelState(args) {
783214
783897
  responseSegments: [],
783215
783898
  responseSegmentSequence: 0,
783216
783899
  steeringReconciliations: [],
783900
+ todoTransitionLines: [],
783217
783901
  evidenceText: "",
783218
783902
  toolLines: [],
783219
783903
  mutationLines: [],
@@ -783222,6 +783906,22 @@ function createTelegramAdminLivePanelState(args) {
783222
783906
  contextPages: []
783223
783907
  };
783224
783908
  }
783909
+ function applyTelegramAdminLivePanelRunEvent(state5, event) {
783910
+ if (event.type === "todo_snapshot") {
783911
+ state5.todoSnapshot = event.snapshot;
783912
+ state5.updatedAt = Date.now();
783913
+ if (state5.activePage !== "tasks") state5.dirtyPages.tasks = true;
783914
+ return;
783915
+ }
783916
+ if (event.type !== "todo_transition") return;
783917
+ const line = telegramAdminTodoTransitionLine(event);
783918
+ if (state5.todoTransitionLines[state5.todoTransitionLines.length - 1] !== line) {
783919
+ state5.todoTransitionLines.push(line);
783920
+ trimTelegramAdminPanelLines(state5.todoTransitionLines, 24);
783921
+ }
783922
+ state5.updatedAt = Date.now();
783923
+ if (state5.activePage !== "tasks") state5.dirtyPages.tasks = true;
783924
+ }
783225
783925
  function applyTelegramAdminLivePanelEvent(state5, event) {
783226
783926
  if (event.type === "stream_start") {
783227
783927
  const turn = telegramAdminEventTurn(event);
@@ -783315,6 +784015,32 @@ function renderTelegramAdminLivePanelPayload(state5) {
783315
784015
  steeringHtml,
783316
784016
  clipped ? convertMarkdownToTelegramHTML(clipped) : "<i>Working…</i>"
783317
784017
  ].filter(Boolean).join("\n\n");
784018
+ } else if (state5.activePage === "tasks") {
784019
+ const snapshot = state5.todoSnapshot;
784020
+ const model = snapshot ? buildTodoRenderModel(snapshot) : void 0;
784021
+ const transitions = state5.todoTransitionLines.slice(-8);
784022
+ const rendered = renderTelegramPanelPage({
784023
+ title: "Tasks",
784024
+ subtitle: model ? `${model.counts.leafStatus.completed}/${model.counts.leaves} leaf tasks complete; ${model.counts.leafStatus.inProgress} active; ${model.counts.leafStatus.blocked} blocked.` : "No checklist exists for this run.",
784025
+ metadata,
784026
+ sections: [
784027
+ {
784028
+ title: "Checklist",
784029
+ packets: telegramAdminTodoPackets(snapshot)
784030
+ },
784031
+ {
784032
+ title: "Recent changes",
784033
+ packets: transitions.map((line, index) => ({
784034
+ title: `Change ${index + 1}`,
784035
+ body: line
784036
+ }))
784037
+ }
784038
+ ],
784039
+ emptyText: "No checklist exists for this run.",
784040
+ footer: "Page 2 of 6 · Tasks"
784041
+ });
784042
+ body = telegramPanelHtmlFallback(rendered.html);
784043
+ richHtml = rendered.richHtml;
783318
784044
  } else if (state5.activePage === "tools") {
783319
784045
  const lines = state5.toolLines.slice(-12);
783320
784046
  const rendered = renderTelegramPanelPage({
@@ -783323,7 +784049,7 @@ function renderTelegramAdminLivePanelPayload(state5) {
783323
784049
  metadata,
783324
784050
  sections: [{ packets: telegramAdminLinePackets(lines, "Tool event") }],
783325
784051
  emptyText: "No tool calls yet.",
783326
- footer: "Page 2 of 5 · Tools"
784052
+ footer: "Page 3 of 6 · Tools"
783327
784053
  });
783328
784054
  body = telegramPanelHtmlFallback(rendered.html);
783329
784055
  richHtml = rendered.richHtml;
@@ -783345,7 +784071,7 @@ function renderTelegramAdminLivePanelPayload(state5) {
783345
784071
  }
783346
784072
  ],
783347
784073
  emptyText: "No workspace changes or runner activity yet.",
783348
- footer: "Page 3 of 5 · Activity"
784074
+ footer: "Page 4 of 6 · Activity"
783349
784075
  });
783350
784076
  body = telegramPanelHtmlFallback(rendered.html);
783351
784077
  richHtml = rendered.richHtml;
@@ -783360,7 +784086,7 @@ function renderTelegramAdminLivePanelPayload(state5) {
783360
784086
  metadata,
783361
784087
  sections: [{ packets }],
783362
784088
  emptyText: "No completion evidence yet.",
783363
- footer: "Page 4 of 5 · Evidence"
784089
+ footer: "Page 5 of 6 · Evidence"
783364
784090
  });
783365
784091
  body = telegramPanelHtmlFallback(rendered.html);
783366
784092
  richHtml = rendered.richHtml;
@@ -783383,7 +784109,7 @@ function renderTelegramAdminLivePanelPayload(state5) {
783383
784109
  }
783384
784110
  const text3 = body;
783385
784111
  const pageButtons = TELEGRAM_ADMIN_LIVE_PANEL_PAGES.map((page2) => ({
783386
- text: `${page2 === state5.activePage ? "●" : "○"} ${telegramAdminLivePanelPageLabel(page2)}${state5.dirtyPages[page2] ? " *" : ""}`,
784112
+ text: `${page2 === state5.activePage ? "●" : "○"} ${page2 === "tasks" ? telegramAdminTodoProgressLabel(state5.todoSnapshot) : telegramAdminLivePanelPageLabel(page2)}${state5.dirtyPages[page2] ? " *" : ""}`,
783387
784113
  callback_data: `omni:v1:tgadmin:${state5.nonce}:page:${page2}`,
783388
784114
  ...page2 === state5.activePage ? { style: "primary" } : {}
783389
784115
  }));
@@ -784734,6 +785460,7 @@ Telegram link integrity contract:
784734
785460
  required: [
784735
785461
  "input_id",
784736
785462
  "route",
785463
+ "expected_outcome_contract",
784737
785464
  "should_reply",
784738
785465
  "confidence",
784739
785466
  "reason",
@@ -784746,6 +785473,65 @@ Telegram link integrity contract:
784746
785473
  recoverable: { type: "boolean" },
784747
785474
  input_id: { type: "string" },
784748
785475
  route: { type: "string", enum: ["chat", "action"] },
785476
+ expected_outcome_contract: {
785477
+ type: "object",
785478
+ additionalProperties: false,
785479
+ required: [
785480
+ "schema",
785481
+ "route",
785482
+ "continuity",
785483
+ "cited_evidence_ids",
785484
+ "confidence",
785485
+ "reason",
785486
+ "planning_mode",
785487
+ "outcome",
785488
+ "required_effects",
785489
+ "input_id"
785490
+ ],
785491
+ properties: {
785492
+ schema: {
785493
+ type: "string",
785494
+ enum: ["omnius.expected-outcome-contract.v1"]
785495
+ },
785496
+ route: { type: "string", enum: ["chat", "action"] },
785497
+ continuity: {
785498
+ type: "string",
785499
+ enum: ["new", "continue_active", "status_probe", "replace"]
785500
+ },
785501
+ active_scope_id: { anyOf: [{ type: "string" }, { type: "null" }] },
785502
+ cited_evidence_ids: {
785503
+ type: "array",
785504
+ items: { type: "string" },
785505
+ maxItems: 16
785506
+ },
785507
+ confidence: { type: "number", minimum: 0, maximum: 1 },
785508
+ reason: { type: "string" },
785509
+ planning_mode: {
785510
+ type: "string",
785511
+ enum: ["none", "checklist"]
785512
+ },
785513
+ outcome: {
785514
+ type: "string",
785515
+ enum: ["conversation", "read_only", "mutation", "delivery"]
785516
+ },
785517
+ required_effects: {
785518
+ type: "array",
785519
+ items: {
785520
+ type: "string",
785521
+ enum: [
785522
+ "visible_response",
785523
+ "observation",
785524
+ "mutation",
785525
+ "verification",
785526
+ "delivery"
785527
+ ]
785528
+ },
785529
+ minItems: 1,
785530
+ maxItems: 5
785531
+ },
785532
+ input_id: { type: "string" }
785533
+ }
785534
+ },
784749
785535
  should_reply: { type: "boolean" },
784750
785536
  confidence: { type: "number", minimum: 0, maximum: 1 },
784751
785537
  reason: { type: "string" },
@@ -784842,7 +785628,7 @@ Telegram link integrity contract:
784842
785628
  TELEGRAM_MODERATION_APPROVAL_TTL_MS = 5 * 6e4;
784843
785629
  TELEGRAM_MODERATION_APPROVAL_RETENTION_MS = 24 * 60 * 6e4;
784844
785630
  TELEGRAM_MODERATION_APPROVAL_MAX_RECORDS = 64;
784845
- TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA = `{"input_id":"exact host input_id","route":"chat"|"action","should_reply":true|false,"confidence":0.0-1.0,"reason":"short reason","addressed_actor_keys":["only actor keys from evidence packet"],"self_role":"addressee"|"participant"|"observer"|"uncertain","reply_basis":"direct_turn"|"ongoing_self_task"|"social_intervention"|"none"|"uncertain","evidence_ids":["only evidence ids from evidence packet"],"attention_state":"idle"|"observing"|"engaged"|"cooldown","attention_delta":-1.0..1.0,"next_check_after_messages":1..12,"reply_mode_preference":null|{"scope":"current_user_in_chat"|"current_user_global"|"current_group","reply_mode":"reply_then_notes"|"notes_then_reply"|"reply_only","confidence":0.0-1.0,"note":"explicit durable cadence preference"}}`;
785631
+ TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA = `{"input_id":"exact host input_id","route":"chat"|"action","expected_outcome_contract":{"schema":"omnius.expected-outcome-contract.v1","route":"chat"|"action","continuity":"new"|"continue_active"|"status_probe"|"replace","active_scope_id":null|"active task scope id","cited_evidence_ids":["only evidence ids from evidence packet"],"confidence":0.0-1.0,"reason":"short outcome reason","planning_mode":"none"|"checklist","outcome":"conversation"|"read_only"|"mutation"|"delivery","required_effects":["visible_response"|"observation"|"mutation"|"verification"|"delivery"],"input_id":"exact host input_id"},"should_reply":true|false,"confidence":0.0-1.0,"reason":"short reason","addressed_actor_keys":["only actor keys from evidence packet"],"self_role":"addressee"|"participant"|"observer"|"uncertain","reply_basis":"direct_turn"|"ongoing_self_task"|"social_intervention"|"none"|"uncertain","evidence_ids":["only evidence ids from evidence packet"],"attention_state":"idle"|"observing"|"engaged"|"cooldown","attention_delta":-1.0..1.0,"next_check_after_messages":1..12,"reply_mode_preference":null|{"scope":"current_user_in_chat"|"current_user_global"|"current_group","reply_mode":"reply_then_notes"|"notes_then_reply"|"reply_only","confidence":0.0-1.0,"note":"explicit durable cadence preference"}}`;
784846
785632
  TELEGRAM_CHAT_REPLY_RESPONSE_FORMAT = {
784847
785633
  type: "json_schema",
784848
785634
  json_schema: {
@@ -785021,6 +785807,7 @@ Telegram link integrity contract:
785021
785807
  TELEGRAM_SUB_AGENT_BURST_CONTEXT_LIMIT = 20;
785022
785808
  TELEGRAM_ADMIN_LIVE_PANEL_PAGES = [
785023
785809
  "response",
785810
+ "tasks",
785024
785811
  "tools",
785025
785812
  "logs",
785026
785813
  "evidence",
@@ -786377,7 +787164,7 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
786377
787164
  }
786378
787165
  buildTelegramRouterUnavailableDecision(msg, toolContext, params) {
786379
787166
  const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
786380
- const route = forcedRoute ?? (msg.chatType === "private" ? "chat" : "action");
787167
+ const route = forcedRoute ?? (toolContext === "telegram-admin-dm" ? "action" : msg.chatType === "private" ? "chat" : "action");
786381
787168
  const failOpen = this.shouldFailOpenTelegramRouterUnavailable(
786382
787169
  msg,
786383
787170
  toolContext
@@ -787758,7 +788545,7 @@ Model: <code>${escapeTelegramHTML(model.id)}</code>`
787758
788545
  const summary = result.success ? [
787759
788546
  `<b>Generation complete</b>`,
787760
788547
  artifactCount > 0 ? `Sent ${artifactCount} artifact${artifactCount === 1 ? "" : "s"}.` : "No artifact file was detected in the tool result.",
787761
- `<blockquote expandable>${escapeTelegramHTML(result.output || result.llmContent || "Done.")}</blockquote>`
788548
+ `<blockquote expandable>${escapeTelegramHTML(result.output || result.llmContent || "The generation tool returned no text.")}</blockquote>`
787762
788549
  ].join("\n") : [
787763
788550
  `<b>Generation failed</b>`,
787764
788551
  `<blockquote expandable>${escapeTelegramHTML(result.error || result.output || "Unknown failure.")}</blockquote>`
@@ -792642,6 +793429,39 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
792642
793429
  message: `input_id must be ${JSON.stringify(packet.inputId)}.`
792643
793430
  });
792644
793431
  }
793432
+ const expectedOutcomeContract = decision2.expectedOutcomeContract ? normalizeExpectedOutcomeContractV1(decision2.expectedOutcomeContract) : null;
793433
+ if (expectedOutcomeContract) {
793434
+ if (expectedOutcomeContract.route !== decision2.route) {
793435
+ issues.push({
793436
+ code: "outcome_route_mismatch",
793437
+ message: `expected_outcome_contract.route must match route=${decision2.route}.`
793438
+ });
793439
+ }
793440
+ if (expectedOutcomeContract.inputId !== packet.inputId) {
793441
+ issues.push({
793442
+ code: "outcome_input_id_mismatch",
793443
+ message: `expected_outcome_contract.input_id must be ${JSON.stringify(packet.inputId)}.`
793444
+ });
793445
+ }
793446
+ const allowedOutcomeEvidence = new Set(
793447
+ packet.evidence.map((entry) => entry.id)
793448
+ );
793449
+ const unknownOutcomeEvidence = expectedOutcomeContract.citedEvidenceIds.filter(
793450
+ (id2) => !allowedOutcomeEvidence.has(id2)
793451
+ );
793452
+ if (unknownOutcomeEvidence.length > 0) {
793453
+ issues.push({
793454
+ code: "unknown_outcome_evidence_id",
793455
+ message: `expected_outcome_contract.cited_evidence_ids contains unknown values ${JSON.stringify(unknownOutcomeEvidence)}.`
793456
+ });
793457
+ }
793458
+ if (decision2.shouldReply && !expectedOutcomeContract.requiredEffects.includes("visible_response")) {
793459
+ issues.push({
793460
+ code: "reply_outcome_missing_visible_response",
793461
+ message: "A reply-worthy Telegram decision requires visible_response in expected_outcome_contract.required_effects."
793462
+ });
793463
+ }
793464
+ }
792645
793465
  if (!decision2.selfRole) {
792646
793466
  issues.push({
792647
793467
  code: "missing_self_role",
@@ -792730,6 +793550,7 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
792730
793550
  JSON.stringify({
792731
793551
  inputId: packet.inputId,
792732
793552
  route: decision2.route,
793553
+ expectedOutcomeContract,
792733
793554
  shouldReply: decision2.shouldReply,
792734
793555
  addressed,
792735
793556
  selfRole: decision2.selfRole,
@@ -792737,15 +793558,55 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
792737
793558
  evidenceIds
792738
793559
  })
792739
793560
  ).digest("hex").slice(0, 20)}`;
792740
- return { decision: { ...decision2, decisionId }, issues: [] };
793561
+ return {
793562
+ decision: {
793563
+ ...decision2,
793564
+ decisionId,
793565
+ ...expectedOutcomeContract ? {
793566
+ expectedOutcomeContract: {
793567
+ ...expectedOutcomeContract,
793568
+ inputId: packet.inputId,
793569
+ decisionId
793570
+ }
793571
+ } : {}
793572
+ },
793573
+ issues: []
793574
+ };
792741
793575
  }
792742
793576
  validateTelegramInteractionDecision(decision2, packet) {
792743
793577
  return this.validateTelegramInteractionDecisionDetailed(decision2, packet).decision;
792744
793578
  }
793579
+ /**
793580
+ * Materialize identity fields that are logical consequences of the model's
793581
+ * selected reply basis. The model remains the sole owner of should_reply
793582
+ * and reply_basis. Once it selects direct_turn, however, self_role and the
793583
+ * self actor citation are redundant representations of the same decision.
793584
+ * Reconcile those fields locally instead of rejecting an otherwise valid
793585
+ * model-authored reply decision or spending a second inference on it.
793586
+ */
793587
+ normalizeTelegramInteractionDecisionImplications(decision2, packet) {
793588
+ if (decision2.replyBasis !== "direct_turn") return decision2;
793589
+ return {
793590
+ ...decision2,
793591
+ addressedActorKeys: [
793592
+ .../* @__PURE__ */ new Set([
793593
+ ...decision2.addressedActorKeys ?? [],
793594
+ packet.selfActorKey
793595
+ ])
793596
+ ],
793597
+ selfRole: "addressee"
793598
+ };
793599
+ }
792745
793600
  bindTrustedTelegramDecision(decision2, packet) {
792746
793601
  const bound = {
792747
793602
  ...decision2,
792748
793603
  inputId: packet.inputId,
793604
+ ...decision2.expectedOutcomeContract ? {
793605
+ expectedOutcomeContract: {
793606
+ ...decision2.expectedOutcomeContract,
793607
+ inputId: packet.inputId
793608
+ }
793609
+ } : {},
792749
793610
  addressedActorKeys: [packet.selfActorKey],
792750
793611
  selfRole: "addressee",
792751
793612
  replyBasis: "direct_turn",
@@ -792805,11 +793666,23 @@ arguments=` : ""}` + (chunk.toolCallArgs ?? "");
792805
793666
  defaultShouldReply: false,
792806
793667
  requireShouldReply: true
792807
793668
  });
792808
- if (parsed && evidencePacket) parsed.inputId = evidencePacket.inputId;
792809
- const validation = parsed && evidencePacket ? this.validateTelegramInteractionDecisionDetailed(
793669
+ if (parsed && evidencePacket) {
793670
+ parsed.inputId = evidencePacket.inputId;
793671
+ if (parsed.expectedOutcomeContract) {
793672
+ parsed.expectedOutcomeContract = {
793673
+ ...parsed.expectedOutcomeContract,
793674
+ inputId: evidencePacket.inputId
793675
+ };
793676
+ }
793677
+ }
793678
+ const normalized4 = parsed && evidencePacket ? this.normalizeTelegramInteractionDecisionImplications(
792810
793679
  parsed,
792811
793680
  evidencePacket
792812
- ) : { decision: parsed, issues: [] };
793681
+ ) : parsed;
793682
+ const validation = normalized4 && evidencePacket ? this.validateTelegramInteractionDecisionDetailed(
793683
+ normalized4,
793684
+ evidencePacket
793685
+ ) : { decision: normalized4, issues: [] };
792813
793686
  const validated = validation.decision;
792814
793687
  if (!validated) {
792815
793688
  if (diagnostics) {
@@ -793168,8 +794041,9 @@ ${retryText}`,
793168
794041
  })()
793169
794042
  });
793170
794043
  if (!config) {
794044
+ const fallbackRoute = forcedRoute ?? (toolContext === "telegram-admin-dm" ? "action" : isGroup ? "action" : "chat");
793171
794045
  const fallback = {
793172
- route: forcedRoute ?? (isGroup ? "action" : "chat"),
794046
+ route: fallbackRoute,
793173
794047
  shouldReply: false,
793174
794048
  confidence: 0,
793175
794049
  reason: "router inference unavailable; no model-derived reply decision",
@@ -793276,6 +794150,10 @@ ${stimulationProbe.context}`,
793276
794150
  `Target binding: infer the addressees and this bot's role before should_reply. Another actor being addressed does not force silence; a reply can still be valid for an ongoing self-owned task or a socially useful intervention, but it must use that reply_basis and cite current evidence.`,
793277
794151
  `Authorization integrity: should_reply=true requires a non-none, non-uncertain reply_basis and at least one cited evidence_id. direct_turn requires self_role=addressee and the self actor key in addressed_actor_keys. ongoing_self_task requires the active_task evidence id.`,
793278
794152
  `Classification boundary: decide whether an action runner is needed, but do not execute a tool and do not emit a tool invocation. A required capability is represented only by route="action" in the attention schema.`,
794153
+ `Expected-outcome boundary: produce expected_outcome_contract from the current input and cited host evidence. Do not derive it from keywords or a fixed request-category table.`,
794154
+ `Required effects are cumulative. Use visible_response for conversation. Use observation for a current factual inspection. Use mutation for a requested state change. Add verification when the requested result must be checked after the final mutation. Use delivery only when an external provider acknowledgement is part of success.`,
794155
+ `Use planning_mode="checklist" when the inferred work has multiple substantive dependent effects. Use planning_mode="none" for direct conversation or one bounded effect.`,
794156
+ `Continuity and active_scope_id must describe whether this input starts, continues, probes, or replaces the active scoped task. Cite only evidence IDs supplied by the host.`,
793279
794157
  ``,
793280
794158
  `Schema: ${TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA}`,
793281
794159
  ``,
@@ -793403,10 +794281,22 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
793403
794281
  defaultShouldReply: false,
793404
794282
  requireShouldReply: true
793405
794283
  });
793406
- if (parsed) parsed.inputId = evidencePacket.inputId;
793407
- const initialValidation = parsed ? this.validateTelegramInteractionDecisionDetailed(
794284
+ if (parsed) {
794285
+ parsed.inputId = evidencePacket.inputId;
794286
+ if (parsed.expectedOutcomeContract) {
794287
+ parsed.expectedOutcomeContract = {
794288
+ ...parsed.expectedOutcomeContract,
794289
+ inputId: evidencePacket.inputId
794290
+ };
794291
+ }
794292
+ }
794293
+ const normalized4 = parsed ? this.normalizeTelegramInteractionDecisionImplications(
793408
794294
  parsed,
793409
794295
  evidencePacket
794296
+ ) : null;
794297
+ const initialValidation = normalized4 ? this.validateTelegramInteractionDecisionDetailed(
794298
+ normalized4,
794299
+ evidencePacket
793410
794300
  ) : {
793411
794301
  decision: null,
793412
794302
  issues: []
@@ -794812,7 +795702,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
794812
795702
  if (event.contextFrame || state5.contextPages.length === 0 && (subAgent.contextFrame || subAgent.promptSnapshot)) {
794813
795703
  this.refreshTelegramAdminLivePanelContextPages(state5, subAgent, msg);
794814
795704
  }
794815
- if (state5.messageId === void 0 && !state5.responseText.trim()) {
795705
+ if (state5.messageId === void 0 && !state5.responseText.trim() && !state5.todoSnapshot && state5.toolLines.length === 0 && state5.mutationLines.length === 0 && state5.logLines.length === 0) {
794816
795706
  return;
794817
795707
  }
794818
795708
  const now2 = Date.now();
@@ -794828,13 +795718,29 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
794828
795718
  });
794829
795719
  }
794830
795720
  }
795721
+ updateTelegramAdminLivePanelFromRunEvent(subAgent, msg, event) {
795722
+ const state5 = this.ensureTelegramAdminLivePanel(subAgent, msg);
795723
+ applyTelegramAdminLivePanelRunEvent(state5, event);
795724
+ const now2 = Date.now();
795725
+ if (state5.messageId !== void 0 && now2 - subAgent.lastEditMs <= 900) {
795726
+ return;
795727
+ }
795728
+ subAgent.lastEditMs = now2;
795729
+ if (subAgent.liveMessagePromise) return;
795730
+ subAgent.liveMessagePromise = this.renderTelegramAdminLivePanel(state5).then(() => {
795731
+ subAgent.liveMessageId = state5.messageId ?? null;
795732
+ }).catch(() => {
795733
+ }).finally(() => {
795734
+ subAgent.liveMessagePromise = null;
795735
+ });
795736
+ }
794831
795737
  async finalizeTelegramAdminLivePanel(subAgent, msg, replyText, status = "completed", evidenceText = "") {
794832
795738
  const state5 = this.ensureTelegramAdminLivePanel(subAgent, msg);
794833
795739
  state5.status = status;
794834
795740
  state5.steeringReconciliations = [
794835
795741
  ...subAgent.steeringReconciliations.values()
794836
795742
  ];
794837
- state5.responseText = replyText || (status === "failed" ? "I couldn't complete that request." : "Done.");
795743
+ state5.responseText = replyText || (status === "failed" ? "I couldn't complete that request. Open Evidence for the recorded blocker." : "The run reached its completion boundary, but it did not produce a user-facing result. Open Evidence for the recorded outcome.");
794838
795744
  state5.responseSegments = [];
794839
795745
  state5.activeResponseSegmentKey = void 0;
794840
795746
  if (evidenceText.trim()) {
@@ -794938,6 +795844,8 @@ ${signals || "No final validating tool/status signal was available."}`
794938
795844
  const verified = [
794939
795845
  `Backend status: ${subAgent.runnerStatus || (subAgent.runnerCompleted ? "completed" : "unknown")}.`,
794940
795846
  stats ? `Run shape: ${stats}.` : "",
795847
+ subAgent.runnerTerminalReceiptId ? `Terminal receipt: ${subAgent.runnerTerminalReceiptId}.` : "",
795848
+ subAgent.runnerExpectedOutcomeAssessment ? `Expected outcome: ${subAgent.runnerExpectedOutcomeAssessment.satisfied ? "satisfied" : "not satisfied"}; observed ${subAgent.runnerExpectedOutcomeAssessment.observedEffects.join(", ") || "none"}; missing ${subAgent.runnerExpectedOutcomeAssessment.missingEffects.join(", ") || "none"}.` : "",
794941
795849
  failures.length > 0 ? `⚠ ${failures.length} tool call(s) failed without a confirmed retry — treat any success claim above as unverified.` : "",
794942
795850
  summary && summary !== finalText ? `Runner summary: ${summary}` : ""
794943
795851
  ].filter(Boolean).join("\n");
@@ -795731,16 +796639,23 @@ Join: ${newUrl}`
795731
796639
  );
795732
796640
  let decision2;
795733
796641
  if (isAdminDM) {
795734
- decision2 = {
795735
- route: this.interactionMode === "action" ? "action" : "chat",
795736
- shouldReply: true,
795737
- confidence: 1,
795738
- reason: "authenticated admin DM is direct operator work",
795739
- source: "forced-mode",
795740
- silentDisposition: "directly admitted to the Telegram AgenticRunner",
795741
- routerMode: "consolidated",
795742
- routerLatencyMs: 0
795743
- };
796642
+ try {
796643
+ decision2 = await this.inferTelegramInteractionDecisionCoalesced(
796644
+ msg,
796645
+ toolContext
796646
+ );
796647
+ } catch (err) {
796648
+ decision2 = this.fallbackTelegramRouterDecision(msg, toolContext, err);
796649
+ }
796650
+ decision2 = this.bindTrustedTelegramDecision(
796651
+ {
796652
+ ...decision2,
796653
+ shouldReply: true,
796654
+ reason: `${decision2.reason}; authenticated admin DM is direct operator work`,
796655
+ silentDisposition: "directly admitted to the Telegram AgenticRunner"
796656
+ },
796657
+ this.buildTelegramInteractionEvidencePacket(msg)
796658
+ );
795744
796659
  } else {
795745
796660
  try {
795746
796661
  decision2 = await this.inferTelegramInteractionDecisionCoalesced(
@@ -795849,7 +796764,8 @@ Join: ${newUrl}`
795849
796764
  msg,
795850
796765
  toolContext,
795851
796766
  rapidContext,
795852
- decisionContext
796767
+ decisionContext,
796768
+ decision2.expectedOutcomeContract
795853
796769
  );
795854
796770
  if (shouldDeferNotes && visibleReplyDelivered) {
795855
796771
  this.deliverTelegramPostReplyNotes(
@@ -795909,6 +796825,7 @@ Join: ${newUrl}`
795909
796825
  assistantText: "",
795910
796826
  streamText: "",
795911
796827
  visibleReplyText: "",
796828
+ terminalUserReply: "",
795912
796829
  currentStreamToolNames: /* @__PURE__ */ new Set(),
795913
796830
  toolNamesThisRun: /* @__PURE__ */ new Set(),
795914
796831
  successfulToolNamesThisRun: /* @__PURE__ */ new Set(),
@@ -795924,6 +796841,7 @@ Join: ${newUrl}`
795924
796841
  pendingContextPackets: [],
795925
796842
  runId: `telegram:${randomBytes29(8).toString("hex")}`,
795926
796843
  taskEpoch: work.intakeRecords[work.intakeRecords.length - 1]?.taskEpoch ?? this.telegramTaskEpoch(sessionKey),
796844
+ expectedOutcomeContract: decision2.expectedOutcomeContract,
795927
796845
  creativeWorkspaceRoot: this.creativeWorkspaceRootForMessage(
795928
796846
  msg,
795929
796847
  toolContext
@@ -796052,7 +796970,7 @@ Join: ${newUrl}`
796052
796970
  subAgent,
796053
796971
  ""
796054
796972
  );
796055
- const deliveredFinalText2 = "Done.";
796973
+ const deliveredFinalText2 = "The run reached its completion boundary, but it did not produce a user-facing result. Open Evidence for the recorded outcome.";
796056
796974
  this.subAgentViewCallbacks?.onWrite(
796057
796975
  subAgent.viewId,
796058
796976
  `completed: ${evidenceText}`
@@ -796251,7 +797169,7 @@ ${errMsg}`
796251
797169
  }
796252
797170
  }
796253
797171
  /** Admin quick-chat: conversational profile with full admin context/tools. */
796254
- async handleTelegramAdminChatAgent(msg, toolContext, additionalContext = "") {
797172
+ async handleTelegramAdminChatAgent(msg, toolContext, additionalContext = "", authorizationContext = "", expectedOutcomeContract) {
796255
797173
  const sessionKey = this.sessionKeyForMessage(msg);
796256
797174
  const subAgent = {
796257
797175
  chatId: msg.chatId,
@@ -796265,6 +797183,7 @@ ${errMsg}`
796265
797183
  assistantText: "",
796266
797184
  streamText: "",
796267
797185
  visibleReplyText: "",
797186
+ terminalUserReply: "",
796268
797187
  currentStreamToolNames: /* @__PURE__ */ new Set(),
796269
797188
  toolNamesThisRun: /* @__PURE__ */ new Set(),
796270
797189
  successfulToolNamesThisRun: /* @__PURE__ */ new Set(),
@@ -796280,6 +797199,7 @@ ${errMsg}`
796280
797199
  pendingContextPackets: [],
796281
797200
  runId: `telegram:${randomBytes29(8).toString("hex")}`,
796282
797201
  taskEpoch: this.telegramTaskEpoch(sessionKey),
797202
+ expectedOutcomeContract,
796283
797203
  creativeWorkspaceRoot: this.creativeWorkspaceRootForMessage(
796284
797204
  msg,
796285
797205
  toolContext
@@ -796348,7 +797268,8 @@ ${errMsg}`
796348
797268
  subAgent,
796349
797269
  mediaContext,
796350
797270
  "chat",
796351
- additionalContext
797271
+ additionalContext,
797272
+ authorizationContext
796352
797273
  ).catch((err) => {
796353
797274
  if (subAgent.preempted) return "";
796354
797275
  throw err;
@@ -796414,7 +797335,7 @@ ${errMsg}`
796414
797335
  return false;
796415
797336
  }
796416
797337
  if (!finalText) {
796417
- const deliveredFinalText2 = "Done.";
797338
+ const deliveredFinalText2 = "The run reached its completion boundary, but it did not produce a user-facing result. Open Evidence for the recorded outcome.";
796418
797339
  const evidenceText2 = this.telegramAdminCompletionRunText(subAgent, "");
796419
797340
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, evidenceText2);
796420
797341
  this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
@@ -796552,12 +797473,14 @@ ${errMsg}`
796552
797473
  }
796553
797474
  }
796554
797475
  /** Fast Telegram chat path: direct streamed completion, no tool loop. */
796555
- async handleTelegramChatCompletion(msg, toolContext, additionalContext = "", authorizationContext = "") {
797476
+ async handleTelegramChatCompletion(msg, toolContext, additionalContext = "", authorizationContext = "", expectedOutcomeContract) {
796556
797477
  if (toolContext === "telegram-admin-dm") {
796557
797478
  return this.handleTelegramAdminChatAgent(
796558
797479
  msg,
796559
797480
  toolContext,
796560
- additionalContext
797481
+ additionalContext,
797482
+ authorizationContext,
797483
+ expectedOutcomeContract
796561
797484
  );
796562
797485
  }
796563
797486
  const viewId = `${this.viewIdForMessage(msg)}-chat`;
@@ -796898,7 +797821,6 @@ ${conversationStream}`
796898
797821
  );
796899
797822
  }
796900
797823
  retainTelegramVisibleReplyDraft(subAgent, draft, streamToolNames = subAgent.currentStreamToolNames) {
796901
- if (subAgent.visibleReplyText) return;
796902
797824
  const clean7 = cleanTelegramVisibleReply(draft);
796903
797825
  if (!clean7) return;
796904
797826
  const toolNames = [...streamToolNames];
@@ -796980,12 +797902,13 @@ ${creativeWorkspace}` : ""
796980
797902
  contextWindowSize,
796981
797903
  modelTier: modelTier2,
796982
797904
  disableTodoCompletionGuard: true,
796983
- disableTodoPlanningNudges: true,
797905
+ disableTodoPlanningNudges: subAgent.expectedOutcomeContract?.planningMode !== "checklist",
797906
+ expectedOutcomeContract: subAgent.expectedOutcomeContract,
796984
797907
  // The attention router already classified this private-admin turn as
796985
797908
  // chat. Accept its first visible assistant answer as the terminal result
796986
797909
  // instead of spending two more generations demanding task_complete.
796987
797910
  // Action routes keep the normal explicit completion/evidence boundary.
796988
- acceptTextOnlyCompletion: isAdminDM && profile === "chat",
797911
+ acceptTextOnlyCompletion: isAdminDM && profile === "chat" && subAgent.expectedOutcomeContract?.route === "chat",
796989
797912
  streamEnabled: true,
796990
797913
  dynamicContext: runnerDynamicContext,
796991
797914
  captureContextFrame: true,
@@ -797014,6 +797937,9 @@ ${creativeWorkspace}` : ""
797014
797937
  // ── WO #03 (Typed Gateway Event Stream): structured event feed ──
797015
797938
  onTypedEvent: (event) => {
797016
797939
  this.forwardTelegramRunnerIntakeLifecycle(event);
797940
+ if (isAdminDM && (event.type === "todo_snapshot" || event.type === "todo_transition")) {
797941
+ this.updateTelegramAdminLivePanelFromRunEvent(subAgent, msg, event);
797942
+ }
797017
797943
  if (event.type === "steering_lifecycle" && event.reconciliation) {
797018
797944
  upsertTelegramSteeringReconciliation(
797019
797945
  subAgent.steeringReconciliations,
@@ -797311,11 +798237,14 @@ ${additionalContext}`;
797311
798237
  subAgent.runnerTurns = result.turns;
797312
798238
  subAgent.runnerToolCalls = result.toolCalls;
797313
798239
  subAgent.runnerSummary = result.summary;
798240
+ subAgent.runnerTerminalReceiptId = result.terminalReceiptId;
798241
+ subAgent.runnerExpectedOutcomeAssessment = result.expectedOutcomeAssessment;
797314
798242
  if (result.status === "completed") subAgent.completionBoundarySeen = true;
797315
798243
  if (result.status === "incomplete_verification") {
797316
798244
  subAgent.completionBoundarySeen = false;
797317
798245
  }
797318
- const finalResponse = selectTelegramFinalResponse({
798246
+ const candidateFinalReply = selectTelegramFinalResponse({
798247
+ terminalUserReply: subAgent.terminalUserReply,
797319
798248
  visibleReplyText: subAgent.visibleReplyText,
797320
798249
  assistantText: subAgent.assistantText,
797321
798250
  streamText: subAgent.streamText,
@@ -797323,13 +798252,13 @@ ${additionalContext}`;
797323
798252
  summary: result.summary,
797324
798253
  completionBoundarySeen: subAgent.completionBoundarySeen
797325
798254
  });
797326
- const scrutinyText = [finalResponse, result.summary].filter(Boolean).join("\n");
797327
- const violations = auditPerceptionClaims(scrutinyText, {
798255
+ const violations = auditPerceptionClaims(candidateFinalReply, {
797328
798256
  toolsUsed: [
797329
798257
  ...subAgent.successfulToolNamesThisRun,
797330
798258
  ...telegramMediaContextEvidenceTools(mediaContext)
797331
798259
  ]
797332
798260
  });
798261
+ let validatedFinalReply = candidateFinalReply;
797333
798262
  if (violations.length > 0) {
797334
798263
  this.subAgentViewCallbacks?.onWrite(
797335
798264
  subAgent.viewId,
@@ -797338,11 +798267,11 @@ ${additionalContext}`;
797338
798267
  const needed = [...new Set(violations.map((v) => v.requiredTool))].join(
797339
798268
  "; "
797340
798269
  );
797341
- return finalResponse ? `${finalResponse}
798270
+ validatedFinalReply = candidateFinalReply ? `${candidateFinalReply}
797342
798271
 
797343
798272
  Verification note: I have not actually run ${needed} for the unsupported action claim above.` : `I have not actually run ${needed} yet, so I cannot verify that claim.`;
797344
798273
  }
797345
- return finalResponse;
798274
+ return validatedFinalReply;
797346
798275
  }
797347
798276
  telegramScopedMemoryPrefix(chatId) {
797348
798277
  const raw = chatId === void 0 ? "unknown" : String(chatId);
@@ -798308,13 +799237,17 @@ Scoped workspace: ${scopedRoot}`,
798308
799237
  const bridge = this;
798309
799238
  const taskComplete = {
798310
799239
  name: "task_complete",
798311
- description: "Internal completion signal for Telegram runs. Put the actual user-facing reply in assistant text before calling this. Acquired public media must first pass semantic analysis and receive a Telegram delivery receipt; this tool enforces both conditions. Use summary 'no_reply' only to silently skip responding; never write that sentinel as assistant text.",
799240
+ description: "Internal completion signal for Telegram runs. Put the natural, evidence-grounded Telegram reply in user_reply (preferred) or assistant text before calling this. summary is internal lifecycle bookkeeping and is never sent to Telegram. Acquired public media must first pass semantic analysis and receive a Telegram delivery receipt; this tool enforces both conditions. Use summary 'no_reply' only to silently skip responding; never write that sentinel as assistant text or user_reply.",
798312
799241
  parameters: {
798313
799242
  type: "object",
798314
799243
  properties: {
798315
799244
  summary: {
798316
799245
  type: "string",
798317
799246
  description: "Internal completion note, or 'no_reply' to skip when no assistant reply should be sent. This is never shown directly to Telegram."
799247
+ },
799248
+ user_reply: {
799249
+ type: "string",
799250
+ description: "Optional exact natural-language reply to send to the Telegram user. Ground claims in successful tool evidence. This takes precedence over prior planning drafts; task_complete.summary never substitutes for it."
798318
799251
  }
798319
799252
  },
798320
799253
  required: ["summary"]
@@ -798352,9 +799285,16 @@ Scoped workspace: ${scopedRoot}`,
798352
799285
  };
798353
799286
  }
798354
799287
  }
799288
+ const terminalUserReply = cleanTelegramVisibleReply(
799289
+ typeof args["user_reply"] === "string" ? args["user_reply"] : ""
799290
+ );
799291
+ if (activeSubAgent && terminalUserReply) {
799292
+ activeSubAgent.terminalUserReply = terminalUserReply;
799293
+ }
798355
799294
  return {
798356
799295
  success: true,
798357
- output: args["summary"] || "complete"
799296
+ output: args["summary"] || "complete",
799297
+ completionVisibleResponse: Boolean(terminalUserReply)
798358
799298
  };
798359
799299
  }
798360
799300
  };
@@ -798850,6 +799790,16 @@ Scoped workspace: ${scopedRoot}`,
798850
799790
  currentMsg
798851
799791
  });
798852
799792
  const reportedMutation = result && typeof result === "object" && !Array.isArray(result) && typeof result["mutated"] === "boolean" ? Boolean(result["mutated"]) : void 0;
799793
+ const resultRecord = result && typeof result === "object" && !Array.isArray(result) ? result : void 0;
799794
+ const deliveredMessageId = Number(resultRecord?.["message_id"]);
799795
+ const deliveredTarget = resultRecord?.["chat_id"];
799796
+ const deliveryReceipt = action === "send_message" && (typeof deliveredTarget === "string" || typeof deliveredTarget === "number") && Number.isInteger(deliveredMessageId) && deliveredMessageId > 0 ? {
799797
+ schema: "omnius.completion-delivery-receipt.v1",
799798
+ provider: "telegram",
799799
+ target: String(deliveredTarget),
799800
+ receiptId: `message:${deliveredMessageId}`,
799801
+ deliveredAtIso: (/* @__PURE__ */ new Date()).toISOString()
799802
+ } : void 0;
798853
799803
  return {
798854
799804
  success: true,
798855
799805
  output: typeof result === "string" ? result : JSON.stringify(result, null, 2),
@@ -798858,7 +799808,11 @@ Scoped workspace: ${scopedRoot}`,
798858
799808
  mutated: reportedMutation ?? TELEGRAM_TOOL_MUTATING_GROUPS.has(
798859
799809
  TELEGRAM_TOOL_ACTION_GROUP[action]
798860
799810
  ),
798861
- mutatedFiles: []
799811
+ mutatedFiles: [],
799812
+ ...deliveryReceipt ? {
799813
+ completionEvidenceRole: "delivery",
799814
+ completionDeliveryReceipt: deliveryReceipt
799815
+ } : {}
798862
799816
  };
798863
799817
  } catch (err) {
798864
799818
  return {
@@ -801879,14 +802833,26 @@ ${objectMemory.contextBlock}`
801879
802833
  currentMsg,
801880
802834
  ledgerPath
801881
802835
  );
801882
- return {
802836
+ const deliveredResult = {
801883
802837
  success: true,
801884
802838
  output: `Sent Telegram file: ${basename44(file.path)} as ${kind} to ${String(target.chatId)}${messageId ? ` (message_id ${messageId})` : ""}`,
801885
802839
  llmContent: `Sent ${basename44(file.path)} to Telegram as ${kind}.`,
801886
802840
  durationMs: performance.now() - start2,
801887
802841
  mutated: false,
801888
- mutatedFiles: []
802842
+ mutatedFiles: [],
802843
+ ...messageId ? {
802844
+ completionEvidenceRole: "delivery",
802845
+ completionDeliveryReceipt: {
802846
+ schema: "omnius.completion-delivery-receipt.v1",
802847
+ provider: "telegram",
802848
+ target: String(target.chatId),
802849
+ receiptId: `message:${messageId}`,
802850
+ deliveredAtIso: (/* @__PURE__ */ new Date()).toISOString(),
802851
+ artifactPaths: [ledgerPath]
802852
+ }
802853
+ } : {}
801889
802854
  };
802855
+ return deliveredResult;
801890
802856
  } catch (err) {
801891
802857
  return {
801892
802858
  success: false,