@miller-tech/uap 1.96.6 → 1.97.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/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +2 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +17 -1
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/verify.d.ts +6 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +20 -2
- package/dist/cli/verify.js.map +1 -1
- package/dist/delivery/index.d.ts +1 -0
- package/dist/delivery/index.d.ts.map +1 -1
- package/dist/delivery/index.js +1 -0
- package/dist/delivery/index.js.map +1 -1
- package/dist/delivery/visual-gate.d.ts +88 -0
- package/dist/delivery/visual-gate.d.ts.map +1 -0
- package/dist/delivery/visual-gate.js +274 -0
- package/dist/delivery/visual-gate.js.map +1 -0
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/schemas/policies/visual-verification.md +52 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
package/dist/cli/verify.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type GateRung, type LadderResult } from '../delivery/verifier-ladder.js';
|
|
12
12
|
import { type AcceptanceResult } from '../delivery/acceptance-judge.js';
|
|
13
|
+
import { type VisualVerdict } from '../delivery/visual-gate.js';
|
|
13
14
|
import type { LoopExecutor } from '../delivery/convergence-loop.js';
|
|
14
15
|
export interface VerifyOptions {
|
|
15
16
|
/** Project directory to verify (default: cwd). */
|
|
@@ -30,6 +31,10 @@ export interface VerifyOptions {
|
|
|
30
31
|
acceptanceSpec?: string;
|
|
31
32
|
/** Model executor for the acceptance gate (injected; verifyCommand builds it). */
|
|
32
33
|
acceptanceExecutor?: LoopExecutor;
|
|
34
|
+
/** Visual gate: render entry pages, check blank/static/errors, save
|
|
35
|
+
* screenshots (default ON for web artifacts; false disables; fail-open
|
|
36
|
+
* without a browser). */
|
|
37
|
+
visual?: boolean;
|
|
33
38
|
}
|
|
34
39
|
export interface VerifyResult {
|
|
35
40
|
passed: boolean;
|
|
@@ -40,6 +45,7 @@ export interface VerifyResult {
|
|
|
40
45
|
ladder?: LadderResult;
|
|
41
46
|
rungs: GateRung[];
|
|
42
47
|
acceptance?: AcceptanceResult;
|
|
48
|
+
visual?: VisualVerdict;
|
|
43
49
|
}
|
|
44
50
|
/** Core verify logic — pure-ish (no process.exit), so it is unit-testable. */
|
|
45
51
|
export declare function runVerify(opts?: VerifyOptions): Promise<VerifyResult>;
|
package/dist/cli/verify.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/cli/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAwC,KAAK,QAAQ,EAAiB,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACvI,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/cli/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAwC,KAAK,QAAQ,EAAiB,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACvI,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnH,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAClC;;6BAEyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,8EAA8E;AAC9E,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsF/E;AA8CD,uEAAuE;AACvE,wBAAsB,aAAa,CACjC,OAAO,EAAE,aAAa,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACtF,OAAO,CAAC,IAAI,CAAC,CAoCf"}
|
package/dist/cli/verify.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { detectRungs, runTieredLadder, tierOf } from '../delivery/verifier-ladder.js';
|
|
12
12
|
import { runAcceptanceGate, formatAcceptanceReport } from '../delivery/acceptance-judge.js';
|
|
13
|
+
import { runVisualGate, discoverEntryPages } from '../delivery/visual-gate.js';
|
|
13
14
|
/** Core verify logic — pure-ish (no process.exit), so it is unit-testable. */
|
|
14
15
|
export async function runVerify(opts = {}) {
|
|
15
16
|
const dir = opts.dir ?? process.cwd();
|
|
@@ -52,7 +53,19 @@ export async function runVerify(opts = {}) {
|
|
|
52
53
|
maxTier,
|
|
53
54
|
...(opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {}),
|
|
54
55
|
});
|
|
55
|
-
|
|
56
|
+
// Visual gate: the rendered truth. Runs by default whenever the project has
|
|
57
|
+
// entry pages (opts.visual === false disables); fail-open without a browser.
|
|
58
|
+
// --runtime-only (the Stop hook's cheap path) skips it unless explicitly
|
|
59
|
+
// forced with visual: true — sampling frames in a real browser is not cheap,
|
|
60
|
+
// and minimal fixtures legitimately render near-blank.
|
|
61
|
+
let visual;
|
|
62
|
+
const visualWanted = opts.visual === true || (opts.visual !== false && !opts.runtimeOnly);
|
|
63
|
+
if (visualWanted && discoverEntryPages(dir).length > 0) {
|
|
64
|
+
visual = await runVisualGate(dir);
|
|
65
|
+
}
|
|
66
|
+
const visualBlocks = Boolean(visual && !visual.skipped && !visual.passed);
|
|
67
|
+
const visualReport = visual ? `\n${visual.feedback}` : '';
|
|
68
|
+
const report = formatReport(ladder) + visualReport + acceptanceReport;
|
|
56
69
|
// Exit-code contract for the Stop hook: 0 = verified, 1 = a REAL gate failure
|
|
57
70
|
// (the code is broken), 3 = INFRA failure (gate timed out / could not spawn /
|
|
58
71
|
// killed by signal). The hook hard-blocks only on 1; 3 fails OPEN so a flaky
|
|
@@ -64,14 +77,19 @@ export async function runVerify(opts = {}) {
|
|
|
64
77
|
}
|
|
65
78
|
if (acceptanceBlocks && exitCode === 0)
|
|
66
79
|
exitCode = 1;
|
|
80
|
+
// Visual problems are REAL failures (blank canvas, static rAF scene,
|
|
81
|
+
// runtime errors observed while watching) — they gate like broken code.
|
|
82
|
+
if (visualBlocks && exitCode === 0)
|
|
83
|
+
exitCode = 1;
|
|
67
84
|
return {
|
|
68
|
-
passed: ladder.passed && !acceptanceBlocks,
|
|
85
|
+
passed: ladder.passed && !acceptanceBlocks && !visualBlocks,
|
|
69
86
|
exitCode,
|
|
70
87
|
empty: false,
|
|
71
88
|
report,
|
|
72
89
|
ladder,
|
|
73
90
|
rungs,
|
|
74
91
|
acceptance,
|
|
92
|
+
visual,
|
|
75
93
|
};
|
|
76
94
|
}
|
|
77
95
|
function formatReport(ladder) {
|
package/dist/cli/verify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/cli/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAmD,MAAM,gCAAgC,CAAC;AACvI,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAyB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/cli/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAmD,MAAM,gCAAgC,CAAC;AACvI,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAyB,MAAM,iCAAiC,CAAC;AACnH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAsB,MAAM,4BAA4B,CAAC;AAwCnG,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB,EAAE;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAE7B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACjF,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,UAAU,GACd,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,kBAAkB;QAC5C,CAAC,CAAC,MAAM,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC7G,CAAC,CAAC,SAAS,CAAC;IAChB,6EAA6E;IAC7E,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;IAClF,MAAM,gBAAgB,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAErF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,6EAA6E;QAC7E,sEAAsE;QACtE,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAChC,MAAM,MAAM,GAAG,UAAU,IAAI,CAAC,gBAAgB,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;YAC1B,CAAC,CAAC,oDAAoD;YACtD,CAAC,CAAC,gEAAgE,CAAC;QACrE,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,GAAG,gBAAgB,EAAE;YAC1F,KAAK;YACL,UAAU;SACX,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAa,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE;QAC/C,OAAO;QACP,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CAAC;IAEH,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,uDAAuD;IACvD,IAAI,MAAiC,CAAC;IACtC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1F,IAAI,YAAY,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1E,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1D,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,GAAG,gBAAgB,CAAC;IACtE,8EAA8E;IAC9E,8EAA8E;IAC9E,6EAA6E;IAC7E,wEAAwE;IACxE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,aAAa,KAAK,MAAM,CAC7D,CAAC;QACF,QAAQ,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,gBAAgB,IAAI,QAAQ,KAAK,CAAC;QAAE,QAAQ,GAAG,CAAC,CAAC;IACrD,qEAAqE;IACrE,wEAAwE;IACxE,IAAI,YAAY,IAAI,QAAQ,KAAK,CAAC;QAAE,QAAQ,GAAG,CAAC,CAAC;IACjD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,gBAAgB,IAAI,CAAC,YAAY;QAC3D,QAAQ;QACR,KAAK,EAAE,KAAK;QACZ,MAAM;QACN,MAAM;QACN,KAAK;QACL,UAAU;QACV,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,MAAoB;IACxC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7D,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrF,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CACR,CAAC,CAAC,UAAU;iBACT,KAAK,CAAC,IAAI,CAAC;iBACX,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;iBACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;iBAC1B,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM;QAC1B,CAAC,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,oBAAoB;QACnE,CAAC,CAAC,mBAAmB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC1E,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,uBAAuB,CAAC,WAAoB,EAAE,QAAiB;IAC5E,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,mCAAmC,CAAC,CAAC;IACjF,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,YAAY,CAAC;IAC9E,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,iBAAiB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3D,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC;IACzE,IAAI,EAAE,IAAI,CAAC,+FAA+F,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QACpH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iFAAiF,EAAE,MAAM,CAAC,CAAC;IAClH,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;IACxC,OAAO,KAAK,EAAE,MAAc,EAAE,EAAE;QAC9B,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,OAAO,CAAC,CAAC,OAAO,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAuF;IAEvF,2EAA2E;IAC3E,0DAA0D;IAC1D,IAAI,IAAI,GAAkB,OAAO,CAAC;IAClC,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,OAAO,CAAC,cAAc,KAAK,CAAC,CAAC;YAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAChF,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;IAC5E,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CACZ;YACE,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI;YACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE;YACrC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;SACtC,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI,CACT,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/delivery/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { ConvergenceLoop, composeIterationHooks, defaultPromptBuilder, type Cand
|
|
|
9
9
|
export { saveRunState, loadRunState, newRunId, isValidRunId, deliverRunsDir, type DeliverRunState, type DeliverRunStatus, } from './run-state.js';
|
|
10
10
|
export { planDeliveryPhases, parsePhaseArray, phaseInstruction, shouldDecompose, type DeliveryPhase, } from './decompose.js';
|
|
11
11
|
export { autoMineHaloTraces, summarizeWeaknesses, isAutoMineEnabled, weaknessGuidance, loadPersistedWeaknesses, type AutoMineResult, } from './auto-mine.js';
|
|
12
|
+
export { runVisualGate, discoverEntryPages, judgePage, motionBetween, visualRuntimeNote, type VisualVerdict, type PageVisualReport, type VisualGateOptions, type VisualBrowserDriver, } from './visual-gate.js';
|
|
12
13
|
export { createGitWorktreeProvider, isParallelExploreEnabled, type CandidateWorkspace, type WorkspaceProvider, } from './candidate-workspace.js';
|
|
13
14
|
export { openDeliveryTask, completeDeliveryTask, recordDeliveryOutcome, hasTaskDb, type DeliveryTaskHandle, } from './task-sync.js';
|
|
14
15
|
export { createEscalationController, defaultEscalationLadder, type DefaultLadderOptions, type EscalationConfig, type EscalationController, type EscalationTier, } from './escalation.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delivery/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delivery/index.ts"],"names":[],"mappings":"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"}
|
package/dist/delivery/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { ConvergenceLoop, composeIterationHooks, defaultPromptBuilder, } from '.
|
|
|
9
9
|
export { saveRunState, loadRunState, newRunId, isValidRunId, deliverRunsDir, } from './run-state.js';
|
|
10
10
|
export { planDeliveryPhases, parsePhaseArray, phaseInstruction, shouldDecompose, } from './decompose.js';
|
|
11
11
|
export { autoMineHaloTraces, summarizeWeaknesses, isAutoMineEnabled, weaknessGuidance, loadPersistedWeaknesses, } from './auto-mine.js';
|
|
12
|
+
export { runVisualGate, discoverEntryPages, judgePage, motionBetween, visualRuntimeNote, } from './visual-gate.js';
|
|
12
13
|
export { createGitWorktreeProvider, isParallelExploreEnabled, } from './candidate-workspace.js';
|
|
13
14
|
export { openDeliveryTask, completeDeliveryTask, recordDeliveryOutcome, hasTaskDb, } from './task-sync.js';
|
|
14
15
|
export { createEscalationController, defaultEscalationLadder, } from './escalation.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delivery/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,oBAAoB,GAcrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,cAAc,GAGf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,GAEhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,GAExB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GAGzB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,GAEV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,GAKxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,yBAAyB,GAM1B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,GAKf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,WAAW,GAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,YAAY,GAIb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,SAAS,EACT,OAAO,EACP,cAAc,GAMf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,GAMf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,8BAA8B,GAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,GAG3B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,cAAc,GAEf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,wBAAwB,GAGzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAkC,MAAM,mCAAmC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delivery/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,oBAAoB,GAcrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,cAAc,GAGf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,GAEhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,GAExB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,iBAAiB,GAKlB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GAGzB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,GAEV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,GAKxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,yBAAyB,GAM1B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,GAKf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,WAAW,GAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,YAAY,GAIb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,SAAS,EACT,OAAO,EACP,cAAc,GAMf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,GAMf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,8BAA8B,GAG/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,GAG3B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,cAAc,GAEf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,wBAAwB,GAGzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAkC,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual Gate — verify that a delivered web artifact actually LOOKS like a
|
|
3
|
+
* working application and BEHAVES over time, not merely that it loads.
|
|
4
|
+
*
|
|
5
|
+
* The execution gate proves crash-free load; the acceptance judge reads code
|
|
6
|
+
* evidence. Both were fooled by real deliveries (a game whose enemy waves
|
|
7
|
+
* were never started; scenes whose "physics" could have been a static frame).
|
|
8
|
+
* This gate closes that class:
|
|
9
|
+
*
|
|
10
|
+
* 1. Loads every root-level entry .html in a headless browser.
|
|
11
|
+
* 2. Samples the canvas/DOM pixels IN-PAGE on a grid at several instants:
|
|
12
|
+
* - blank detection (dominant-color ratio, distinct-color count)
|
|
13
|
+
* - animation detection (grid cells changing between samples — required
|
|
14
|
+
* whenever the page source uses requestAnimationFrame)
|
|
15
|
+
* - uncaught runtime errors across the whole observation window
|
|
16
|
+
* 3. Saves timestamped screenshots to `.uap/visual/` so a vision-capable
|
|
17
|
+
* reviewer (human, Claude session, or a configured vision model) can apply
|
|
18
|
+
* design and aesthetic judgment to the real rendered output.
|
|
19
|
+
*
|
|
20
|
+
* The verdict is objective and machine-checked; the screenshots are the
|
|
21
|
+
* hand-off point for aesthetic review (see the visual-verification policy).
|
|
22
|
+
* Fail-open ONLY when no browser is available (vm-DOM cannot render pixels);
|
|
23
|
+
* everything observed is reported either way.
|
|
24
|
+
*/
|
|
25
|
+
/** Browser surface the gate needs (satisfied by src/browser WebBrowser). */
|
|
26
|
+
export interface VisualBrowserDriver {
|
|
27
|
+
launch(opts?: Record<string, unknown>): Promise<unknown>;
|
|
28
|
+
goto(url: string): Promise<string>;
|
|
29
|
+
waitForLoadState(state?: 'load' | 'domcontentloaded' | 'networkidle'): Promise<void>;
|
|
30
|
+
evaluate<T>(script: string): Promise<T>;
|
|
31
|
+
screenshot(path: string): Promise<void>;
|
|
32
|
+
getErrors(): Array<{
|
|
33
|
+
kind: string;
|
|
34
|
+
message: string;
|
|
35
|
+
}>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export interface VisualGateOptions {
|
|
39
|
+
/** Entry html files relative to projectRoot (default: root-level *.html, index first, max 6). */
|
|
40
|
+
files?: string[];
|
|
41
|
+
/** Pixel samples per page (default 3). */
|
|
42
|
+
samples?: number;
|
|
43
|
+
/** Interval between samples in ms (default 900). */
|
|
44
|
+
intervalMs?: number;
|
|
45
|
+
/** Per-page hard budget in ms (default 30000). */
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
/** Injected browser (tests). Default: the real WebBrowser (cloakbrowser). */
|
|
48
|
+
browserFactory?: () => VisualBrowserDriver;
|
|
49
|
+
}
|
|
50
|
+
export interface PageVisualReport {
|
|
51
|
+
file: string;
|
|
52
|
+
loaded: boolean;
|
|
53
|
+
hasCanvas: boolean;
|
|
54
|
+
/** Grid stats from the last sample. */
|
|
55
|
+
distinctColors: number;
|
|
56
|
+
dominantRatio: number;
|
|
57
|
+
/** Fraction of grid cells that changed between first and last sample. */
|
|
58
|
+
motionRatio: number;
|
|
59
|
+
/** Whether the page source demands animation (requestAnimationFrame). */
|
|
60
|
+
expectsAnimation: boolean;
|
|
61
|
+
runtimeErrors: string[];
|
|
62
|
+
screenshots: string[];
|
|
63
|
+
/** Failures for THIS page (empty = visually sound). */
|
|
64
|
+
problems: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface VisualVerdict {
|
|
67
|
+
/** False when any page has objective visual/behavioral problems. */
|
|
68
|
+
passed: boolean;
|
|
69
|
+
/** True when the gate could not run (no browser) — advisory pass. */
|
|
70
|
+
skipped: boolean;
|
|
71
|
+
feedback: string;
|
|
72
|
+
pages: PageVisualReport[];
|
|
73
|
+
screenshotDir: string | null;
|
|
74
|
+
}
|
|
75
|
+
/** Root-level entry pages: index.html first, then other .html files. */
|
|
76
|
+
export declare function discoverEntryPages(projectRoot: string): string[];
|
|
77
|
+
/** Fraction of grid cells that differ between two samples. */
|
|
78
|
+
export declare function motionBetween(a: string[] | undefined, b: string[] | undefined): number;
|
|
79
|
+
/** Pure verdict for one page from its observations — unit-testable. */
|
|
80
|
+
export declare function judgePage(report: Omit<PageVisualReport, 'problems'>): string[];
|
|
81
|
+
/**
|
|
82
|
+
* Run the visual gate over the project's entry pages. Fail-open (skipped=true)
|
|
83
|
+
* only when no browser can launch.
|
|
84
|
+
*/
|
|
85
|
+
export declare function runVisualGate(projectRoot: string, options?: VisualGateOptions): Promise<VisualVerdict>;
|
|
86
|
+
/** One-line summary for acceptance-judge evidence (runtimeNote). */
|
|
87
|
+
export declare function visualRuntimeNote(verdict: VisualVerdict): string;
|
|
88
|
+
//# sourceMappingURL=visual-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visual-gate.d.ts","sourceRoot":"","sources":["../../src/delivery/visual-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,iGAAiG;IACjG,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AA2DD,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAQhE;AAOD,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAKtF;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,CAwB9E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAiIxB;AAUD,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAOhE"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual Gate — verify that a delivered web artifact actually LOOKS like a
|
|
3
|
+
* working application and BEHAVES over time, not merely that it loads.
|
|
4
|
+
*
|
|
5
|
+
* The execution gate proves crash-free load; the acceptance judge reads code
|
|
6
|
+
* evidence. Both were fooled by real deliveries (a game whose enemy waves
|
|
7
|
+
* were never started; scenes whose "physics" could have been a static frame).
|
|
8
|
+
* This gate closes that class:
|
|
9
|
+
*
|
|
10
|
+
* 1. Loads every root-level entry .html in a headless browser.
|
|
11
|
+
* 2. Samples the canvas/DOM pixels IN-PAGE on a grid at several instants:
|
|
12
|
+
* - blank detection (dominant-color ratio, distinct-color count)
|
|
13
|
+
* - animation detection (grid cells changing between samples — required
|
|
14
|
+
* whenever the page source uses requestAnimationFrame)
|
|
15
|
+
* - uncaught runtime errors across the whole observation window
|
|
16
|
+
* 3. Saves timestamped screenshots to `.uap/visual/` so a vision-capable
|
|
17
|
+
* reviewer (human, Claude session, or a configured vision model) can apply
|
|
18
|
+
* design and aesthetic judgment to the real rendered output.
|
|
19
|
+
*
|
|
20
|
+
* The verdict is objective and machine-checked; the screenshots are the
|
|
21
|
+
* hand-off point for aesthetic review (see the visual-verification policy).
|
|
22
|
+
* Fail-open ONLY when no browser is available (vm-DOM cannot render pixels);
|
|
23
|
+
* everything observed is reported either way.
|
|
24
|
+
*/
|
|
25
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync } from 'fs';
|
|
26
|
+
import { join } from 'path';
|
|
27
|
+
import { startStaticServer } from './execution-gate.js';
|
|
28
|
+
const GRID = 24;
|
|
29
|
+
const DEFAULT_SAMPLES = 3;
|
|
30
|
+
const DEFAULT_INTERVAL_MS = 900;
|
|
31
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
32
|
+
const MAX_PAGES = 6;
|
|
33
|
+
/** A canvas showing fewer distinct colors than this is a blank/failed render. */
|
|
34
|
+
const MIN_DISTINCT_COLORS = 3;
|
|
35
|
+
/** One color covering more of the grid than this is a blank-ish frame. */
|
|
36
|
+
const MAX_DOMINANT_RATIO = 0.98;
|
|
37
|
+
/** rAF pages must move at least this fraction of grid cells across samples. */
|
|
38
|
+
const MIN_MOTION_RATIO = 0.02;
|
|
39
|
+
/** In-page probe: sample the largest canvas on a GRID×GRID grid. Returns JSON.
|
|
40
|
+
* NOTE: a function EXPRESSION (not self-invoked) — WebBrowser.evaluate wraps
|
|
41
|
+
* string scripts as `return (<script>)()`, supplying the invocation itself. */
|
|
42
|
+
const PIXEL_PROBE = `(function () {
|
|
43
|
+
var canvases = Array.prototype.slice.call(document.querySelectorAll('canvas'));
|
|
44
|
+
if (canvases.length === 0) return JSON.stringify({ canvas: false });
|
|
45
|
+
canvases.sort(function (a, b) { return b.width * b.height - a.width * a.height; });
|
|
46
|
+
var c = canvases[0];
|
|
47
|
+
var ctx = c.getContext('2d');
|
|
48
|
+
if (!ctx || !c.width || !c.height) return JSON.stringify({ canvas: true, readable: false });
|
|
49
|
+
var img;
|
|
50
|
+
try { img = ctx.getImageData(0, 0, c.width, c.height).data; }
|
|
51
|
+
catch (e) { return JSON.stringify({ canvas: true, readable: false }); }
|
|
52
|
+
var N = ${GRID}, colors = {}, cells = [];
|
|
53
|
+
for (var gy = 0; gy < N; gy++) {
|
|
54
|
+
for (var gx = 0; gx < N; gx++) {
|
|
55
|
+
var x = Math.floor((gx + 0.5) * c.width / N);
|
|
56
|
+
var y = Math.floor((gy + 0.5) * c.height / N);
|
|
57
|
+
var i = (y * c.width + x) * 4;
|
|
58
|
+
var key = (img[i] >> 4) + ',' + (img[i + 1] >> 4) + ',' + (img[i + 2] >> 4);
|
|
59
|
+
colors[key] = (colors[key] || 0) + 1;
|
|
60
|
+
cells.push(key);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
var dominant = 0;
|
|
64
|
+
for (var k in colors) if (colors[k] > dominant) dominant = colors[k];
|
|
65
|
+
return JSON.stringify({
|
|
66
|
+
canvas: true, readable: true, cells: cells,
|
|
67
|
+
distinctColors: Object.keys(colors).length,
|
|
68
|
+
dominantRatio: dominant / cells.length,
|
|
69
|
+
});
|
|
70
|
+
})`;
|
|
71
|
+
function delay(ms) {
|
|
72
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
73
|
+
}
|
|
74
|
+
/** Root-level entry pages: index.html first, then other .html files. */
|
|
75
|
+
export function discoverEntryPages(projectRoot) {
|
|
76
|
+
try {
|
|
77
|
+
const all = readdirSync(projectRoot).filter((f) => f.toLowerCase().endsWith('.html'));
|
|
78
|
+
all.sort((a, b) => (a === 'index.html' ? -1 : b === 'index.html' ? 1 : a.localeCompare(b)));
|
|
79
|
+
return all.slice(0, MAX_PAGES);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function loadRealBrowser() {
|
|
86
|
+
const mod = await import('../browser/web-browser.js');
|
|
87
|
+
return new mod.WebBrowser();
|
|
88
|
+
}
|
|
89
|
+
/** Fraction of grid cells that differ between two samples. */
|
|
90
|
+
export function motionBetween(a, b) {
|
|
91
|
+
if (!a || !b || a.length === 0 || a.length !== b.length)
|
|
92
|
+
return 0;
|
|
93
|
+
let changed = 0;
|
|
94
|
+
for (let i = 0; i < a.length; i++)
|
|
95
|
+
if (a[i] !== b[i])
|
|
96
|
+
changed++;
|
|
97
|
+
return changed / a.length;
|
|
98
|
+
}
|
|
99
|
+
/** Pure verdict for one page from its observations — unit-testable. */
|
|
100
|
+
export function judgePage(report) {
|
|
101
|
+
const problems = [];
|
|
102
|
+
if (!report.loaded) {
|
|
103
|
+
problems.push('page did not load');
|
|
104
|
+
return problems;
|
|
105
|
+
}
|
|
106
|
+
if (report.runtimeErrors.length > 0) {
|
|
107
|
+
problems.push(`uncaught runtime error(s) during observation: ${report.runtimeErrors[0].slice(0, 200)}`);
|
|
108
|
+
}
|
|
109
|
+
if (report.hasCanvas) {
|
|
110
|
+
if (report.distinctColors < MIN_DISTINCT_COLORS || report.dominantRatio > MAX_DOMINANT_RATIO) {
|
|
111
|
+
problems.push(`canvas renders blank/near-blank (${report.distinctColors} distinct colors, dominant color covers ${Math.round(report.dominantRatio * 100)}%)`);
|
|
112
|
+
}
|
|
113
|
+
if (report.expectsAnimation && report.motionRatio < MIN_MOTION_RATIO) {
|
|
114
|
+
problems.push(`page uses requestAnimationFrame but the canvas is STATIC (${(report.motionRatio * 100).toFixed(1)}% of cells changed between samples) — the scene is not actually animating`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (report.expectsAnimation) {
|
|
118
|
+
problems.push('page source expects a canvas animation but no canvas was found in the DOM');
|
|
119
|
+
}
|
|
120
|
+
return problems;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Run the visual gate over the project's entry pages. Fail-open (skipped=true)
|
|
124
|
+
* only when no browser can launch.
|
|
125
|
+
*/
|
|
126
|
+
export async function runVisualGate(projectRoot, options = {}) {
|
|
127
|
+
const files = options.files ?? discoverEntryPages(projectRoot);
|
|
128
|
+
if (files.length === 0) {
|
|
129
|
+
return { passed: true, skipped: true, feedback: 'visual gate: no entry .html pages found', pages: [], screenshotDir: null };
|
|
130
|
+
}
|
|
131
|
+
const samples = Math.max(2, options.samples ?? DEFAULT_SAMPLES);
|
|
132
|
+
const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
133
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
134
|
+
const screenshotDir = join(projectRoot, '.uap', 'visual');
|
|
135
|
+
try {
|
|
136
|
+
mkdirSync(screenshotDir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// screenshots become best-effort
|
|
140
|
+
}
|
|
141
|
+
let server = null;
|
|
142
|
+
const pages = [];
|
|
143
|
+
try {
|
|
144
|
+
server = await startStaticServer(projectRoot);
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
let browser = null;
|
|
147
|
+
try {
|
|
148
|
+
browser = options.browserFactory ? options.browserFactory() : await loadRealBrowser();
|
|
149
|
+
await browser.launch({ headless: true });
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
try {
|
|
153
|
+
await browser?.close();
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* ignore */
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
passed: true,
|
|
160
|
+
skipped: true,
|
|
161
|
+
feedback: `visual gate skipped: browser unavailable (${String(e).slice(0, 120)})`,
|
|
162
|
+
pages,
|
|
163
|
+
screenshotDir: null,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const start = Date.now();
|
|
167
|
+
const src = safeRead(join(projectRoot, file));
|
|
168
|
+
const expectsAnimation = /requestAnimationFrame/.test(src);
|
|
169
|
+
const shots = [];
|
|
170
|
+
let loaded = false;
|
|
171
|
+
let probes = [];
|
|
172
|
+
try {
|
|
173
|
+
// startStaticServer's url includes its own entry path (/index.html);
|
|
174
|
+
// navigate per page from the ORIGIN.
|
|
175
|
+
const origin = new URL(server.url).origin;
|
|
176
|
+
const status = await Promise.race([
|
|
177
|
+
browser.goto(`${origin}/${file}`),
|
|
178
|
+
delay(timeoutMs).then(() => 'timeout'),
|
|
179
|
+
]);
|
|
180
|
+
loaded = /^2\d\d$/.test(String(status)) || String(status) === '304';
|
|
181
|
+
await Promise.race([browser.waitForLoadState('load'), delay(5000)]).catch(() => undefined);
|
|
182
|
+
if (loaded) {
|
|
183
|
+
for (let i = 0; i < samples && Date.now() - start < timeoutMs; i++) {
|
|
184
|
+
if (i > 0)
|
|
185
|
+
await delay(intervalMs);
|
|
186
|
+
try {
|
|
187
|
+
const raw = await browser.evaluate(PIXEL_PROBE);
|
|
188
|
+
probes.push(JSON.parse(raw));
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
probes.push({ canvas: false });
|
|
192
|
+
}
|
|
193
|
+
const shot = join(screenshotDir, `${file.replace(/\.html$/i, '')}-t${i}.png`);
|
|
194
|
+
try {
|
|
195
|
+
await browser.screenshot(shot);
|
|
196
|
+
shots.push(shot);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// screenshots are best-effort evidence
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
probes = [];
|
|
206
|
+
loaded = false;
|
|
207
|
+
}
|
|
208
|
+
const errors = browser
|
|
209
|
+
.getErrors()
|
|
210
|
+
.filter((e) => e.kind === 'pageerror')
|
|
211
|
+
.map((e) => e.message);
|
|
212
|
+
await browser.close().catch(() => undefined);
|
|
213
|
+
const last = probes[probes.length - 1] ?? { canvas: false };
|
|
214
|
+
const first = probes.find((p) => p.readable);
|
|
215
|
+
const base = {
|
|
216
|
+
file,
|
|
217
|
+
loaded,
|
|
218
|
+
hasCanvas: Boolean(last.canvas),
|
|
219
|
+
distinctColors: last.distinctColors ?? 0,
|
|
220
|
+
dominantRatio: last.dominantRatio ?? 1,
|
|
221
|
+
motionRatio: motionBetween(first?.cells, last.cells),
|
|
222
|
+
expectsAnimation,
|
|
223
|
+
runtimeErrors: errors,
|
|
224
|
+
screenshots: shots,
|
|
225
|
+
};
|
|
226
|
+
pages.push({ ...base, problems: judgePage(base) });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (e) {
|
|
230
|
+
return {
|
|
231
|
+
passed: true,
|
|
232
|
+
skipped: true,
|
|
233
|
+
feedback: `visual gate skipped: ${String(e).slice(0, 160)}`,
|
|
234
|
+
pages,
|
|
235
|
+
screenshotDir: null,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
server?.close();
|
|
240
|
+
}
|
|
241
|
+
const failing = pages.filter((p) => p.problems.length > 0);
|
|
242
|
+
const passed = failing.length === 0;
|
|
243
|
+
const lines = [];
|
|
244
|
+
for (const p of pages) {
|
|
245
|
+
const stat = p.problems.length === 0
|
|
246
|
+
? `OK (motion ${(p.motionRatio * 100).toFixed(1)}%, ${p.distinctColors} colors)`
|
|
247
|
+
: p.problems.join('; ');
|
|
248
|
+
lines.push(`- ${p.file}: ${stat}`);
|
|
249
|
+
}
|
|
250
|
+
if (!passed) {
|
|
251
|
+
lines.unshift('VISUAL/BEHAVIORAL PROBLEMS — the rendered output is wrong even though the code loads:');
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
lines.unshift(`visual gate: ${pages.length} page(s) render, animate, and run clean`);
|
|
255
|
+
}
|
|
256
|
+
lines.push(`screenshots: ${screenshotDir} (review for design/aesthetic quality)`);
|
|
257
|
+
return { passed, skipped: false, feedback: lines.join('\n'), pages, screenshotDir };
|
|
258
|
+
}
|
|
259
|
+
function safeRead(path) {
|
|
260
|
+
try {
|
|
261
|
+
return existsSync(path) ? readFileSync(path, 'utf-8') : '';
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return '';
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** One-line summary for acceptance-judge evidence (runtimeNote). */
|
|
268
|
+
export function visualRuntimeNote(verdict) {
|
|
269
|
+
if (verdict.skipped)
|
|
270
|
+
return '';
|
|
271
|
+
const parts = verdict.pages.map((p) => `${p.file}: ${p.problems.length === 0 ? 'renders+animates OK' : p.problems.join('; ')} (motion ${(p.motionRatio * 100).toFixed(1)}%)`);
|
|
272
|
+
return `Visual observation of the RUNNING artifact: ${parts.join(' | ')}`;
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=visual-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visual-gate.js","sourceRoot":"","sources":["../../src/delivery/visual-gate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# visual-verification
|
|
2
|
+
|
|
3
|
+
**Category**: quality
|
|
4
|
+
**Level**: REQUIRED
|
|
5
|
+
**Enforcement Stage**: post-exec
|
|
6
|
+
**Tags**: visual, ui, ux, behavior, screenshots, design, verification
|
|
7
|
+
|
|
8
|
+
## Rule
|
|
9
|
+
|
|
10
|
+
A delivery whose artifact renders (web/canvas/UI) is NOT done until its
|
|
11
|
+
**rendered output has been observed running**:
|
|
12
|
+
|
|
13
|
+
1. The visual gate (`uap verify` / deliver's acceptance path) must pass: every
|
|
14
|
+
entry page loads, the canvas/DOM is not blank, pages that use
|
|
15
|
+
`requestAnimationFrame` are actually animating (pixel motion between
|
|
16
|
+
samples), and no uncaught errors occur during the observation window.
|
|
17
|
+
2. The screenshots the gate saves under `.uap/visual/` must be **reviewed by a
|
|
18
|
+
vision-capable reviewer** (the driving agent session, a configured vision
|
|
19
|
+
model, or a human) for design and aesthetic quality — composition, color,
|
|
20
|
+
readability, polish — and findings applied before claiming done.
|
|
21
|
+
3. Behavioral claims in the spec (things spawn, collide, crush, score) must be
|
|
22
|
+
confirmed against the *observed* runtime — the gate's motion/state samples
|
|
23
|
+
and screenshots — never from code reading alone.
|
|
24
|
+
|
|
25
|
+
## Why
|
|
26
|
+
|
|
27
|
+
Two live deliveries passed every code-level gate while being behaviorally
|
|
28
|
+
wrong: a game whose enemy waves were never started (complete wave logic,
|
|
29
|
+
never called — 18/18 code-evidence acceptance), and physics scenes whose
|
|
30
|
+
animation was only presumed. Load-testing proves "does not crash"; code
|
|
31
|
+
evidence proves "logic exists". Only watching the rendered artifact proves
|
|
32
|
+
"it works and looks right". Screenshots make aesthetic taste applicable:
|
|
33
|
+
an agent that can see the output can improve it.
|
|
34
|
+
|
|
35
|
+
## Enforcement
|
|
36
|
+
|
|
37
|
+
- `src/delivery/visual-gate.ts` — headless render + in-page pixel-grid
|
|
38
|
+
sampling (blank/static/error detection), screenshots to `.uap/visual/`.
|
|
39
|
+
- `uap verify` runs it by default whenever entry `.html` pages exist
|
|
40
|
+
(`--no-visual` opts out); failures are REAL failures (exit 1).
|
|
41
|
+
- `uap deliver` (acceptance-primary path) blocks acceptance on visual
|
|
42
|
+
failures and feeds the observation summary to the acceptance judge as
|
|
43
|
+
runtime evidence.
|
|
44
|
+
- Fail-open ONLY when no headless browser is available (vm-DOM cannot
|
|
45
|
+
render pixels); the skip is stated explicitly in the report.
|
|
46
|
+
|
|
47
|
+
## Agent obligations
|
|
48
|
+
|
|
49
|
+
After any delivery with a rendered artifact: run `uap verify --dir <project>`,
|
|
50
|
+
Read the `.uap/visual/*.png` screenshots, apply design/aesthetic judgment
|
|
51
|
+
(spacing, palette, hierarchy, motion feel), fix what looks wrong, and re-verify.
|
|
52
|
+
"It passed the gates" is not "it looks right".
|