yam-flow 0.1.4 → 0.1.6

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/src/bin/yam.ts CHANGED
@@ -14,8 +14,10 @@ import {
14
14
  buildMissionPatchEnvelope,
15
15
  buildRollbackHint,
16
16
  buildRuntimeBackendEvidence,
17
+ buildUeyeDesignCompletionGate,
17
18
  buildUeyeVisualProvenance,
18
19
  buildUeyeRunReport,
20
+ buildUeyeSurfaceContext,
19
21
  buildYamCompletionProof,
20
22
  detectDbSafetyText as detectTrustDbSafetyText,
21
23
  isTruthStatus
@@ -139,7 +141,7 @@ Usage:
139
141
  yam proof write [dir] [--format json|md] [--out file] [--route route] [--truth status] [--command text]
140
142
  yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
141
143
  yam ueye compare --reference ref.png --actual screenshot.png [--json]
142
- yam ueye report [--reference ref.png] [--actual screenshot.png] [--json]
144
+ yam ueye report [--reference ref.png] [--actual screenshot.png] [--provider-context local] [--execution-surface in-app-browser] [--json]
143
145
  yam media proof [--requested] [--attempted] [--output file] [--json]
144
146
  yam runtime evidence [--backend terminal|in-app-browser|playwright|tmux|zellij] [--claim observed|started|stopped|cleanup-verified] [--json]
145
147
  yam mission queue [--agent-id id] [--scope text] [--changed file] [--verification-hint text] [--json]
@@ -808,7 +810,7 @@ function toolsDoctorNextActionDetails({ pack, rows, riskNotes, frameworkChecklis
808
810
  if (rows.some((row) => row.name === 'Yam skills' && row.status !== 'ready')) actions.push(nextActionDetail('install-skills', 'warning', 'skill install state is incomplete', 'run `yam install` and restart Codex before relying on installed skills', 'yam install'));
809
811
  if (riskNotes.some((note) => note.level === 'danger')) actions.push(nextActionDetail('deep-safety', 'error', 'destructive database or production write signal detected', 'use $deep before claiming destructive database or production write safety', 'yam safety "<command or SQL>"'));
810
812
  if (frameworkChecklist?.detected && !commands?.build && !commands?.typecheck) actions.push(nextActionDetail('verification-command', 'warning', 'build/typecheck command not detected', 'add or document a small build/typecheck command for implementation verification', 'yam pack .'));
811
- if (frameworkChecklist?.uiLike) actions.push(nextActionDetail('ueye-evidence', 'info', 'UI-like project detected', 'for Ueye verified claims, record reference, actual screenshot, and comparison result', 'yam ueye report --reference ref.png --actual shot.png --json'));
813
+ if (frameworkChecklist?.uiLike) actions.push(nextActionDetail('ueye-evidence', 'info', 'UI-like project detected', 'for Ueye verified claims, record reference, actual screenshot, comparison result, and surface context', 'yam ueye report --reference ref.png --actual shot.png --provider-context local --execution-surface in-app-browser --json'));
812
814
  return uniqueNextActionDetails(actions);
813
815
  }
814
816
 
@@ -1348,18 +1350,18 @@ Opt-in visual evidence helpers. Ueye stays one skill: fast by default, capture/c
1348
1350
  Usage:
1349
1351
  yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
1350
1352
  yam ueye compare --reference ref.png --actual screenshot.png [--json]
1351
- yam ueye report [--reference ref.png] [--actual screenshot.png] [--review-session-id id] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
1353
+ yam ueye report [--reference ref.png] [--actual screenshot.png] [--review-session-id id] [--provider-context local] [--execution-surface in-app-browser] [--app-surface codex-app] [--browser-surface in-app-browser] [--control-mode manual|automated] [--preserved-state] [--preserved-url URL] [--completion-claim draft|needs-polish|done] [--strict] [--design-score n] [--p0 text] [--p1 text] [--states-checked] [--mobile-checked] [--contrast-checked] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
1352
1354
 
1353
1355
  Notes:
1354
1356
  capture uses a locally available Playwright install when present. It does not download browsers or install dependencies.
1355
1357
  compare uses local files only and reports sha256, dimensions, comparison_result, and proof-ready visual provenance.
1356
- report produces a proof-ready Ueye visual run report and continuity/comparison record without requiring a new capture.
1358
+ report produces a proof-ready Ueye visual run report, design completion gate, and continuity/comparison record without requiring a new capture.
1357
1359
  `);
1358
1360
  }
1359
1361
 
1360
1362
  async function ueyeCapture(args = []) {
1361
1363
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') return ueyeUsage();
1362
- const flags = parseSimpleFlags(args, new Set(['url', 'out', 'viewport', 'wait-until', 'timeout', 'full-page', 'json']));
1364
+ const flags = parseSimpleFlags(args, new Set(['url', 'out', 'viewport', 'wait-until', 'timeout', 'full-page', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'evidence-id', 'screenshot-id', 'json']));
1363
1365
  const url = String(flags.url || '');
1364
1366
  const out = String(flags.out || '');
1365
1367
  if (!url || !out) {
@@ -1384,6 +1386,24 @@ async function ueyeCapture(args = []) {
1384
1386
  await page.goto(url, { waitUntil, timeout });
1385
1387
  await page.screenshot({ path: target, fullPage: Boolean(flags.full_page) });
1386
1388
  const info = await imageFileInfo(target);
1389
+ const surfaceContext = buildUeyeSurfaceContext({
1390
+ provider_context: String(flags.provider_context || 'local-playwright'),
1391
+ provider_badge: String(flags.provider_badge || flags.provider_context || 'local-playwright'),
1392
+ execution_surface: String(flags.execution_surface || 'browser-capture'),
1393
+ app_surface: String(flags.app_surface || 'local-project'),
1394
+ browser_surface: String(flags.browser_surface || 'playwright'),
1395
+ control_mode: String(flags.control_mode || 'automated-capture'),
1396
+ route: 'ueye',
1397
+ mode: 'capture',
1398
+ url,
1399
+ viewport: `${viewport.width}x${viewport.height}`,
1400
+ screenshot_id: String(flags.screenshot_id || path.basename(target)),
1401
+ evidence_id: String(flags.evidence_id || `ueye-capture-${timestampId()}`),
1402
+ preserved_state: Boolean(flags.preserved_state),
1403
+ preserved_url: String(flags.preserved_url || url),
1404
+ local_only: true,
1405
+ truth_status: 'verified'
1406
+ });
1387
1407
  const result = {
1388
1408
  schema: 'yam.ueye-capture.v1',
1389
1409
  status: 'verified',
@@ -1393,6 +1413,7 @@ async function ueyeCapture(args = []) {
1393
1413
  full_page: Boolean(flags.full_page),
1394
1414
  sha256: info.sha256,
1395
1415
  dimensions: info.dimensions,
1416
+ surface_context: surfaceContext,
1396
1417
  visual_evidence: `browser screenshot captured: ${target} (${info.dimensions}, sha256:${info.sha256})`
1397
1418
  };
1398
1419
  printJsonOrHuman(result, Boolean(flags.json), 'Ueye capture');
@@ -1415,7 +1436,7 @@ async function ueyeCapture(args = []) {
1415
1436
 
1416
1437
  async function ueyeCompare(args = []) {
1417
1438
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') return ueyeUsage();
1418
- const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'json', 'reference-id', 'screenshot-id']));
1439
+ const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'json', 'reference-id', 'screenshot-id', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'viewport', 'evidence-id']));
1419
1440
  const reference = String(flags.reference || flags.ref || '');
1420
1441
  const actual = String(flags.actual || flags.screenshot || '');
1421
1442
  if (!reference || !actual) {
@@ -1436,12 +1457,35 @@ async function ueyeCompare(args = []) {
1436
1457
  const sameDimensions = referenceInfo.dimensions === actualInfo.dimensions;
1437
1458
  const comparisonResult = exactMatch ? 'matched' : 'different';
1438
1459
  const truthStatus = exactMatch ? 'verified' : 'partial';
1460
+ const surfaceContext = buildUeyeSurfaceContext({
1461
+ provider_context: String(flags.provider_context || 'local-file'),
1462
+ provider_badge: String(flags.provider_badge || flags.provider_context || 'local-file'),
1463
+ execution_surface: String(flags.execution_surface || 'local-file-compare'),
1464
+ app_surface: String(flags.app_surface || 'local-project'),
1465
+ browser_surface: String(flags.browser_surface || 'not-used'),
1466
+ control_mode: String(flags.control_mode || 'local-compare'),
1467
+ route: 'ueye',
1468
+ mode: 'compare',
1469
+ url: String(flags.url || ''),
1470
+ viewport: String(flags.viewport || ''),
1471
+ screenshot_id: String(flags.screenshot_id || path.basename(actualPath)),
1472
+ evidence_id: String(flags.evidence_id || `ueye-compare-${timestampId()}`),
1473
+ preserved_state: Boolean(flags.preserved_state),
1474
+ preserved_url: String(flags.preserved_url || flags.url || ''),
1475
+ local_only: true,
1476
+ truth_status: truthStatus
1477
+ });
1439
1478
  const provenance = buildUeyeVisualProvenance({
1440
1479
  source_kind: 'implementation_screenshot',
1441
1480
  source_path: actualPath,
1442
1481
  source_hash: actualInfo.sha256,
1443
1482
  reference_id: String(flags.reference_id || path.basename(referencePath)),
1444
1483
  screenshot_id: String(flags.screenshot_id || path.basename(actualPath)),
1484
+ provider_context: surfaceContext.provider_context,
1485
+ provider_badge: surfaceContext.provider_badge,
1486
+ execution_surface: surfaceContext.execution_surface,
1487
+ app_surface: surfaceContext.app_surface,
1488
+ browser_surface: surfaceContext.browser_surface,
1445
1489
  local_only: true,
1446
1490
  redacted: false,
1447
1491
  operator_provided: false,
@@ -1456,6 +1500,7 @@ async function ueyeCompare(args = []) {
1456
1500
  same_dimensions: sameDimensions,
1457
1501
  reference: referenceInfo,
1458
1502
  actual: actualInfo,
1503
+ surface_context: surfaceContext,
1459
1504
  visual_evidence: `browser/local screenshot comparison executed: reference=${referencePath}, actual=${actualPath}, result=${comparisonResult}`,
1460
1505
  visual_provenance: provenance,
1461
1506
  proof_hint: `yam proof --route ueye --truth ${truthStatus} --visual "browser/local screenshot comparison executed: ${comparisonResult}" --visual-provenance '${JSON.stringify(provenance)}' --require-visual`
@@ -1476,7 +1521,7 @@ async function ueyeCompare(args = []) {
1476
1521
 
1477
1522
  async function ueyeReport(args = []) {
1478
1523
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') return ueyeUsage();
1479
- const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'json']));
1524
+ const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'evidence-id', 'completion-claim', 'completion-status', 'gate-mode', 'strict', 'design-score', 'min-design-score', 'p0', 'p1', 'open-p0', 'open-p1', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'comparison-result', 'json']));
1480
1525
  const reference = String(flags.reference || flags.ref || '');
1481
1526
  const actual = String(flags.actual || flags.screenshot || '');
1482
1527
  const referenceSources = [];
@@ -1485,6 +1530,24 @@ async function ueyeReport(args = []) {
1485
1530
  let blockedReason = String(flags.blocked_reason || '');
1486
1531
  const reviewSessionId = String(flags.review_session_id || `ueye-${timestampId()}`);
1487
1532
  const previousReport = await readPreviousUeyeReport(flags.previous_report);
1533
+ const surfaceContext = buildUeyeSurfaceContext({
1534
+ provider_context: String(flags.provider_context || 'not-recorded'),
1535
+ provider_badge: String(flags.provider_badge || flags.provider_context || 'not-recorded'),
1536
+ execution_surface: String(flags.execution_surface || flags.capture_backend || 'not-recorded'),
1537
+ app_surface: String(flags.app_surface || 'not-recorded'),
1538
+ browser_surface: String(flags.browser_surface || flags.capture_backend || 'not-recorded'),
1539
+ control_mode: String(flags.control_mode || 'not-recorded'),
1540
+ route: 'ueye',
1541
+ mode: 'report',
1542
+ url: String(flags.url || flags.preserved_url || ''),
1543
+ viewport: String(flags.viewport || ''),
1544
+ screenshot_id: String(flags.current_screenshot_id || flags.screenshot_id || ''),
1545
+ evidence_id: String(flags.evidence_id || reviewSessionId),
1546
+ preserved_state: Boolean(flags.preserved_state),
1547
+ preserved_url: String(flags.preserved_url || flags.url || ''),
1548
+ local_only: true,
1549
+ truth_status: actual ? 'partial' : 'assumed'
1550
+ });
1488
1551
 
1489
1552
  try {
1490
1553
  if (reference) {
@@ -1494,6 +1557,11 @@ async function ueyeReport(args = []) {
1494
1557
  source_path: info.path,
1495
1558
  source_hash: info.sha256,
1496
1559
  reference_id: String(flags.reference_id || path.basename(info.path)),
1560
+ provider_context: surfaceContext.provider_context,
1561
+ provider_badge: surfaceContext.provider_badge,
1562
+ execution_surface: surfaceContext.execution_surface,
1563
+ app_surface: surfaceContext.app_surface,
1564
+ browser_surface: surfaceContext.browser_surface,
1497
1565
  local_only: true,
1498
1566
  operator_provided: true,
1499
1567
  comparison_result: 'reference-recorded',
@@ -1508,13 +1576,20 @@ async function ueyeReport(args = []) {
1508
1576
  source_hash: info.sha256,
1509
1577
  reference_id: String(flags.reference_id || referenceSources[0]?.reference_id || ''),
1510
1578
  screenshot_id: String(flags.current_screenshot_id || flags.screenshot_id || path.basename(info.path)),
1579
+ provider_context: surfaceContext.provider_context,
1580
+ provider_badge: surfaceContext.provider_badge,
1581
+ execution_surface: surfaceContext.execution_surface,
1582
+ app_surface: surfaceContext.app_surface,
1583
+ browser_surface: surfaceContext.browser_surface,
1511
1584
  local_only: true,
1512
1585
  operator_provided: false,
1513
1586
  comparison_result: 'implementation-recorded',
1514
1587
  truth_status: 'partial'
1515
1588
  }));
1516
1589
  }
1517
- if (reference && actual && referenceSources[0]?.source_hash === implementationSources[0]?.source_hash) {
1590
+ if (flags.comparison_result) {
1591
+ comparisonResult = normalizeUeyeComparisonResult(flags.comparison_result);
1592
+ } else if (reference && actual && referenceSources[0]?.source_hash === implementationSources[0]?.source_hash) {
1518
1593
  comparisonResult = 'matched';
1519
1594
  } else if (reference && actual) {
1520
1595
  comparisonResult = 'different';
@@ -1526,8 +1601,29 @@ async function ueyeReport(args = []) {
1526
1601
  const report = buildUeyeRunReport({
1527
1602
  reference_sources: referenceSources,
1528
1603
  implementation_sources: implementationSources,
1604
+ surface_context: {
1605
+ ...surfaceContext,
1606
+ screenshot_id: surfaceContext.screenshot_id || String(flags.current_screenshot_id || flags.screenshot_id || implementationSources[0]?.screenshot_id || ''),
1607
+ truth_status: blockedReason ? 'blocked' : implementationSources.length ? 'partial' : 'assumed'
1608
+ },
1529
1609
  comparison_result: comparisonResult,
1530
1610
  design_quality: String(flags.design_quality || 'not-checked'),
1611
+ design_completion_gate: {
1612
+ mode: flags.strict || flags.gate_mode === 'strict' ? 'strict' : 'fast',
1613
+ completion_claim: flags.completion_claim || flags.completion_status || 'draft',
1614
+ design_score: numberOrNull(flags.design_score),
1615
+ min_design_score: numberOrNull(flags.min_design_score) ?? 8,
1616
+ p0: [...arrayFlag(flags.p0), ...arrayFlag(flags.open_p0)],
1617
+ p1: [...arrayFlag(flags.p1), ...arrayFlag(flags.open_p1)],
1618
+ states_checked: Boolean(flags.states_checked),
1619
+ mobile_checked: Boolean(flags.mobile_checked),
1620
+ responsive_checked: Boolean(flags.responsive_checked),
1621
+ contrast_checked: Boolean(flags.contrast_checked),
1622
+ accessibility_checked: Boolean(flags.accessibility_checked),
1623
+ cta_checked: Boolean(flags.cta_checked),
1624
+ direction_locked: Boolean(flags.direction_locked),
1625
+ reference_read: Boolean(flags.reference_read)
1626
+ },
1531
1627
  blocked_reason: blockedReason,
1532
1628
  next_action: String(flags.next_visual_action || flags.next_action || '')
1533
1629
  });
@@ -1536,6 +1632,8 @@ async function ueyeReport(args = []) {
1536
1632
  previousReport,
1537
1633
  referenceSources,
1538
1634
  implementationSources,
1635
+ surfaceContext: report.surface_context,
1636
+ designCompletionGate: report.design_completion_gate,
1539
1637
  comparisonResult,
1540
1638
  designQuality: String(flags.design_quality || 'not-checked'),
1541
1639
  similar: arrayFlag(flags.similar),
@@ -1593,6 +1691,8 @@ function buildUeyeComparisonReport({
1593
1691
  previousReport,
1594
1692
  referenceSources,
1595
1693
  implementationSources,
1694
+ surfaceContext,
1695
+ designCompletionGate,
1596
1696
  comparisonResult,
1597
1697
  designQuality,
1598
1698
  similar,
@@ -1633,6 +1733,8 @@ function buildUeyeComparisonReport({
1633
1733
  reference_count: referenceSources.length,
1634
1734
  implementation_count: implementationSources.length
1635
1735
  },
1736
+ surface_context: surfaceContext || buildUeyeSurfaceContext(),
1737
+ design_completion_gate: designCompletionGate || null,
1636
1738
  comparison_result: comparisonResult,
1637
1739
  design_quality: designQuality,
1638
1740
  similar,
@@ -1652,6 +1754,12 @@ function buildUeyeComparisonReport({
1652
1754
  };
1653
1755
  }
1654
1756
 
1757
+ function normalizeUeyeComparisonResult(value = '') {
1758
+ const text = String(value || '').toLowerCase();
1759
+ if (['matched', 'similar', 'different', 'not-verified', 'not-applicable'].includes(text)) return text;
1760
+ return 'not-verified';
1761
+ }
1762
+
1655
1763
  async function media(args = []) {
1656
1764
  const subcommand = args[0] || 'help';
1657
1765
  if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') return mediaUsage();
@@ -1935,7 +2043,7 @@ function parseSimpleFlags(args = [], allowed = new Set<string>()) {
1935
2043
  const key = rawKey.slice(2);
1936
2044
  if (allowed.size && !allowed.has(key)) continue;
1937
2045
  const normalizedKey = key.replace(/-/g, '_');
1938
- if (['json', 'full-page', 'requested', 'attempted', 'available', 'wait-loop', 'cleanup-checked'].includes(key)) {
2046
+ if (['json', 'full-page', 'requested', 'attempted', 'available', 'wait-loop', 'cleanup-checked', 'strict', 'preserved-state', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read'].includes(key)) {
1939
2047
  flags[normalizedKey] = true;
1940
2048
  continue;
1941
2049
  }
@@ -2085,6 +2193,7 @@ async function proof(args = []) {
2085
2193
  printProofList('Mission patch envelope', summary.missionEnvelope || []);
2086
2194
  printProofList('Rollback hint', summary.rollbackHint || []);
2087
2195
  printProofList('Media proof', summary.mediaProof || []);
2196
+ printProofList('Design completion', summary.designCompletion || []);
2088
2197
  printProofList('Changed surfaces', summary.changed);
2089
2198
  printProofList('Skipped', summary.skipped);
2090
2199
  printProofList('Blocked', summary.blocked);
@@ -2180,6 +2289,10 @@ function buildProofSummary(parsed, artifact) {
2180
2289
  ...structuredEvidenceList(artifact.mediaProof),
2181
2290
  ...structuredEvidenceList(parsed.flags.media_proof)
2182
2291
  ],
2292
+ designCompletion: [
2293
+ ...structuredEvidenceList(artifact.designCompletion),
2294
+ ...structuredEvidenceList(parsed.flags.design_completion)
2295
+ ],
2183
2296
  cleanup: parsed.flags.cleanup || artifact.cleanup || '',
2184
2297
  changed: [...artifact.changed, ...arrayFlag(parsed.flags.changed)],
2185
2298
  skipped: [...artifact.skipped, ...arrayFlag(parsed.flags.skipped)],
@@ -2245,6 +2358,9 @@ function renderProofMarkdown(summary) {
2245
2358
  '## Media proof',
2246
2359
  ...renderProofMarkdownList(summary.mediaProof || []),
2247
2360
  '',
2361
+ '## Design completion',
2362
+ ...renderProofMarkdownList(summary.designCompletion || []),
2363
+ '',
2248
2364
  '## Changed surfaces',
2249
2365
  ...renderProofMarkdownList(summary.changed),
2250
2366
  '',
@@ -2277,7 +2393,7 @@ function renderProofMarkdownList(values) {
2277
2393
  function parseProofArgs(args = []) {
2278
2394
  const flags: AnyRecord = {};
2279
2395
  const positionals: string[] = [];
2280
- const aliases = new Set(['goal', 'route', 'truth', 'command', 'evidence', 'visual', 'runtime', 'runtime-backend', 'runtime-claim', 'runtime-evidence-id', 'runtime-command', 'cleanup-checked', 'runtime-note', 'runtime-backend-evidence', 'visual-provenance', 'mission-envelope', 'rollback-hint', 'media-proof', 'cleanup', 'changed', 'skipped', 'blocked', 'assumed', 'assumption', 'unverified', 'from', 'format', 'out', 'file', 'json', 'require-runtime', 'require-real-runtime', 'require-tmux', 'require-visual']);
2396
+ const aliases = new Set(['goal', 'route', 'truth', 'command', 'evidence', 'visual', 'runtime', 'runtime-backend', 'runtime-claim', 'runtime-evidence-id', 'runtime-command', 'cleanup-checked', 'runtime-note', 'runtime-backend-evidence', 'visual-provenance', 'mission-envelope', 'rollback-hint', 'media-proof', 'design-completion', 'cleanup', 'changed', 'skipped', 'blocked', 'assumed', 'assumption', 'unverified', 'from', 'format', 'out', 'file', 'json', 'require-runtime', 'require-real-runtime', 'require-tmux', 'require-visual']);
2281
2397
  for (let index = 0; index < args.length; index += 1) {
2282
2398
  const arg = args[index];
2283
2399
  if (arg.startsWith('--')) {
@@ -2291,7 +2407,7 @@ function parseProofArgs(args = []) {
2291
2407
  }
2292
2408
  const value = inlineValue ?? args[index + 1] ?? '';
2293
2409
  if (inlineValue === undefined) index += 1;
2294
- if (['command', 'evidence', 'visual', 'runtime', 'runtime-backend-evidence', 'visual-provenance', 'mission-envelope', 'rollback-hint', 'media-proof', 'changed', 'skipped', 'blocked', 'assumed', 'assumption', 'unverified'].includes(key)) {
2410
+ if (['command', 'evidence', 'visual', 'runtime', 'runtime-backend-evidence', 'visual-provenance', 'mission-envelope', 'rollback-hint', 'media-proof', 'design-completion', 'changed', 'skipped', 'blocked', 'assumed', 'assumption', 'unverified'].includes(key)) {
2295
2411
  flags[normalizedKey] = [...arrayFlag(flags[normalizedKey]), value];
2296
2412
  } else {
2297
2413
  flags[normalizedKey] = value;
@@ -2334,6 +2450,7 @@ function emptyProofArtifact() {
2334
2450
  missionEnvelope: [],
2335
2451
  rollbackHint: [],
2336
2452
  mediaProof: [],
2453
+ designCompletion: [],
2337
2454
  cleanup: '',
2338
2455
  changed: [],
2339
2456
  skipped: [],
@@ -2361,6 +2478,7 @@ async function parseProofJson(file, empty) {
2361
2478
  missionEnvelope: structuredEvidenceList(data.missionEnvelope || data.mission_envelope),
2362
2479
  rollbackHint: structuredEvidenceList(data.rollbackHint || data.rollback_hint),
2363
2480
  mediaProof: structuredEvidenceList(data.mediaProof || data.media_proof),
2481
+ designCompletion: structuredEvidenceList(data.designCompletion || data.design_completion),
2364
2482
  cleanup: String(data.cleanup || data.cleanupStatus || ''),
2365
2483
  changed: arrayFlag(data.changed || data.files),
2366
2484
  skipped: arrayFlag(data.skipped),
@@ -2391,6 +2509,7 @@ async function parseProofMarkdown(file, empty) {
2391
2509
  missionEnvelope: readProofList(text, 'Mission patch envelope'),
2392
2510
  rollbackHint: readProofList(text, 'Rollback hint'),
2393
2511
  mediaProof: readProofList(text, 'Media proof'),
2512
+ designCompletion: readProofList(text, 'Design completion'),
2394
2513
  cleanup: readProofField(text, 'Cleanup') || readProofField(text, 'Cleanup status'),
2395
2514
  changed: firstProofList(text, ['Changed surfaces', 'Files']),
2396
2515
  skipped: readProofList(text, 'Skipped'),
@@ -2476,6 +2595,9 @@ function formatStructuredEvidence(value) {
2476
2595
  if (data.schema === 'yam.media-generation-proof.v1' || data.generation_requested || data.output_hash) {
2477
2596
  return JSON.stringify(buildMediaGenerationProof(data));
2478
2597
  }
2598
+ if (data.schema === 'yam.ueye-design-completion-gate.v1' || data.completion_claim || data.ready_to_claim_done !== undefined) {
2599
+ return JSON.stringify(buildUeyeDesignCompletionGate(data));
2600
+ }
2479
2601
  return JSON.stringify(data);
2480
2602
  } catch {
2481
2603
  return text;
@@ -2484,7 +2606,7 @@ function formatStructuredEvidence(value) {
2484
2606
 
2485
2607
  function hasProofEvidence(parsed) {
2486
2608
  const flags = parsed.flags || {};
2487
- return ['command', 'evidence', 'visual', 'runtime', 'runtime_backend_evidence', 'visual_provenance', 'mission_envelope', 'rollback_hint', 'media_proof', 'changed', 'skipped', 'blocked'].some((key) => arrayFlag(flags[key]).length > 0) || Boolean(flags.cleanup || flags.runtime_backend || flags.runtime_claim);
2609
+ return ['command', 'evidence', 'visual', 'runtime', 'runtime_backend_evidence', 'visual_provenance', 'mission_envelope', 'rollback_hint', 'media_proof', 'design_completion', 'changed', 'skipped', 'blocked'].some((key) => arrayFlag(flags[key]).length > 0) || Boolean(flags.cleanup || flags.runtime_backend || flags.runtime_claim);
2488
2610
  }
2489
2611
 
2490
2612
  function printProofList(label, values) {