blun-king-cli 9.1.452 → 9.1.454

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.
@@ -31,7 +31,9 @@ const REQUIRED_EVIDENCE_INPUT_KEYS = new Set([
31
31
  'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs',
32
32
  ]);
33
33
  const EVIDENCE_DIGEST_RE = /^[a-f0-9]{16}$/u;
34
+ const EVIDENCE_PRODUCER_REF_RE = /^[a-f0-9]{16}$/u;
34
35
  const DECISION_BASIS_RE = /^[a-f0-9]{16}$/u;
36
+ const COMPLETION_CRITERION_REF_RE = /^[a-f0-9]{16}$/u;
35
37
  const ISO_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}(?::?\d{2})?)$/u;
36
38
  const ACTION_ONLY_TOOL_NAMES = new Set([
37
39
  'CreateGoal', 'CronCreate', 'CronDelete', 'DubVideo', 'Edit', 'EnterPlanMode',
@@ -179,6 +181,20 @@ function successfulToolDigest(toolName) {
179
181
  return crypto.createHash('sha256').update(`tool:${name}`).digest('hex').slice(0, 16);
180
182
  }
181
183
 
184
+ function evidenceProducerRef(identity) {
185
+ const value = bounded(identity, 'evidence producer identity', 1024);
186
+ return crypto.createHash('sha256')
187
+ .update(`evidence-producer:${value}`)
188
+ .digest('hex')
189
+ .slice(0, 16);
190
+ }
191
+
192
+ function normalizedEvidenceProducerRef(value, field = 'evidence producer ref') {
193
+ const ref = String(value ?? '').trim();
194
+ if (!EVIDENCE_PRODUCER_REF_RE.test(ref)) throw new TypeError(`${field} is invalid`);
195
+ return ref;
196
+ }
197
+
182
198
  function successfulToolCallDigest(turnId, toolCallId, toolName) {
183
199
  const turn = normalizedTurnId(turnId);
184
200
  const callId = bounded(toolCallId, 'verificationProof toolCallId', 256);
@@ -216,6 +232,15 @@ function successfulVerificationScopeDigest(turnId, toolCallId, toolName, kind, s
216
232
  .slice(0, 16);
217
233
  }
218
234
 
235
+ function completionCriterionRef(value) {
236
+ const criterion = String(value ?? '').trim();
237
+ if (!criterion) throw new TypeError('completion criterion is required');
238
+ return crypto.createHash('sha256')
239
+ .update(`completion-criterion:${criterion}`)
240
+ .digest('hex')
241
+ .slice(0, 16);
242
+ }
243
+
219
244
  function isActionOnlyTool(toolName) {
220
245
  return ACTION_ONLY_TOOL_NAMES.has(String(toolName ?? '').trim());
221
246
  }
@@ -412,14 +437,16 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
412
437
  && Object.hasOwn(input, 'kind')
413
438
  && Object.hasOwn(input, 'claim')
414
439
  && keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'claim', 'sharpnessProof'].includes(key));
415
- const currentResult = subject === 'result'
440
+ const legacyScopedResult = options.allowLegacy === true
441
+ && subject === 'result'
416
442
  && keys.length === 6
417
443
  && Object.hasOwn(input, 'toolCallId')
418
444
  && Object.hasOwn(input, 'toolName')
419
445
  && Object.hasOwn(input, 'kind')
420
446
  && Object.hasOwn(input, 'scope')
421
447
  && Object.hasOwn(input, 'claim');
422
- const currentVerifier = subject === 'verifier'
448
+ const legacyScopedVerifier = options.allowLegacy === true
449
+ && subject === 'verifier'
423
450
  && (keys.length === 6 || keys.length === 7)
424
451
  && Object.hasOwn(input, 'toolCallId')
425
452
  && Object.hasOwn(input, 'toolName')
@@ -427,9 +454,68 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
427
454
  && Object.hasOwn(input, 'scope')
428
455
  && Object.hasOwn(input, 'claim')
429
456
  && keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'scope', 'claim', 'sharpnessProof'].includes(key));
457
+ const freshResult = subject === 'result'
458
+ && keys.length === 7
459
+ && Object.hasOwn(input, 'toolCallId')
460
+ && Object.hasOwn(input, 'toolName')
461
+ && Object.hasOwn(input, 'kind')
462
+ && Object.hasOwn(input, 'scope')
463
+ && Object.hasOwn(input, 'criterion')
464
+ && Object.hasOwn(input, 'claim');
465
+ const freshVerifier = subject === 'verifier'
466
+ && (keys.length === 7 || keys.length === 8)
467
+ && Object.hasOwn(input, 'toolCallId')
468
+ && Object.hasOwn(input, 'toolName')
469
+ && Object.hasOwn(input, 'kind')
470
+ && Object.hasOwn(input, 'scope')
471
+ && Object.hasOwn(input, 'criterion')
472
+ && Object.hasOwn(input, 'claim')
473
+ && keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'scope', 'criterion', 'claim', 'sharpnessProof'].includes(key));
474
+ const replayResult = options.allowLegacy === true
475
+ && subject === 'result'
476
+ && keys.length === 7
477
+ && Object.hasOwn(input, 'toolCallId')
478
+ && Object.hasOwn(input, 'toolName')
479
+ && Object.hasOwn(input, 'kind')
480
+ && Object.hasOwn(input, 'scope')
481
+ && Object.hasOwn(input, 'criterionRef')
482
+ && Object.hasOwn(input, 'claim');
483
+ const replayVerifier = options.allowLegacy === true
484
+ && subject === 'verifier'
485
+ && (keys.length === 7 || keys.length === 8)
486
+ && Object.hasOwn(input, 'toolCallId')
487
+ && Object.hasOwn(input, 'toolName')
488
+ && Object.hasOwn(input, 'kind')
489
+ && Object.hasOwn(input, 'scope')
490
+ && Object.hasOwn(input, 'criterionRef')
491
+ && Object.hasOwn(input, 'claim')
492
+ && keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'scope', 'criterionRef', 'claim', 'sharpnessProof'].includes(key));
493
+ const replayProvenanceResult = options.allowLegacy === true
494
+ && subject === 'result'
495
+ && keys.length === 8
496
+ && Object.hasOwn(input, 'toolCallId')
497
+ && Object.hasOwn(input, 'toolName')
498
+ && Object.hasOwn(input, 'kind')
499
+ && Object.hasOwn(input, 'scope')
500
+ && Object.hasOwn(input, 'criterionRef')
501
+ && Object.hasOwn(input, 'producerRef')
502
+ && Object.hasOwn(input, 'claim');
503
+ const replayProvenanceVerifier = options.allowLegacy === true
504
+ && subject === 'verifier'
505
+ && (keys.length === 8 || keys.length === 9)
506
+ && Object.hasOwn(input, 'toolCallId')
507
+ && Object.hasOwn(input, 'toolName')
508
+ && Object.hasOwn(input, 'kind')
509
+ && Object.hasOwn(input, 'scope')
510
+ && Object.hasOwn(input, 'criterionRef')
511
+ && Object.hasOwn(input, 'producerRef')
512
+ && Object.hasOwn(input, 'claim')
513
+ && keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'scope', 'criterionRef', 'producerRef', 'claim', 'sharpnessProof'].includes(key));
430
514
  if (!legacyName && !legacyExact && !legacySubjectResult && !legacySubjectVerifier
431
515
  && !legacyTypedSubjectResult && !legacyTypedSubjectVerifier
432
- && !currentResult && !currentVerifier) {
516
+ && !legacyScopedResult && !legacyScopedVerifier
517
+ && !freshResult && !freshVerifier && !replayResult && !replayVerifier
518
+ && !replayProvenanceResult && !replayProvenanceVerifier) {
433
519
  throw new TypeError('verificationProof fields are invalid');
434
520
  }
435
521
  const receipt = normalizeActionEvidenceReceipt(evidenceReceipt);
@@ -450,15 +536,41 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
450
536
  toolCallId: input.toolCallId,
451
537
  toolName: input.toolName,
452
538
  ...(legacySubject ? {} : { kind: input.kind }),
453
- ...(currentResult || currentVerifier ? { scope: input.scope } : {}),
539
+ ...(legacyScopedResult || legacyScopedVerifier || freshResult || freshVerifier
540
+ || replayResult || replayVerifier || replayProvenanceResult || replayProvenanceVerifier
541
+ ? { scope: input.scope } : {}),
454
542
  claim: input.claim,
455
543
  }, receipt, 'verificationProof', {
456
544
  requireKind: !legacyExact && !legacySubject,
457
- requireScope: currentResult || currentVerifier,
545
+ requireScope: legacyScopedResult || legacyScopedVerifier || freshResult || freshVerifier
546
+ || replayResult || replayVerifier || replayProvenanceResult || replayProvenanceVerifier,
458
547
  });
459
548
  if (legacyExact) return primary;
460
549
  if (!VERIFICATION_SUBJECTS.has(subject)) throw new TypeError('verificationProof subject is invalid');
461
- if (subject === 'result') return Object.freeze({ subject, ...primary });
550
+ const criterionRef = freshResult || freshVerifier
551
+ ? completionCriterionRef(input.criterion)
552
+ : replayResult || replayVerifier || replayProvenanceResult || replayProvenanceVerifier
553
+ ? String(input.criterionRef ?? '')
554
+ : undefined;
555
+ if (criterionRef !== undefined && !COMPLETION_CRITERION_REF_RE.test(criterionRef)) {
556
+ throw new TypeError('verificationProof criterionRef is invalid');
557
+ }
558
+ const producerRef = freshResult || freshVerifier
559
+ ? receipt.producerRef
560
+ : replayProvenanceResult || replayProvenanceVerifier
561
+ ? normalizedEvidenceProducerRef(input.producerRef, 'verificationProof producerRef')
562
+ : undefined;
563
+ if (producerRef !== undefined && receipt.producerRef !== producerRef) {
564
+ throw new TypeError('verificationProof producerRef must match the runtime evidence producer');
565
+ }
566
+ if (subject === 'result') {
567
+ return Object.freeze({
568
+ subject,
569
+ ...primary,
570
+ ...(criterionRef === undefined ? {} : { criterionRef }),
571
+ ...(producerRef === undefined ? {} : { producerRef }),
572
+ });
573
+ }
462
574
  if (input.sharpnessProof === undefined) {
463
575
  throw new TypeError('verifier proof requires a sharpnessProof');
464
576
  }
@@ -470,13 +582,23 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
470
582
  && sharpnessProof.toolName === primary.toolName) {
471
583
  throw new TypeError('sharpnessProof must name a distinct verification call');
472
584
  }
473
- return Object.freeze({ subject, ...primary, sharpnessProof });
585
+ return Object.freeze({
586
+ subject,
587
+ ...primary,
588
+ ...(criterionRef === undefined ? {} : { criterionRef }),
589
+ ...(producerRef === undefined ? {} : { producerRef }),
590
+ sharpnessProof,
591
+ });
474
592
  }
475
593
 
476
- function emptyActionEvidenceReceipt(turnId) {
594
+ function emptyActionEvidenceReceipt(turnId, producerRef) {
477
595
  const normalized = normalizedTurnId(turnId);
596
+ const producer = producerRef === undefined
597
+ ? undefined
598
+ : normalizedEvidenceProducerRef(producerRef);
478
599
  return Object.freeze({
479
600
  turnId: normalized,
601
+ ...(producer === undefined ? {} : { producerRef: producer }),
480
602
  completedTools: 0,
481
603
  successfulTools: 0,
482
604
  failedTools: 0,
@@ -484,7 +606,12 @@ function emptyActionEvidenceReceipt(turnId) {
484
606
  successfulToolCallDigests: Object.freeze([]),
485
607
  successfulVerificationCallDigests: Object.freeze([]),
486
608
  successfulVerificationScopeDigests: Object.freeze([]),
487
- digest: crypto.createHash('sha256').update(`turn:${normalized}:empty`).digest('hex').slice(0, 16),
609
+ digest: crypto.createHash('sha256')
610
+ .update(producer === undefined
611
+ ? `turn:${normalized}:empty`
612
+ : `producer:${producer}\0turn:${normalized}:empty`)
613
+ .digest('hex')
614
+ .slice(0, 16),
488
615
  });
489
616
  }
490
617
 
@@ -493,7 +620,7 @@ function normalizeActionEvidenceReceipt(input) {
493
620
  const requiredKeys = new Set(['turnId', 'completedTools', 'successfulTools', 'failedTools', 'digest']);
494
621
  const allowedKeys = new Set([
495
622
  ...requiredKeys, 'successfulToolDigests', 'successfulToolCallDigests',
496
- 'successfulVerificationCallDigests', 'successfulVerificationScopeDigests',
623
+ 'successfulVerificationCallDigests', 'successfulVerificationScopeDigests', 'producerRef',
497
624
  ]);
498
625
  if (!Object.keys(input).every((key) => allowedKeys.has(key))
499
626
  || ![...requiredKeys].every((key) => Object.hasOwn(input, key))) {
@@ -501,6 +628,9 @@ function normalizeActionEvidenceReceipt(input) {
501
628
  }
502
629
  const receipt = {
503
630
  turnId: normalizedTurnId(input.turnId),
631
+ ...(input.producerRef === undefined
632
+ ? {}
633
+ : { producerRef: normalizedEvidenceProducerRef(input.producerRef) }),
504
634
  completedTools: Number(input.completedTools),
505
635
  successfulTools: Number(input.successfulTools),
506
636
  failedTools: Number(input.failedTools),
@@ -594,11 +724,13 @@ function advanceActionEvidenceReceipt(current, input) {
594
724
  }
595
725
  }
596
726
  const digest = crypto.createHash('sha256').update([
597
- prior.digest, String(turnId), toolCallId, toolName, decision, outcome, String(durationMs),
727
+ prior.digest, prior.producerRef ?? 'legacy', String(turnId), toolCallId, toolName,
728
+ decision, outcome, String(durationMs),
598
729
  verificationKinds.join(','), verificationScopes.join(','),
599
730
  ].join('\0')).digest('hex').slice(0, 16);
600
731
  return Object.freeze({
601
732
  turnId,
733
+ ...(prior.producerRef === undefined ? {} : { producerRef: prior.producerRef }),
602
734
  completedTools: prior.completedTools + 1,
603
735
  successfulTools: prior.successfulTools + (successful ? 1 : 0),
604
736
  failedTools: prior.failedTools + (successful ? 0 : 1),
@@ -728,7 +860,13 @@ function projectActionCheckpoint(checkpoint) {
728
860
  const scope = value.verificationProof.scope === undefined
729
861
  ? ''
730
862
  : ` [scope: ${value.verificationProof.scope}]`;
731
- lines.push(`Verification proof${subject}${kind}${scope}: ${call} - ${value.verificationProof.claim}`);
863
+ const criterion = value.verificationProof.criterionRef === undefined
864
+ ? ''
865
+ : ` [criterion: ${value.verificationProof.criterionRef}]`;
866
+ const producer = value.verificationProof.producerRef === undefined
867
+ ? ''
868
+ : ` [producer: ${value.verificationProof.producerRef}]`;
869
+ lines.push(`Verification proof${subject}${kind}${scope}${criterion}${producer}: ${call} - ${value.verificationProof.claim}`);
732
870
  if (value.verificationProof.sharpnessProof !== undefined) {
733
871
  const sharpness = value.verificationProof.sharpnessProof;
734
872
  const sharpnessKind = sharpness.kind === undefined ? '' : ` [${sharpness.kind}]`;
@@ -769,6 +907,8 @@ module.exports = {
769
907
  advanceActionEvidenceReceipt,
770
908
  assertActionCheckpointEvidenceBasis,
771
909
  assertActionCheckpointRevision,
910
+ completionCriterionRef,
911
+ evidenceProducerRef,
772
912
  emptyActionEvidenceReceipt,
773
913
  normalizeActionCheckpoint,
774
914
  normalizeVerificationProof,
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
+ completionCriterionRef,
4
5
  normalizeVerificationProof,
5
6
  } = require('./cognitive-action-checkpoint.cjs');
6
7
 
@@ -14,12 +15,25 @@ function successfulRuntimeEvidence(checkpoint) {
14
15
  return Number.isSafeInteger(successfulTools) && successfulTools > 0;
15
16
  }
16
17
 
17
- function verificationProofGaps(checkpoint) {
18
+ function verificationProofGaps(checkpoint, criterion, expectedProducerRef) {
18
19
  if (!checkpoint?.verificationProof) {
19
20
  return ['Bind the completion claim to a successful verification tool from the checkpoint turn.'];
20
21
  }
21
22
  try {
22
- normalizeVerificationProof(checkpoint.verificationProof, checkpoint.evidenceReceipt, { allowLegacy: true });
23
+ const proof = normalizeVerificationProof(
24
+ checkpoint.verificationProof,
25
+ checkpoint.evidenceReceipt,
26
+ { allowLegacy: true },
27
+ );
28
+ if (proof.criterionRef !== completionCriterionRef(criterion)) {
29
+ return ['Bind the completion proof to the active completion criterion.'];
30
+ }
31
+ if (expectedProducerRef !== undefined && proof.producerRef === undefined) {
32
+ return ['Bind the completion proof to the runtime that produced its measurement.'];
33
+ }
34
+ if (expectedProducerRef !== undefined && proof.producerRef !== expectedProducerRef) {
35
+ return ['The completion proof was produced by a different agent session; preserve it as an external report instead of relabelling it as local verification.'];
36
+ }
23
37
  return [];
24
38
  } catch (error) {
25
39
  if (/verifier proof requires a sharpnessProof|sharpnessProof must name a distinct verification call/u
@@ -48,7 +62,7 @@ function verificationProofGaps(checkpoint) {
48
62
  }
49
63
  }
50
64
 
51
- function evaluateGoalCompletionEvidence(goal) {
65
+ function evaluateGoalCompletionEvidence(goal, options = {}) {
52
66
  if (!hasCompletionCriterion(goal)) {
53
67
  return {
54
68
  required: false,
@@ -86,7 +100,11 @@ function evaluateGoalCompletionEvidence(goal) {
86
100
  && checkpoint.evidenceBasis === 'runtime_tool'
87
101
  && checkpoint.epistemicState === 'verified'
88
102
  && hasRuntimeEvidence) {
89
- gaps.push(...verificationProofGaps(checkpoint));
103
+ gaps.push(...verificationProofGaps(
104
+ checkpoint,
105
+ goal.completionCriterion,
106
+ options.expectedProducerRef,
107
+ ));
90
108
  }
91
109
 
92
110
  return {
package/blun.mjs CHANGED
@@ -21463,7 +21463,7 @@ var { rollbackPersonalityChoice, setPersonalityEnabledAtomic } = createRequire(i
21463
21463
  var { projectSoulText } = createRequire(import.meta.url)("./bin/soul-organization-policy.cjs");
21464
21464
  var { soulFileInstruction } = createRequire(import.meta.url)("./bin/soul-preservation-policy.cjs");
21465
21465
  var { readProfilePersona, resolveSoulFile } = createRequire(import.meta.url)("./bin/profile-identity-resolution.cjs");
21466
- var { advanceActionEvidenceReceipt, assertActionCheckpointEvidenceBasis, assertActionCheckpointRevision, emptyActionEvidenceReceipt, normalizeActionCheckpoint, projectActionCheckpoint } = createRequire(import.meta.url)("./bin/cognitive-action-checkpoint.cjs");
21466
+ var { advanceActionEvidenceReceipt, assertActionCheckpointEvidenceBasis, assertActionCheckpointRevision, emptyActionEvidenceReceipt, evidenceProducerRef, normalizeActionCheckpoint, projectActionCheckpoint } = createRequire(import.meta.url)("./bin/cognitive-action-checkpoint.cjs");
21467
21467
  var { evaluateGoalCompletionEvidence } = createRequire(import.meta.url)("./bin/goal-completion-evidence-policy.cjs");
21468
21468
  async function prepareSystemPromptContext(kaos, brandHome, options) {
21469
21469
  const additionalDirs = normalizeAdditionalDirs(options?.additionalDirs ?? []);
@@ -230425,7 +230425,9 @@ var init_goal$1 = __esmMin((() => {
230425
230425
  async markComplete(input = {}, actor = "model") {
230426
230426
  const state = this.state;
230427
230427
  if (state === void 0 || state.status !== "active") return null;
230428
- const completionEvidence = evaluateGoalCompletionEvidence(state);
230428
+ const completionEvidence = evaluateGoalCompletionEvidence(state, {
230429
+ expectedProducerRef: this.agent.evidenceProducerRef
230430
+ });
230429
230431
  if (!completionEvidence.allPassed) {
230430
230432
  throw new BlunError(ErrorCodes.GOAL_STATUS_INVALID, `Completion criterion needs revision: ${completionEvidence.gaps.join(" ")} Run the required verification, save a runtime-backed verify checkpoint, then mark the goal complete.`);
230431
230433
  }
@@ -245812,6 +245814,7 @@ var init_events$1 = __esmMin((() => {
245812
245814
  updatedAt: string(),
245813
245815
  evidenceReceipt: object({
245814
245816
  turnId: number$1().int().min(0),
245817
+ producerRef: string().regex(/^[a-f0-9]{16}$/u).optional(),
245815
245818
  completedTools: number$1().int().min(0),
245816
245819
  successfulTools: number$1().int().min(0),
245817
245820
  failedTools: number$1().int().min(0),
@@ -260354,6 +260357,7 @@ function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFra
260354
260357
  toolName: string().min(1).max(128),
260355
260358
  kind: _enum(["inspection", "integrity", "syntax", "test", "reachability"]),
260356
260359
  scope: string().min(1).max(256),
260360
+ criterion: string().min(1),
260357
260361
  claim: string().min(1).max(512),
260358
260362
  sharpnessProof: object({
260359
260363
  toolCallId: string().min(1).max(256),
@@ -261845,7 +261849,7 @@ var init_turn = __esmMin((() => {
261845
261849
  return;
261846
261850
  }
261847
261851
  this.cognitiveToolPolicyByCall.delete(input.toolCallId);
261848
- const currentEvidence = this.cognitiveActionEvidenceByTurn.get(input.turnId) ?? emptyActionEvidenceReceipt(input.turnId);
261852
+ const currentEvidence = this.cognitiveActionEvidenceByTurn.get(input.turnId) ?? emptyActionEvidenceReceipt(input.turnId, this.agent.evidenceProducerRef);
261849
261853
  this.cognitiveActionEvidenceByTurn.set(input.turnId, advanceActionEvidenceReceipt(currentEvidence, {
261850
261854
  ...input,
261851
261855
  decision: policy.decision
@@ -261876,7 +261880,7 @@ var init_turn = __esmMin((() => {
261876
261880
  }
261877
261881
  actionEvidenceReceiptForCurrentTurn() {
261878
261882
  const turnId = this.currentId;
261879
- return this.cognitiveActionEvidenceByTurn.get(turnId) ?? emptyActionEvidenceReceipt(turnId);
261883
+ return this.cognitiveActionEvidenceByTurn.get(turnId) ?? emptyActionEvidenceReceipt(turnId, this.agent.evidenceProducerRef);
261880
261884
  }
261881
261885
  projectCognitiveState(turnId, input) {
261882
261886
  try {
@@ -262917,6 +262921,8 @@ var update_goal_default;
262917
262921
  var init_update_goal$1 = __esmMin((() => {
262918
262922
  update_goal_default = "Update the current autonomous goal. Set `status` only for a lifecycle change. After a coherent work slice, save `actionCheckpoint` with a monotone revision, the last verified result, exact next action, expected evidence, exact `nextTrigger`, and an explicit evidence basis. Persist the exact `nextTrigger` that releases `nextAction`: use `immediate` outside the `wait` phase; while waiting, name the external event, time, dependency, or user decision instead of pretending work can continue. A `time` trigger must include the exact ISO timestamp in `dueAt`; no other trigger kind may include `dueAt`. Use `runtime_tool` only when a successful tool in this turn measured the result; use `user_statement` for a direct user assertion, `external_report` for a report not independently measured here, and `carried_forward` only when the last verified text is unchanged. Classify knowledge as `verified`, `credible_unverified`, `hypothesis`, `uncertain_memory`, `stale`, or `unknown`; never present a weaker state as verified, and preserve the state on carry-forward. Start at revision 1 and increment the currently projected revision by exactly one; stale writers fail closed. This is durable progress state, not permission, and should change only when the facts change. A checkpoint-only call keeps the goal active.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is fully satisfied, all files are written, all tests pass, and any stated validation has passed. When the goal has a completion criterion, first save a `verify` checkpoint with `runtime_tool`, `verified`, and a successful runtime evidence receipt.\n- `blocked` — a genuine external condition or required user decision prevents progress.\n- `paused` — set the goal aside for now.\n\nDo not mark complete after a plan or partial result. If useful work remains, checkpoint it and continue. Do not ask for permission merely to execute an already authorized checkpoint; ask only at a real rights boundary or missing user decision.\n";
262919
262923
  update_goal_default += "\nBefore completing a goal with a criterion, bind the verified claim to the exact successful current-turn verification call in `verificationProof`, including its `toolCallId`. A write, edit, copy, deploy, or other action is not proof that the changed behavior works, even when it shares a mixed-use tool such as `Bash` with tests. Use `subject: result` for a result, report, measurement, or download. Use `subject: verifier` only when the new or changed test, gate, harness, or detector itself is the completion subject; then bind `sharpnessProof` to a separate successful current-turn counterexample or mutation call. Do not require a red probe for a normal report or measurement.\n";
262924
+ update_goal_default += "\nCopy the active goal's exact `completionCriterion` into `verificationProof.criterion`. The runtime stores only its bounded reference and refuses completion if the proof belongs to a different or superseded completion criterion.\n";
262925
+ update_goal_default += "\nThe runtime binds fresh verification automatically to the session and agent that produced the successful tool result. Do not invent or copy a producer reference. Preserve forwarded measurements as `external_report` with `credible_unverified` until this agent measures them independently; forwarding is allowed, relabelling them as local verification is not.\n";
262920
262926
  update_goal_default += "\nSet the proof `kind` to the exact capability of that call: `inspection` reads or searches, `integrity` compares bytes or hashes, `syntax` parses or type-checks, and `test` runs assertions. None of these alone proves a stronger kind. Use `reachability` only for a successful runtime probe that actually invokes the changed path and emits the exact marker `BLUN_EVIDENCE_KIND=reachability` after its assertions; loading a module without reaching the changed path is not reachability.\n";
262921
262927
  update_goal_default += "\nBind each proof `scope` to the exact target measured by that successful call, never to a free-text claim or intended file. Read and search tools derive scope from their target arguments. For shell or command tools, include the same safe token `BLUN_EVIDENCE_SCOPE=<scope>` in the launched non-mutating verification command and emit it only after that exact target succeeds; the runtime requires both sides.\n";
262922
262928
  update_goal_default += "\nFor a non-trivial or unfamiliar problem, preserve `problemFrame` with the success criterion, missing knowledge, bounded candidate actions, selected action and reason, support choice, risk, and reversibility. The selected action must match one candidate. Bind each selected action to the projected durable facts or assumptions it relies on by copying their explicit refs into `decisionBasis`. A stale or unknown decision basis requires replanning before execution. Problem framing is descriptive state and never grants permission.\n";
@@ -265361,6 +265367,7 @@ var init_agent = __esmMin((() => {
265361
265367
  blunConfig;
265362
265368
  blunHomeDir;
265363
265369
  homedir;
265370
+ evidenceProducerRef;
265364
265371
  mediaOriginalsDir;
265365
265372
  rpc;
265366
265373
  toolServices;
@@ -265416,6 +265423,7 @@ var init_agent = __esmMin((() => {
265416
265423
  this.blunConfig = options.config;
265417
265424
  this.blunHomeDir = options.blunHomeDir;
265418
265425
  this.homedir = options.homedir;
265426
+ this.evidenceProducerRef = options.evidenceProducerRef;
265419
265427
  this.mediaOriginalsDir = options.mediaOriginalsDir;
265420
265428
  this.rpc = options.rpc;
265421
265429
  this.toolServices = options.toolServices;
@@ -298009,6 +298017,7 @@ var init_session$1 = __esmMin((() => {
298009
298017
  config: this.options.config,
298010
298018
  blunHomeDir: this.options.blunHomeDir,
298011
298019
  homedir,
298020
+ evidenceProducerRef: evidenceProducerRef(`${this.options.id ?? this.options.homedir}\0${id}`),
298012
298021
  mediaOriginalsDir: sessionMediaOriginalsDir(this.options.homedir),
298013
298022
  onMediaDropped: (dropped) => {
298014
298023
  for (const part of dropped) this.rpc.emitEvent({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.452",
3
+ "version": "9.1.454",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {