@miller-tech/uap 1.96.6 → 1.98.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.
Files changed (49) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/benchmarks/paired/adapter.d.ts +15 -0
  3. package/dist/benchmarks/paired/adapter.d.ts.map +1 -1
  4. package/dist/benchmarks/paired/adapter.js +79 -20
  5. package/dist/benchmarks/paired/adapter.js.map +1 -1
  6. package/dist/benchmarks/paired/types.d.ts +9 -0
  7. package/dist/benchmarks/paired/types.d.ts.map +1 -1
  8. package/dist/benchmarks/paired/types.js +9 -0
  9. package/dist/benchmarks/paired/types.js.map +1 -1
  10. package/dist/bin/cli.js +4 -0
  11. package/dist/bin/cli.js.map +1 -1
  12. package/dist/cli/bench.d.ts +2 -0
  13. package/dist/cli/bench.d.ts.map +1 -1
  14. package/dist/cli/bench.js +8 -2
  15. package/dist/cli/bench.js.map +1 -1
  16. package/dist/cli/deliver.d.ts +4 -0
  17. package/dist/cli/deliver.d.ts.map +1 -1
  18. package/dist/cli/deliver.js +88 -12
  19. package/dist/cli/deliver.js.map +1 -1
  20. package/dist/cli/verify.d.ts +6 -0
  21. package/dist/cli/verify.d.ts.map +1 -1
  22. package/dist/cli/verify.js +37 -2
  23. package/dist/cli/verify.js.map +1 -1
  24. package/dist/delivery/decompose.d.ts +9 -0
  25. package/dist/delivery/decompose.d.ts.map +1 -1
  26. package/dist/delivery/decompose.js +38 -4
  27. package/dist/delivery/decompose.js.map +1 -1
  28. package/dist/delivery/index.d.ts +2 -0
  29. package/dist/delivery/index.d.ts.map +1 -1
  30. package/dist/delivery/index.js +2 -0
  31. package/dist/delivery/index.js.map +1 -1
  32. package/dist/delivery/vision-judge.d.ts +28 -0
  33. package/dist/delivery/vision-judge.d.ts.map +1 -0
  34. package/dist/delivery/vision-judge.js +98 -0
  35. package/dist/delivery/vision-judge.js.map +1 -0
  36. package/dist/delivery/visual-gate.d.ts +112 -0
  37. package/dist/delivery/visual-gate.d.ts.map +1 -0
  38. package/dist/delivery/visual-gate.js +292 -0
  39. package/dist/delivery/visual-gate.js.map +1 -0
  40. package/dist/models/openai-compat-client.d.ts +1 -0
  41. package/dist/models/openai-compat-client.d.ts.map +1 -1
  42. package/dist/models/openai-compat-client.js +4 -0
  43. package/dist/models/openai-compat-client.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  46. package/src/policies/schemas/policies/visual-verification.md +52 -0
  47. package/tools/agents/config/json-response.gbnf +7 -0
  48. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  49. package/tools/agents/scripts/anthropic_proxy.py +56 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Vision Judge — aesthetic/behavioral review of the visual gate's screenshots
3
+ * by a vision-capable model (the seam the visual-verification policy names).
4
+ *
5
+ * The pixel heuristics prove "renders and moves"; only vision can judge
6
+ * "looks right". When UAP_VISION_MODEL (+ UAP_VISION_ENDPOINT, OpenAI-compat
7
+ * with image_url support) is configured, the saved screenshots are scored
8
+ * against the spec; findings flow into reports/acceptance evidence as
9
+ * ADVISORY context. Unset config or any failure returns null — this seam is
10
+ * fail-soft by contract and never blocks a delivery on its own.
11
+ */
12
+ import { readFileSync } from 'fs';
13
+ import { fetchModelWithRetry } from '../models/long-fetch.js';
14
+ const MAX_IMAGES = 4;
15
+ const MAX_FINDINGS = 8;
16
+ export function visionJudgeConfigured() {
17
+ return Boolean(process.env.UAP_VISION_MODEL && process.env.UAP_VISION_ENDPOINT);
18
+ }
19
+ /** Extract the first JSON object from model output (grammar-free fallback). */
20
+ export function parseVisionVerdict(text) {
21
+ const match = text.match(/\{[\s\S]*\}/);
22
+ if (!match)
23
+ return null;
24
+ try {
25
+ const parsed = JSON.parse(match[0]);
26
+ const score = Number(parsed.score);
27
+ if (!Number.isFinite(score))
28
+ return null;
29
+ const findings = Array.isArray(parsed.findings)
30
+ ? parsed.findings.filter((f) => typeof f === 'string').slice(0, MAX_FINDINGS)
31
+ : [];
32
+ return { score: Math.max(0, Math.min(10, score)), findings };
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * Score screenshots against the spec with the configured vision model.
40
+ * Returns null when unconfigured or on any failure.
41
+ */
42
+ export async function judgeScreenshots(screenshotPaths, spec, fetchImpl) {
43
+ if (!visionJudgeConfigured() || screenshotPaths.length === 0)
44
+ return null;
45
+ const endpoint = process.env.UAP_VISION_ENDPOINT.replace(/\/$/, '');
46
+ const model = process.env.UAP_VISION_MODEL;
47
+ try {
48
+ const images = screenshotPaths.slice(0, MAX_IMAGES).map((p) => ({
49
+ type: 'image_url',
50
+ image_url: { url: `data:image/png;base64,${readFileSync(p).toString('base64')}` },
51
+ }));
52
+ const body = {
53
+ model,
54
+ max_tokens: 800,
55
+ messages: [
56
+ {
57
+ role: 'user',
58
+ content: [
59
+ {
60
+ type: 'text',
61
+ text: 'You are a strict visual reviewer. These are frames of a rendered application. ' +
62
+ 'Judge (a) design/aesthetic quality (composition, color, readability, polish) and ' +
63
+ '(b) whether the visible behavior matches the spec below. Respond with ONLY JSON: ' +
64
+ '{"score": <0-10>, "findings": ["<specific, actionable issue>", ...]}\n\nSPEC:\n' +
65
+ spec.slice(0, 4000),
66
+ },
67
+ ...images,
68
+ ],
69
+ },
70
+ ],
71
+ };
72
+ const doFetch = fetchImpl ?? fetchModelWithRetry;
73
+ const res = await doFetch(`${endpoint}/chat/completions`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ ...(process.env.UAP_VISION_API_KEY ? { Authorization: `Bearer ${process.env.UAP_VISION_API_KEY}` } : {}),
78
+ },
79
+ body: JSON.stringify(body),
80
+ });
81
+ if (!res.ok)
82
+ return null;
83
+ const data = (await res.json());
84
+ const content = data.choices?.[0]?.message?.content ?? '';
85
+ return parseVisionVerdict(content);
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }
91
+ /** One-line advisory summary for reports/evidence. */
92
+ export function visionSummary(verdict) {
93
+ if (!verdict)
94
+ return null;
95
+ const findings = verdict.findings.length > 0 ? ` — ${verdict.findings.slice(0, 3).join('; ')}` : '';
96
+ return `vision review: ${verdict.score.toFixed(1)}/10${findings}`;
97
+ }
98
+ //# sourceMappingURL=vision-judge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision-judge.js","sourceRoot":"","sources":["../../src/delivery/vision-judge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
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
+ /**
76
+ * Project-declared visual targets (P8): `.uap/visual-targets.json` raises the
77
+ * gate's thresholds so aesthetic requirements become in-loop convergence
78
+ * pressure instead of a post-hoc opinion. All fields optional; per-page
79
+ * overrides win over file-level values, which win over the built-in floors.
80
+ * Shape: { minDistinctColors, maxDominantRatio, minMotionRatio,
81
+ * pages: { "<file>.html": { ...same fields } } }
82
+ */
83
+ export interface VisualTargets {
84
+ minDistinctColors?: number;
85
+ maxDominantRatio?: number;
86
+ minMotionRatio?: number;
87
+ pages?: Record<string, {
88
+ minDistinctColors?: number;
89
+ maxDominantRatio?: number;
90
+ minMotionRatio?: number;
91
+ }>;
92
+ }
93
+ export declare function readVisualTargets(projectRoot: string): VisualTargets;
94
+ /** Root-level entry pages: index.html first, then other .html files. */
95
+ export declare function discoverEntryPages(projectRoot: string): string[];
96
+ /** Fraction of grid cells that differ between two samples. */
97
+ export declare function motionBetween(a: string[] | undefined, b: string[] | undefined): number;
98
+ /** Pure verdict for one page from its observations — unit-testable. Optional
99
+ * thresholds (project visual targets) tighten the built-in floors. */
100
+ export declare function judgePage(report: Omit<PageVisualReport, 'problems'>, targets?: {
101
+ minDistinctColors?: number;
102
+ maxDominantRatio?: number;
103
+ minMotionRatio?: number;
104
+ }): string[];
105
+ /**
106
+ * Run the visual gate over the project's entry pages. Fail-open (skipped=true)
107
+ * only when no browser can launch.
108
+ */
109
+ export declare function runVisualGate(projectRoot: string, options?: VisualGateOptions): Promise<VisualVerdict>;
110
+ /** One-line summary for acceptance-judge evidence (runtimeNote). */
111
+ export declare function visualRuntimeNote(verdict: VisualVerdict): string;
112
+ //# 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;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5G;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CASpE;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;sEACsE;AACtE,wBAAgB,SAAS,CACvB,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAC1C,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/F,MAAM,EAAE,CA2BV;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAmIxB;AAUD,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAOhE"}
@@ -0,0 +1,292 @@
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
+ export function readVisualTargets(projectRoot) {
29
+ try {
30
+ const path = join(projectRoot, '.uap', 'visual-targets.json');
31
+ if (!existsSync(path))
32
+ return {};
33
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'));
34
+ return parsed && typeof parsed === 'object' ? parsed : {};
35
+ }
36
+ catch {
37
+ return {};
38
+ }
39
+ }
40
+ const GRID = 24;
41
+ const DEFAULT_SAMPLES = 3;
42
+ const DEFAULT_INTERVAL_MS = 900;
43
+ const DEFAULT_TIMEOUT_MS = 30_000;
44
+ const MAX_PAGES = 6;
45
+ /** A canvas showing fewer distinct colors than this is a blank/failed render. */
46
+ const MIN_DISTINCT_COLORS = 3;
47
+ /** One color covering more of the grid than this is a blank-ish frame. */
48
+ const MAX_DOMINANT_RATIO = 0.98;
49
+ /** rAF pages must move at least this fraction of grid cells across samples. */
50
+ const MIN_MOTION_RATIO = 0.02;
51
+ /** In-page probe: sample the largest canvas on a GRID×GRID grid. Returns JSON.
52
+ * NOTE: a function EXPRESSION (not self-invoked) — WebBrowser.evaluate wraps
53
+ * string scripts as `return (<script>)()`, supplying the invocation itself. */
54
+ const PIXEL_PROBE = `(function () {
55
+ var canvases = Array.prototype.slice.call(document.querySelectorAll('canvas'));
56
+ if (canvases.length === 0) return JSON.stringify({ canvas: false });
57
+ canvases.sort(function (a, b) { return b.width * b.height - a.width * a.height; });
58
+ var c = canvases[0];
59
+ var ctx = c.getContext('2d');
60
+ if (!ctx || !c.width || !c.height) return JSON.stringify({ canvas: true, readable: false });
61
+ var img;
62
+ try { img = ctx.getImageData(0, 0, c.width, c.height).data; }
63
+ catch (e) { return JSON.stringify({ canvas: true, readable: false }); }
64
+ var N = ${GRID}, colors = {}, cells = [];
65
+ for (var gy = 0; gy < N; gy++) {
66
+ for (var gx = 0; gx < N; gx++) {
67
+ var x = Math.floor((gx + 0.5) * c.width / N);
68
+ var y = Math.floor((gy + 0.5) * c.height / N);
69
+ var i = (y * c.width + x) * 4;
70
+ var key = (img[i] >> 4) + ',' + (img[i + 1] >> 4) + ',' + (img[i + 2] >> 4);
71
+ colors[key] = (colors[key] || 0) + 1;
72
+ cells.push(key);
73
+ }
74
+ }
75
+ var dominant = 0;
76
+ for (var k in colors) if (colors[k] > dominant) dominant = colors[k];
77
+ return JSON.stringify({
78
+ canvas: true, readable: true, cells: cells,
79
+ distinctColors: Object.keys(colors).length,
80
+ dominantRatio: dominant / cells.length,
81
+ });
82
+ })`;
83
+ function delay(ms) {
84
+ return new Promise((r) => setTimeout(r, ms));
85
+ }
86
+ /** Root-level entry pages: index.html first, then other .html files. */
87
+ export function discoverEntryPages(projectRoot) {
88
+ try {
89
+ const all = readdirSync(projectRoot).filter((f) => f.toLowerCase().endsWith('.html'));
90
+ all.sort((a, b) => (a === 'index.html' ? -1 : b === 'index.html' ? 1 : a.localeCompare(b)));
91
+ return all.slice(0, MAX_PAGES);
92
+ }
93
+ catch {
94
+ return [];
95
+ }
96
+ }
97
+ async function loadRealBrowser() {
98
+ const mod = await import('../browser/web-browser.js');
99
+ return new mod.WebBrowser();
100
+ }
101
+ /** Fraction of grid cells that differ between two samples. */
102
+ export function motionBetween(a, b) {
103
+ if (!a || !b || a.length === 0 || a.length !== b.length)
104
+ return 0;
105
+ let changed = 0;
106
+ for (let i = 0; i < a.length; i++)
107
+ if (a[i] !== b[i])
108
+ changed++;
109
+ return changed / a.length;
110
+ }
111
+ /** Pure verdict for one page from its observations — unit-testable. Optional
112
+ * thresholds (project visual targets) tighten the built-in floors. */
113
+ export function judgePage(report, targets = {}) {
114
+ const minColors = Math.max(MIN_DISTINCT_COLORS, targets.minDistinctColors ?? 0);
115
+ const maxDominant = Math.min(MAX_DOMINANT_RATIO, targets.maxDominantRatio ?? 1);
116
+ const minMotion = Math.max(MIN_MOTION_RATIO, targets.minMotionRatio ?? 0);
117
+ const problems = [];
118
+ if (!report.loaded) {
119
+ problems.push('page did not load');
120
+ return problems;
121
+ }
122
+ if (report.runtimeErrors.length > 0) {
123
+ problems.push(`uncaught runtime error(s) during observation: ${report.runtimeErrors[0].slice(0, 200)}`);
124
+ }
125
+ if (report.hasCanvas) {
126
+ if (report.distinctColors < minColors || report.dominantRatio > maxDominant) {
127
+ problems.push(`canvas renders below the visual floor (${report.distinctColors} distinct colors < ${minColors} required, dominant color covers ${Math.round(report.dominantRatio * 100)}%)`);
128
+ }
129
+ if (report.expectsAnimation && report.motionRatio < minMotion) {
130
+ problems.push(`page uses requestAnimationFrame but motion is ${(report.motionRatio * 100).toFixed(1)}% (< ${(minMotion * 100).toFixed(1)}% required) — the scene is not animating enough`);
131
+ }
132
+ }
133
+ else if (report.expectsAnimation) {
134
+ problems.push('page source expects a canvas animation but no canvas was found in the DOM');
135
+ }
136
+ return problems;
137
+ }
138
+ /**
139
+ * Run the visual gate over the project's entry pages. Fail-open (skipped=true)
140
+ * only when no browser can launch.
141
+ */
142
+ export async function runVisualGate(projectRoot, options = {}) {
143
+ const files = options.files ?? discoverEntryPages(projectRoot);
144
+ if (files.length === 0) {
145
+ return { passed: true, skipped: true, feedback: 'visual gate: no entry .html pages found', pages: [], screenshotDir: null };
146
+ }
147
+ const samples = Math.max(2, options.samples ?? DEFAULT_SAMPLES);
148
+ const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
149
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
150
+ const visualTargets = readVisualTargets(projectRoot);
151
+ const screenshotDir = join(projectRoot, '.uap', 'visual');
152
+ try {
153
+ mkdirSync(screenshotDir, { recursive: true });
154
+ }
155
+ catch {
156
+ // screenshots become best-effort
157
+ }
158
+ let server = null;
159
+ const pages = [];
160
+ try {
161
+ server = await startStaticServer(projectRoot);
162
+ for (const file of files) {
163
+ let browser = null;
164
+ try {
165
+ browser = options.browserFactory ? options.browserFactory() : await loadRealBrowser();
166
+ await browser.launch({ headless: true });
167
+ }
168
+ catch (e) {
169
+ try {
170
+ await browser?.close();
171
+ }
172
+ catch {
173
+ /* ignore */
174
+ }
175
+ return {
176
+ passed: true,
177
+ skipped: true,
178
+ feedback: `visual gate skipped: browser unavailable (${String(e).slice(0, 120)})`,
179
+ pages,
180
+ screenshotDir: null,
181
+ };
182
+ }
183
+ const start = Date.now();
184
+ const src = safeRead(join(projectRoot, file));
185
+ const expectsAnimation = /requestAnimationFrame/.test(src);
186
+ const shots = [];
187
+ let loaded = false;
188
+ let probes = [];
189
+ try {
190
+ // startStaticServer's url includes its own entry path (/index.html);
191
+ // navigate per page from the ORIGIN.
192
+ const origin = new URL(server.url).origin;
193
+ const status = await Promise.race([
194
+ browser.goto(`${origin}/${file}`),
195
+ delay(timeoutMs).then(() => 'timeout'),
196
+ ]);
197
+ loaded = /^2\d\d$/.test(String(status)) || String(status) === '304';
198
+ await Promise.race([browser.waitForLoadState('load'), delay(5000)]).catch(() => undefined);
199
+ if (loaded) {
200
+ for (let i = 0; i < samples && Date.now() - start < timeoutMs; i++) {
201
+ if (i > 0)
202
+ await delay(intervalMs);
203
+ try {
204
+ const raw = await browser.evaluate(PIXEL_PROBE);
205
+ probes.push(JSON.parse(raw));
206
+ }
207
+ catch {
208
+ probes.push({ canvas: false });
209
+ }
210
+ const shot = join(screenshotDir, `${file.replace(/\.html$/i, '')}-t${i}.png`);
211
+ try {
212
+ await browser.screenshot(shot);
213
+ shots.push(shot);
214
+ }
215
+ catch {
216
+ // screenshots are best-effort evidence
217
+ }
218
+ }
219
+ }
220
+ }
221
+ catch (e) {
222
+ probes = [];
223
+ loaded = false;
224
+ }
225
+ const errors = browser
226
+ .getErrors()
227
+ .filter((e) => e.kind === 'pageerror')
228
+ .map((e) => e.message);
229
+ await browser.close().catch(() => undefined);
230
+ const last = probes[probes.length - 1] ?? { canvas: false };
231
+ const first = probes.find((p) => p.readable);
232
+ const base = {
233
+ file,
234
+ loaded,
235
+ hasCanvas: Boolean(last.canvas),
236
+ distinctColors: last.distinctColors ?? 0,
237
+ dominantRatio: last.dominantRatio ?? 1,
238
+ motionRatio: motionBetween(first?.cells, last.cells),
239
+ expectsAnimation,
240
+ runtimeErrors: errors,
241
+ screenshots: shots,
242
+ };
243
+ const pageTargets = { ...visualTargets, ...(visualTargets.pages?.[file] ?? {}) };
244
+ pages.push({ ...base, problems: judgePage(base, pageTargets) });
245
+ }
246
+ }
247
+ catch (e) {
248
+ return {
249
+ passed: true,
250
+ skipped: true,
251
+ feedback: `visual gate skipped: ${String(e).slice(0, 160)}`,
252
+ pages,
253
+ screenshotDir: null,
254
+ };
255
+ }
256
+ finally {
257
+ server?.close();
258
+ }
259
+ const failing = pages.filter((p) => p.problems.length > 0);
260
+ const passed = failing.length === 0;
261
+ const lines = [];
262
+ for (const p of pages) {
263
+ const stat = p.problems.length === 0
264
+ ? `OK (motion ${(p.motionRatio * 100).toFixed(1)}%, ${p.distinctColors} colors)`
265
+ : p.problems.join('; ');
266
+ lines.push(`- ${p.file}: ${stat}`);
267
+ }
268
+ if (!passed) {
269
+ lines.unshift('VISUAL/BEHAVIORAL PROBLEMS — the rendered output is wrong even though the code loads:');
270
+ }
271
+ else {
272
+ lines.unshift(`visual gate: ${pages.length} page(s) render, animate, and run clean`);
273
+ }
274
+ lines.push(`screenshots: ${screenshotDir} (review for design/aesthetic quality)`);
275
+ return { passed, skipped: false, feedback: lines.join('\n'), pages, screenshotDir };
276
+ }
277
+ function safeRead(path) {
278
+ try {
279
+ return existsSync(path) ? readFileSync(path, 'utf-8') : '';
280
+ }
281
+ catch {
282
+ return '';
283
+ }
284
+ }
285
+ /** One-line summary for acceptance-judge evidence (runtimeNote). */
286
+ export function visualRuntimeNote(verdict) {
287
+ if (verdict.skipped)
288
+ return '';
289
+ const parts = verdict.pages.map((p) => `${p.file}: ${p.problems.length === 0 ? 'renders+animates OK' : p.problems.join('; ')} (motion ${(p.motionRatio * 100).toFixed(1)}%)`);
290
+ return `Visual observation of the RUNNING artifact: ${parts.join(' | ')}`;
291
+ }
292
+ //# sourceMappingURL=visual-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-gate.js","sourceRoot":"","sources":["../../src/delivery/visual-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAoExD,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAC9D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAkB,CAAC;QACxE,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,EAAE,CAAC;AAChB,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,SAAS,GAAG,CAAC,CAAC;AACpB,iFAAiF;AACjF,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,0EAA0E;AAC1E,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,+EAA+E;AAC/E,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B;;+EAE+E;AAC/E,MAAM,WAAW,GAAG;;;;;;;;;;YAUR,IAAI;;;;;;;;;;;;;;;;;;GAkBb,CAAC;AAUJ,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACtF,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5F,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe;IAC5B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACtD,OAAO,IAAI,GAAG,CAAC,UAAU,EAAoC,CAAC;AAChE,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,CAAuB,EAAE,CAAuB;IAC5E,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IAClE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;IAChE,OAAO,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;AAC5B,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,SAAS,CACvB,MAA0C,EAC1C,UAA8F,EAAE;IAEhG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,OAAO,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC;IAChF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACnC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,CAAC,iDAAiD,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,IAAI,MAAM,CAAC,cAAc,GAAG,SAAS,IAAI,MAAM,CAAC,aAAa,GAAG,WAAW,EAAE,CAAC;YAC5E,QAAQ,CAAC,IAAI,CACX,0CAA0C,MAAM,CAAC,cAAc,sBAAsB,SAAS,oCAAoC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,GAAG,GAAG,CAAC,IAAI,CAC7K,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,WAAW,GAAG,SAAS,EAAE,CAAC;YAC9D,QAAQ,CAAC,IAAI,CACX,iDAAiD,CAAC,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iDAAiD,CAC5K,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAmB,EACnB,UAA6B,EAAE;IAE/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,yCAAyC,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC9H,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAC7D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAE1D,MAAM,aAAa,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;IACnC,CAAC;IAED,IAAI,MAAM,GAA8C,IAAI,CAAC;IAC7D,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;QAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,GAA+B,IAAI,CAAC;YAC/C,IAAI,CAAC;gBACH,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC;gBACtF,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC;oBACH,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,YAAY;gBACd,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,IAAI;oBACZ,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,6CAA6C,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;oBACjF,KAAK;oBACL,aAAa,EAAE,IAAI;iBACpB,CAAC;YACJ,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;YAC9C,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,MAAM,GAAG,KAAK,CAAC;YACnB,IAAI,MAAM,GAAkB,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,qEAAqE;gBACrE,qCAAqC;gBACrC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;gBAC1C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;oBAChC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;oBACjC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;iBACvC,CAAC,CAAC;gBACH,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC;gBACpE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAE3F,IAAI,MAAM,EAAE,CAAC;oBACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;wBACnE,IAAI,CAAC,GAAG,CAAC;4BAAE,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC;wBACnC,IAAI,CAAC;4BACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAS,WAAW,CAAC,CAAC;4BACxD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC,CAAC;wBAC9C,CAAC;wBAAC,MAAM,CAAC;4BACP,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;wBACjC,CAAC;wBACD,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBAC9E,IAAI,CAAC;4BACH,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;4BAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBACnB,CAAC;wBAAC,MAAM,CAAC;4BACP,uCAAuC;wBACzC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,GAAG,EAAE,CAAC;gBACZ,MAAM,GAAG,KAAK,CAAC;YACjB,CAAC;YACD,MAAM,MAAM,GAAG,OAAO;iBACnB,SAAS,EAAE;iBACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;iBACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAE7C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAuC;gBAC/C,IAAI;gBACJ,MAAM;gBACN,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC/B,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,CAAC;gBACxC,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,CAAC;gBACtC,WAAW,EAAE,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;gBACpD,gBAAgB;gBAChB,aAAa,EAAE,MAAM;gBACrB,WAAW,EAAE,KAAK;aACnB,CAAC;YACF,MAAM,WAAW,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACjF,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,wBAAwB,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YAC3D,KAAK;YACL,aAAa,EAAE,IAAI;SACpB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;IACpC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAClC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc,UAAU;YAChF,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,KAAK,CAAC,OAAO,CAAC,uFAAuF,CAAC,CAAC;IACzG,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,OAAO,CAAC,gBAAgB,KAAK,CAAC,MAAM,yCAAyC,CAAC,CAAC;IACvF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,aAAa,wCAAwC,CAAC,CAAC;IAClF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AACtF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAC7B,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACxI,CAAC;IACF,OAAO,+CAA+C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;AAC5E,CAAC"}
@@ -29,6 +29,7 @@ export declare class OpenAICompatClient implements ModelClient {
29
29
  maxTokens?: number;
30
30
  timeout?: number;
31
31
  temperature?: number;
32
+ jsonResponse?: boolean;
32
33
  }): Promise<{
33
34
  content: string;
34
35
  tokensUsed: {
@@ -1 +1 @@
1
- {"version":3,"file":"openai-compat-client.d.ts","sourceRoot":"","sources":["../../src/models/openai-compat-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,yBAAyB;IACxC,oHAAoH;IACpH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwBD,qBAAa,kBAAmB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,GAAE,yBAA8B;IAQnD;;;;;;OAMG;IACG,QAAQ,CACZ,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;YAgBnF,QAAQ;CAwEvB"}
1
+ {"version":3,"file":"openai-compat-client.d.ts","sourceRoot":"","sources":["../../src/models/openai-compat-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,yBAAyB;IACxC,oHAAoH;IACpH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwBD,qBAAa,kBAAmB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,GAAE,yBAA8B;IAQnD;;;;;;OAMG;IACG,QAAQ,CACZ,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAC/F,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;YAgBnF,QAAQ;CA4EvB"}
@@ -66,6 +66,10 @@ export class OpenAICompatClient {
66
66
  headers: {
67
67
  'Content-Type': 'application/json',
68
68
  ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
69
+ // Evaluator verdicts: the UAP proxy grammar-constrains this
70
+ // completion to a bare JSON value (no <think> preamble), so judge/
71
+ // critic/ideation parses are deterministic. Ignored by other servers.
72
+ ...(options?.jsonResponse ? { 'x-uap-json-response': '1' } : {}),
69
73
  },
70
74
  body: JSON.stringify({
71
75
  model: model.apiModel,
@@ -1 +1 @@
1
- {"version":3,"file":"openai-compat-client.js","sourceRoot":"","sources":["../../src/models/openai-compat-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openai-compat-client.js","sourceRoot":"","sources":["../../src/models/openai-compat-client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.96.6",
3
+ "version": "1.98.0",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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".