@sabaiway/agent-workflow-kit 1.49.0 → 2.1.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.
@@ -18,8 +18,10 @@
18
18
  // round VANISHED unclassified (D6 — no-repro-no-fold; `refuted` is the honest
19
19
  // phantom lane); refuses while the changed source surface exceeds the diff cap
20
20
  // without a recorded segment size-cap override (D4). Integrity binding (Decision 7):
21
- // each NON-degraded backend needs a grounded code receipt for the current tree, so a
22
- // round cannot be recorded for a tree no bridge reviewed.
21
+ // each NON-degraded backend needs an ATTESTING code receipt for the current tree
22
+ // (the shared review-ledger-core predicate: grounded AND probe:false a probe,
23
+ // unmarked or malformed marker never attests), so a round cannot be recorded for a
24
+ // tree no bridge really reviewed.
23
25
  // recordTriage — the classification that BREAKS the deadlock: each surviving blocking finding of a
24
26
  // SEGMENT round classified fixable-bug / inherent-layer-residual / escalate /
25
27
  // refuted (v4). No teeth (a triage is exactly what lets the next round proceed),
@@ -51,6 +53,9 @@ import {
51
53
  decideStop,
52
54
  validateRecord,
53
55
  } from './review-ledger.mjs';
56
+ // The SHARED attesting-receipt predicate (D3) — read straight from the neutral core, the same one
57
+ // review-state and the round cross-check use: one definition of "this receipt may attest a tree".
58
+ import { summarizeReviewReceiptsForTree, describeMissingReviewAttestation } from './review-ledger-core.mjs';
54
59
  // The NEUTRAL shared changed-surface computation (BUGFREE-2 / D4): the D4 diff-cap and the
55
60
  // fold-completeness coverage gate consume ONE computation, so they can never drift. The writer
56
61
  // imports the NEUTRAL module, never the runner (the sole-tree-toucher boundary, codex R2 — an
@@ -253,17 +258,20 @@ export const recordRound = (params, deps = {}) => {
253
258
  const v = validateRecord(record);
254
259
  if (!v.ok) throw stop(`refusing to record a malformed round: ${v.reason}`);
255
260
 
256
- // Integrity binding: each NON-degraded backend needs a grounded code receipt for this tree — a
257
- // round cannot be recorded for a tree no bridge reviewed. A degraded backend minted no receipt.
261
+ // Integrity binding: each NON-degraded backend needs an ATTESTING receipt for this tree — a round
262
+ // cannot be recorded for a tree no bridge really reviewed. A degraded backend minted no receipt.
263
+ // The predicate is the SHARED one (review-ledger-core), the same review-state and the round
264
+ // cross-check read — a probe receipt never counted as a review, and the stated reason names WHICH
265
+ // exclusion applied, because the recoveries differ (run a real review / refresh the bridge / fix
266
+ // the receipt source / re-run grounded) and a silent "no receipt" would hide that.
258
267
  const receiptsPath = deps.receiptsPath ?? resolveReceiptsPath(cwd, env);
259
268
  const { receipts } = receiptsPath ? readReceipts(receiptsPath, deps.readFile) : { receipts: [] };
260
269
  for (const b of backends) {
261
270
  if (b.degraded) continue;
262
- const own = receipts.filter(
263
- (r) => r.backend === b.backend && r.fingerprint === fingerprint && r.artifact === 'code' && r.fresh === true && r.grounded === true,
264
- );
265
- if (own.length === 0) {
266
- throw stop(`refusing to record a round for ${b.backend}: no grounded code receipt for the current tree — run its review wrapper (codex-review code / agy-review code --facts @f) first, or mark the backend degraded with a reason`);
271
+ const own = receipts.filter((r) => r.backend === b.backend);
272
+ const failure = describeMissingReviewAttestation(summarizeReviewReceiptsForTree(own, fingerprint));
273
+ if (failure !== null) {
274
+ throw stop(`refusing to record a round for ${b.backend}: no grounded code receipt for the current tree can attest this round — ${failure}; run its real review (codex-review code / agy-review code --facts @f), or mark the backend degraded with a reason`);
267
275
  }
268
276
  }
269
277
 
@@ -518,7 +526,8 @@ record appends one review round. The JSON payload carries { loop, round, origi
518
526
  segment size-cap override (D4); while the segment lacks a quality-green gate-run at the
519
527
  current fingerprint (D5 — run the FULL matrix first: run-gates.mjs --record; a --only
520
528
  subset or a tree-changed run never satisfies; red PROCESS gates never block); or when a
521
- non-degraded backend lacks a grounded code receipt for the current tree.
529
+ non-degraded backend lacks an ATTESTING code receipt for the current tree (grounded AND
530
+ probe:false — a probe, unmarked or malformed marker never attests).
522
531
  classify appends one triage record. The JSON payload carries { loop, round, classifications } (each
523
532
  { findingKey, class, accepted, testId, note }). A fixable-bug REQUIRES a testId — the
524
533
  red→green test that pins the fold, formatted "<test-file>#<test-name-pattern>" (write it
@@ -19,8 +19,10 @@
19
19
  // no reviewer ready); when no plan is in flight (the review-state naming convention);
20
20
  // when the tree is clean (nothing to review); when the cwd is not a git work tree; and
21
21
  // when the in-flight plan-execution SEGMENT is `converged` or `resolved-residual` (its
22
- // latest round's non-degraded backends carry grounded code receipts for the recorded
23
- // fingerprint, and a recorded 0/0 is ship-class-consistent with those receipts).
22
+ // latest round's non-degraded backends carry ATTESTING code receipts for the recorded
23
+ // fingerprint the shared review-ledger-core predicate: grounded AND probe:false, a
24
+ // probe/unmarked/malformed marker never attests — and a recorded 0/0 is
25
+ // ship-class-consistent with those receipts).
24
26
  // exit 1 for any DIRTY in-flight plan-execution segment that is neither `converged` nor
25
27
  // `resolved-residual` — `triage-required`, `continue`, OR no round/receipt recorded in
26
28
  // the CURRENT segment (a dirty active plan with an empty/stale/other-segment ledger is a
@@ -83,6 +85,8 @@ import {
83
85
  filterLoopRecords,
84
86
  filterSegmentRecords,
85
87
  roundSequenceIntact,
88
+ summarizeReviewReceiptsForTree,
89
+ describeMissingReviewAttestation,
86
90
  } from './review-ledger-core.mjs';
87
91
  export {
88
92
  LEDGER_BASENAME,
@@ -270,22 +274,27 @@ export const decideStop = (records, { cap = REVIEW_CAP, currentFingerprint = nul
270
274
  // ── receipt cross-check (integrity binding, Decision 7) ──────────────────────────────────────────
271
275
 
272
276
  // receiptCrossCheck(round, receipts, fingerprint) → { ok, reason }. For each NON-degraded backend of
273
- // `round`: a grounded code receipt must exist for (backend, fingerprint) — a round cannot pass for a
274
- // tree no bridge reviewed — AND a recorded ship-class 0/0 must not coexist with a non-ship receipt
277
+ // `round`: an ATTESTING receipt must exist for (backend, fingerprint) — a round cannot pass for a
278
+ // tree no bridge really reviewed — AND a recorded ship-class 0/0 must not coexist with a non-ship
275
279
  // verdict. A degraded backend minted no receipt (it ran no real review) and is exempt.
280
+ // The attesting predicate is the SHARED one (review-ledger-core), the same review-state reads: this
281
+ // gate used to filter raw fields and take `own[own.length - 1]`, so a probe receipt landing AFTER a
282
+ // real one became the authoritative verdict — a late probe SHIP could bury a real REWORK and let
283
+ // BOTH gates report convergence (D3). The summary's `receipt` is the latest ATTESTING one, never
284
+ // simply the last line.
276
285
  export const receiptCrossCheck = (round, receipts, fingerprint) => {
277
286
  for (const b of round.backends) {
278
287
  if (b.degraded) continue;
279
- const own = receipts.filter(
280
- (r) => r.backend === b.backend && r.fingerprint === fingerprint && r.artifact === 'code' && r.fresh === true && r.grounded === true,
281
- );
282
- if (own.length === 0) {
283
- return { ok: false, reason: `no grounded code receipt for ${b.backend} at the recorded fingerprint (a recorded round must bind to a real review)` };
288
+ const own = receipts.filter((r) => r.backend === b.backend);
289
+ const summary = summarizeReviewReceiptsForTree(own, fingerprint);
290
+ const failure = describeMissingReviewAttestation(summary);
291
+ if (failure !== null) {
292
+ return { ok: false, reason: `no grounded code receipt for ${b.backend} at the recorded fingerprint can attest this review round ${failure}` };
284
293
  }
285
294
  if (b.blockers === 0 && b.majors === 0) {
286
- const latest = own[own.length - 1];
287
- if (!isShipVerdict(latest.verdict)) {
288
- return { ok: false, reason: `${b.backend} recorded 0 blockers/0 majors but its receipt verdict "${latest.verdict}" is not ship-class` };
295
+ const { verdict } = summary.receipt;
296
+ if (!isShipVerdict(verdict)) {
297
+ return { ok: false, reason: `${b.backend} recorded 0 blockers/0 majors but its attesting receipt verdict "${verdict}" is not ship-class` };
289
298
  }
290
299
  }
291
300
  }
@@ -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