@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.
- package/CHANGELOG.md +71 -0
- package/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +9 -1
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +22 -9
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +173 -2
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +76 -0
- package/bridges/antigravity-cli-bridge/capability.json +160 -2
- package/bridges/codex-cli-bridge/SKILL.md +8 -1
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +133 -0
- package/bridges/codex-cli-bridge/bin/codex-review.sh +22 -9
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +165 -2
- package/bridges/codex-cli-bridge/capability.json +118 -2
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/review-ledger.md +1 -1
- package/references/modes/review-state.md +2 -2
- package/tools/detect-backends.mjs +2 -2
- package/tools/manifest/schema.md +62 -0
- package/tools/manifest/validate.mjs +327 -0
- package/tools/review-ledger-core.mjs +74 -0
- package/tools/review-ledger-write.mjs +19 -10
- package/tools/review-ledger.mjs +21 -12
- package/tools/review-state.mjs +89 -28
package/tools/review-state.mjs
CHANGED
|
@@ -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 {
|
|
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
|
-
//
|
|
294
|
-
//
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
//
|
|
299
|
-
//
|
|
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
|
|
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
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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 (
|
|
312
|
-
|
|
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
|
-
|
|
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 === '
|
|
492
|
-
? '
|
|
493
|
-
:
|
|
494
|
-
|
|
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
|