Skip to content

v0.6.0-prerelease — Phase 5: Verification-Gate USP

Pre-release
Pre-release

Choose a tag to compare

@Samuel0101010 Samuel0101010 released this 23 May 08:52

THE Verification-Gate. THE wisp-design differentiator.

No other live-edit tool gates accept on (a11y + screenshot + anti-slop)
simultaneously. UI-UX-Pro-Max stops at "generated text", Impeccable stops
at "wrote to file", Onlook/Stagewise stop at "wrote to file", Huashu has
5-dim radar but no gate, Open-design has 5-dim gate but no source-edit.
wisp-design alone links source-edit + a11y-block + screenshot-diff +
anti-slop-lint in one accept-gate.

Built by a 4-agent team (architect / coder / security / tester) with
disjoint file ownership and security-architect-flagged coordination
between the parallel agents.

Quality-gate metrics (100-component-sample FPR canary)

hard-ban FPR    = 0.00%  (target <= 5%)  PASS
FN-rate         = 0.00%  (caught 30/30 known-slop)
soft-warn FPR   = 45.71% (target <= 20%) PINNED  [AUDIT-PENDING for Phase 6]
verdict         = USP delivered, calibration TODO

Hard-ban FPR being 0.00% on real-world-good components (shadcn/Radix/MUI
patterns) while still catching 100% of known-slop is the central proof
point. The soft-warn FPR is too noisy on Tailwind defaults — security's
audit pointed at the round-number-whitespace rule firing per-occurrence;
fix via file-level aggregation (>0.7 ratio threshold) lands in Phase 6.

What landed

Contracts (src/contracts/verify.ts, 491 lines)

  • VerifyMode enum across 5 modes (stop-hook | live-accept |
    live-with-screenshot | audit | audit-strict)
  • Lookup tables: MODE_CHECK_SETS, MODE_BLOCKS_ON_FAIL,
    MODE_TIMING_BUDGET_MS
  • AntiSlopRuleId (7 hard-bans + 5 soft), HARD_BAN_RULES Set
  • Aggregator helpers, per-check budgets, audit options schema

Verify modules (src/verify/, 8 files)

  • anti-slop-linter.ts (648) - pre-compiled regex set, 7 hard-bans
    (em-dash-ui, gradient-text-headline, default-glassmorphism,
    hero-metric-template, side-stripe-decoration, purple-blue-gradient,
    generic-ai-illustration) + 5 soft-suggestions
  • a11y-axe.ts (381) - axe-core via jsdom or Playwright when available
  • console-scan.ts (221) - 3 modes (session-log, bridge-poll, static)
  • tab-order.ts (232) - focus-trap-leak detection, tabindex audit
  • reduced-motion.ts (112) - CSS regex pass for motion-without-guard
  • multi-viewport.ts (276) - Playwright 4 viewports x {light,dark} = 8 PNGs
  • _sandbox.ts (384, security) - safe-launch with 6 URL guards
    (loopback-only, no userinfo, http(s) only, port 1025-65535) +
    chromium hardening (sandbox ON, disable-extensions, etc.) +
    restricted context (no downloads, no permissions) + route-handler
    aborts non-loopback hosts
  • gate.ts (259) - orchestrator via Promise.allSettled, per-check
    timeout, 5-mode routing, blocked field for audit-strict

CLI (src/agent/audit.ts, 308 lines)

  • wisp-design audit [paths...] with --mode fast|full|strict,
    --format text|json|markdown, --screenshot
  • Exit codes: 0/1/2/3 for pass/strict-block/bad-flag/throw

Stop-Hook (src/hooks/dispatcher.ts)

  • git diff HEAD --name-only via execFileSync (path-injection safe)
  • 50-file cap, UI-extension filter, 15ms tail-reserve
  • Dynamic-import linter (Node module-cache amortises after turn 1)
  • WISP_DESIGN_STRICT=1 env: permissionDecision:block JSON to stdout
  • Default: stderr warn, exit 0 (never blocks user on internal error)

Doctor (12/12 OK)

  • axe-core FAIL when missing, playwright + pixelmatch WARN
  • Doctor surfaces optionalDep absence so users can see it but don't have
    to install. Same path for both optional deps.

Tests (tests/verify/, 155 new tests in 9 files)

  • anti-slop-linter.test.ts (54) - 7 hard-bans + 5 soft-suggestions
    each with KNOWN-BAD + KNOWN-GOOD, plus extractCssFromFile per ext
  • anti-slop-fp-rate.test.ts (7) - 100-component canary
  • a11y-axe.test.ts (12) - contrast, alt-missing, [data-wisp-ui] exclusion
  • console-scan.test.ts (11) - 3-mode coverage + severity routing
  • tab-order.test.ts (12) - focus-trap, tabindex, focus-ring
  • reduced-motion.test.ts (8) - guard coverage + long-transition fail
  • multi-viewport.test.ts (20) - graceful skip + isLoopbackUrl unit tests
    • SandboxError code discrimination
  • gate.test.ts (18) - parallel timing, mode routing, aggregates
  • audit-cli.test.ts (13) - exit codes, formats, flag parsing

Cumulative: 502/502 tests green (155 verify + 77 agent/skills + 99
source + 94 browser + 77 bridge + 2 smoke).

npm deps

  • axe-core ^4.10.0 as regular dependency
  • playwright ^1.49.0 + pixelmatch ^7.1.0 as optionalDependencies
  • @types/pixelmatch as devDep

Open Decision #7 confirmed

warn-default in v0.x, hard-block via audit --mode strict opt-in.
Override-flow via floating-bar with session-log entry.

Phase-5 deferred items (Phase 6+)

  • 4 regex tightenings per security audit:
    • oklch() branch for purple-blue-gradient
    • brace-anchoring for selector windows
    • broader CSS-property scan for default-tailwind-blue (fill/stroke)
    • file-level aggregation for round-number-whitespace
  • Multi-viewport baseline-comparison + visual regression
  • reduced-motion pixelmatch-based two-render diff
  • Soft-warn FPR drop from 45.71% to <20% via aggregation fix

Quality gates

typecheck:  clean
test:       502/502 in ~5s (33 files)
build:      15 dist bundles (index.js 32.74 kB + 7 verify + 4 agent + live.js)
doctor:     12/12 OK

Next

Phase 6 - Session-Replay + Component-Lib-Awareness. Session logger writes
.wisp/sessions/<id>.jsonl (Improvement #2 vs Impeccable's no-undo);
wisp-design history viewer; component-detect.ts detects shadcn/Radix/
MUI/Tailwind to prefer prop-edits over CSS-overrides (Improvement #11);
structure-variant-mode (Improvement #6); in-session policy-proposal flow
(Improvement #5); morph-mode interpolation between variants (Improvement #3);
plus Phase-5 deferred fixes (anti-slop regex tightenings, FPR aggregation,
multi-viewport baseline comparison).