@sabaiway/agent-workflow-kit 1.49.0 → 2.0.0

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.
@@ -30,6 +30,18 @@
30
30
  // Informational receipts NEVER satisfy (nor fail) the tree check: plan/diff-mode receipts
31
31
  // (artifact ≠ "code") and continuations (fresh:false — agy --continue/--conversation cannot attest
32
32
  // a folded tree; only a fresh grounded re-run mints a gate-satisfying receipt).
33
+ // PROBE receipts never satisfy either (BRIDGE-MODES-CATALOG, D3): a CODEX_PROBE=1 / AGY_PROBE=1
34
+ // review runs with the frontier-model/max-effort guard OFF, so the wrappers stamp `probe:true` and
35
+ // this checker drops those receipts — PER RECEIPT, so a normal receipt at the same fingerprint still
36
+ // satisfies, and a backend whose ONLY current receipts are probes fails with its own stated reason
37
+ // (never the stale one). Every receipt from a marker-aware wrapper SELF-DECLARES — `probe` is written
38
+ // on every successful review, true or false — so a NON-BOOLEAN or ABSENT marker is rejected
39
+ // fail-closed: silence is not a declaration, and the probe status of an unmarked receipt is
40
+ // untrustworthy whoever wrote it (the pre-D3 wrappers honoured the probe env vars while writing no
41
+ // marker; a hand-written line is no better evidence). Deliberately NOT keyed on wrapperVersion: the
42
+ // version bumps in a different release phase than the marker lands, so a version floor would reject
43
+ // the very receipts the current wrappers write. Accepted cost (maintainer, 2026-07-15): a pre-D3
44
+ // receipt stops satisfying — re-run the review with a marker-aware bridge.
33
45
  //
34
46
  // The fingerprint is the ONE canonical uncommitted-state identity — sha256 over: staged diff +
35
47
  // unstaged diff + untracked-not-ignored file contents (binary untracked files, symlinks, and
@@ -61,7 +73,14 @@ import { resolveActivityRecipe, planRecipe, DISPLAY_ALIASES } from './recipes.mj
61
73
  import { CONFIG_REL, fail, loadConfig } from './orchestration-config.mjs';
62
74
  // The NEUTRAL ledger read-core (AD-050): review-state reads the review-ledger ONLY for the degraded
63
75
  // exemption, through the neutral core — never review-ledger.mjs (which imports THIS module, the cycle).
64
- import { resolveLedgerPath, resolveBase, readLedger, filterSegmentRecords, roundSequenceIntact } from './review-ledger-core.mjs';
76
+ import {
77
+ resolveLedgerPath,
78
+ resolveBase,
79
+ readLedger,
80
+ filterSegmentRecords,
81
+ roundSequenceIntact,
82
+ summarizeReviewReceiptsForTree,
83
+ } from './review-ledger-core.mjs';
65
84
 
66
85
  export const RECEIPTS_BASENAME = 'agent-workflow-review-receipts.jsonl';
67
86
  export const PLANS_REL = 'docs/plans';
@@ -290,29 +309,35 @@ export const readReceipts = (path, readFile = readFileSync) => {
290
309
  return { receipts, malformed };
291
310
  };
292
311
 
293
- // A receipt that can satisfy the tree check: a FRESH code-mode receipt for the current fingerprint.
294
- // Plan/diff-mode receipts and continuations are informational-only (see the header contract).
295
- const satisfies = (receipt, fingerprint) =>
296
- receipt.fresh === true && receipt.artifact === 'code' && receipt.fingerprint === fingerprint;
297
-
298
- // Per-backend receipt status for the current fingerprint:
299
- // current a satisfying receipt with grounded:true exists (its latest verdict reported);
300
- // ungrounded — current-fingerprint fresh receipts exist but every one carries grounded:false;
312
+ // Per-backend receipt status for the current fingerprint, over the ONE shared attesting-receipt
313
+ // predicate (review-ledger-core) that the round cross-check and the round writer read too — two
314
+ // gates disagreeing about what counts as an attestation is the class AD-050 closed:
315
+ // current — an ATTESTING receipt exists (fresh code, probe:false, grounded) its verdict rides;
316
+ // ungrounded — real (probe:false) current receipts exist but every one carries grounded:false;
317
+ // probe — current receipts exist and EVERY one is a well-formed probe (D3);
318
+ // rejected current receipts exist, none attests, and >=1 marker was malformed or absent;
301
319
  // stale — this backend has receipts, none for the current fingerprint (edited after review);
302
- // missing — no usable receipt from this backend at all.
320
+ // missing — no receipt from this backend at all.
321
+ // The counts state what was dropped, so a PASS over a partially-excluded set still says so
322
+ // (No-silent-failures) and the --json surface can show it.
303
323
  export const backendReceiptStatus = (receipts, backend, fingerprint) => {
304
324
  const own = receipts.filter((r) => r.backend === backend);
305
- const current = own.filter((r) => satisfies(r, fingerprint));
306
- const grounded = current.filter((r) => r.grounded === true);
307
- if (grounded.length > 0) {
308
- const latest = grounded[grounded.length - 1];
309
- return { state: 'current', verdict: latest.verdict ?? 'unknown', grounded: true, timestamp: latest.timestamp ?? null };
325
+ const summary = summarizeReviewReceiptsForTree(own, fingerprint);
326
+ const counts = {
327
+ probeExcluded: summary.probeExcluded,
328
+ markerRejected: summary.markerRejected,
329
+ unmarkedRejected: summary.unmarkedRejected,
330
+ };
331
+ if (summary.state === 'current') {
332
+ return { state: 'current', verdict: summary.receipt.verdict ?? 'unknown', grounded: true, timestamp: summary.receipt.timestamp ?? null, ...counts };
310
333
  }
311
- if (current.length > 0) {
312
- const latest = current[current.length - 1];
313
- return { state: 'ungrounded', verdict: latest.verdict ?? 'unknown', grounded: false, timestamp: latest.timestamp ?? null };
334
+ if (summary.state === 'ungrounded') {
335
+ return { state: 'ungrounded', verdict: summary.receipt.verdict ?? 'unknown', grounded: false, timestamp: summary.receipt.timestamp ?? null, ...counts };
314
336
  }
315
- return { state: own.length > 0 ? 'stale' : 'missing', verdict: null, grounded: null, timestamp: null };
337
+ if (summary.state === 'probe' || summary.state === 'rejected') {
338
+ return { state: summary.state, verdict: null, grounded: null, timestamp: null, ...counts };
339
+ }
340
+ return { state: own.length > 0 ? 'stale' : 'missing', verdict: null, grounded: null, timestamp: null, ...counts };
316
341
  };
317
342
 
318
343
  // ── the degraded exemption (AD-050): read the review-ledger for a recorded current-tree degrade ────
@@ -411,6 +436,17 @@ export const buildState = ({ cwd, env = process.env, detect = detectBackends, ls
411
436
  };
412
437
  };
413
438
 
439
+ // Why a backend's current-tree receipts were all rejected — the two causes read differently and
440
+ // have different recoveries (fix the file vs refresh the bridge), so they are never collapsed.
441
+ const rejectionCause = (b) => {
442
+ const parts = [];
443
+ if (b.markerRejected > 0) parts.push(`${b.markerRejected} with a malformed probe marker`);
444
+ if (b.unmarkedRejected > 0) {
445
+ parts.push(`${b.unmarkedRejected} with no probe marker — silence is not a declaration, so the probe status is untrustworthy; re-run the review with a bridge that marks its runs`);
446
+ }
447
+ return parts.join(' + ');
448
+ };
449
+
414
450
  // The normative --check decision (the header contract, in order). → { code, reason }.
415
451
  export const decideCheck = (state) => {
416
452
  // A DETECTOR FAILURE is unknown state, not "no reviewer ready" — the advisory tools warn and
@@ -449,23 +485,37 @@ export const decideCheck = (state) => {
449
485
  // stays verdict-blind: the exemption proves the degrade was RECORDED, never that the tree converged.
450
486
  const exempt = new Set(state.degradedExempt);
451
487
  const failing = state.backends.filter((b) => b.state !== 'current' && !exempt.has(b.backend));
488
+ // A receipt dropped for an untrustworthy probe marker is never silently dropped either (D3): it
489
+ // cannot fail a tree that other receipts satisfy, but a report over a partially-rejected set says
490
+ // so. It counts only the exclusions NOT already named per backend — a FAILING `rejected` backend
491
+ // prints its own cause below, and repeating it in the summary is noise. Every other exclusion (a
492
+ // partial one on a satisfied backend, or one on a degraded-exempt backend) still needs a voice.
493
+ const namedPerBackend = new Set(failing.filter((b) => b.state === 'rejected').map((b) => b.backend));
494
+ const untrustedTotal = state.backends
495
+ .filter((b) => !namedPerBackend.has(b.backend))
496
+ .reduce((n, b) => n + (b.markerRejected ?? 0) + (b.unmarkedRejected ?? 0), 0);
497
+ const markerNote = untrustedTotal > 0
498
+ ? ` — ${untrustedTotal} receipt(s) rejected: an untrustworthy probe marker (malformed, or absent — silence is not a declaration) — fail-closed; inspect ${state.receiptsPath}`
499
+ : '';
452
500
  if (failing.length === 0) {
453
501
  if (exempt.size === 0) {
454
- return { code: 0, reason: `every recipe-named backend has a fresh grounded receipt for the current tree (${state.requiredBackends.join(' + ')})${malformedNote}${ledgerNote}` };
502
+ return { code: 0, reason: `every recipe-named backend has a fresh grounded receipt for the current tree (${state.requiredBackends.join(' + ')})${markerNote}${malformedNote}${ledgerNote}` };
455
503
  }
456
- return { code: 0, reason: `every recipe-named backend reviewed the current tree (${state.requiredBackends.join(' + ')}) — degraded-exempt (recorded degraded for the current tree in the review ledger): ${[...exempt].join(', ')}${malformedNote}${ledgerNote}` };
504
+ return { code: 0, reason: `every recipe-named backend reviewed the current tree (${state.requiredBackends.join(' + ')}) — degraded-exempt (recorded degraded for the current tree in the review ledger): ${[...exempt].join(', ')}${markerNote}${malformedNote}${ledgerNote}` };
457
505
  }
458
506
  const parts = failing.map((b) => {
459
507
  if (b.state === 'ungrounded') return `${b.backend}: only ungrounded receipts for the current tree — re-run grounded (--facts)`;
508
+ if (b.state === 'probe') return `${b.backend}: only probe receipts for the current tree (CODEX_PROBE=1 / AGY_PROBE=1 relaxes the quality guards) — a probe review never attests; re-run a real one`;
509
+ if (b.state === 'rejected') return `${b.backend}: current-tree receipts rejected — ${rejectionCause(b)} (fail-closed); inspect ${state.receiptsPath}`;
460
510
  if (b.state === 'stale') return `${b.backend}: receipts exist but none matches the current tree (edited after review) — run a fresh review`;
461
511
  return `${b.backend}: no receipt — run its review wrapper`;
462
512
  });
463
- return { code: 1, reason: `${parts.join('; ')}${malformedNote}${ledgerNote}` };
513
+ return { code: 1, reason: `${parts.join('; ')}${markerNote}${malformedNote}${ledgerNote}` };
464
514
  };
465
515
 
466
516
  // ── rendering ───────────────────────────────────────────────────────────────────────
467
517
 
468
- const STATE_GLYPH = { current: '✓', ungrounded: '✗', stale: '✗', missing: '✗' };
518
+ const STATE_GLYPH = { current: '✓', ungrounded: '✗', probe: '✗', rejected: '✗', stale: '✗', missing: '✗' };
469
519
 
470
520
  const formatHuman = (state, check) => {
471
521
  const src = state.resolved.source === 'config' ? `from ${CONFIG_REL}` : 'computed default';
@@ -488,10 +538,17 @@ const formatHuman = (state, check) => {
488
538
  ? `current (verdict: ${b.verdict}, grounded, ${b.timestamp ?? '?'})`
489
539
  : b.state === 'ungrounded'
490
540
  ? `ungrounded for the current tree (verdict: ${b.verdict}) — a grounded fresh run is required`
491
- : b.state === 'stale'
492
- ? 'stale no receipt matches the current tree (edited after review)'
493
- : 'missing no receipt from this backend';
494
- lines.push(` ${exempt.has(b.backend) ? '⊘' : STATE_GLYPH[b.state]} ${b.backend}: ${detail}${exemptTag}`);
541
+ : b.state === 'probe'
542
+ ? 'only probe receipts for the current tree (quality guards relaxed) — a probe review never attests'
543
+ : b.state === 'rejected'
544
+ ? `current-tree receipts rejected ${rejectionCause(b)} (fail-closed)`
545
+ : b.state === 'stale'
546
+ ? 'stale — no receipt matches the current tree (edited after review)'
547
+ : 'missing — no receipt from this backend';
548
+ const excludedTag = b.probeExcluded || b.markerRejected || b.unmarkedRejected
549
+ ? ` [excluded: ${b.probeExcluded} probe, ${b.markerRejected} malformed-marker, ${b.unmarkedRejected} unmarked]`
550
+ : '';
551
+ lines.push(` ${exempt.has(b.backend) ? '⊘' : STATE_GLYPH[b.state]} ${b.backend}: ${detail}${excludedTag}${exemptTag}`);
495
552
  }
496
553
  lines.push(` check: ${check.code === 0 ? 'PASS' : 'FAIL'} — ${check.reason}`);
497
554
  return lines.join('\n');
@@ -507,7 +564,11 @@ recomputes the canonical uncommitted-state fingerprint (staged + unstaged + untr
507
564
  the review-payload domain), reads the receipt file the review wrappers append to
508
565
  (<git dir>/${RECEIPTS_BASENAME}; AW_REVIEW_RECEIPTS overrides), and reports per-backend receipt
509
566
  presence + verdict + grounding for the CURRENT tree. Plan/diff-mode receipts and continuations
510
- (fresh:false) are informational-only — they never satisfy the tree check.
567
+ (fresh:false) are informational-only — they never satisfy the tree check, and neither does a PROBE
568
+ receipt (probe:true — a CODEX_PROBE=1 / AGY_PROBE=1 run has the quality guards off). The probe
569
+ filter is per receipt, so a real receipt at the same fingerprint still satisfies. Every marker-aware
570
+ wrapper writes the probe field on EVERY review (true or false), so a malformed OR absent marker is
571
+ rejected fail-closed — silence is not a declaration.
511
572
 
512
573
  --check exits 0/1 per the normative contract in the tool header: 0 for solo / no plan in flight /
513
574
  a clean tree / not-a-git-tree / all recipe-named backends receipted-current-and-grounded OR