docs: spec, implementation plan, jev goal gate

This commit is contained in:
ahmed mohammed
2026-09-21 14:14:12 +03:00
commit 2778ce74ba
5 changed files with 2824 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
node_modules
.next
out
build
data
.env
.env.local
.env*.local
*.tsbuildinfo
.DS_Store
.vercel
+233
View File
@@ -0,0 +1,233 @@
# Design System Master File
> **LOGIC:** When building a specific page, first check `design-system/pages/[page-name].md`.
> If that file exists, its rules **override** this Master file.
> If not, strictly follow the rules below.
---
**Project:** SQL Server qAI
**Generated:** 2026-09-21 12:56:55
**Category:** Developer Tool / IDE
**Design Dials:** Variance 4/10 (Balanced / Modern) | Motion 3/10 (Subtle) | Density 8/10 (Dense / Dashboard)
---
## Global Rules
### Color Palette
| Role | Hex | CSS Variable |
|------|-----|--------------|
| Primary | `#1E293B` | `--color-primary` |
| On Primary | `#FFFFFF` | `--color-on-primary` |
| Secondary | `#334155` | `--color-secondary` |
| On Secondary | `#FFFFFF` | `--color-on-secondary` |
| Accent/CTA | `#22C55E` | `--color-accent` |
| On Accent/CTA | `#0F172A` | `--color-on-accent` |
| Background | `#0F172A` | `--color-background` |
| Foreground | `#F8FAFC` | `--color-foreground` |
| Card | `#1B2336` | `--color-card` |
| Card Foreground | `#F8FAFC` | `--color-card-foreground` |
| Muted | `#272F42` | `--color-muted` |
| Muted Foreground | `#94A3B8` | `--color-muted-foreground` |
| Border | `#475569` | `--color-border` |
| Destructive | `#EF4444` | `--color-destructive` |
| On Destructive | `#000000` | `--color-on-destructive` |
| Ring | `#FFFFFF` | `--color-ring` |
**Color Notes:** Code dark + run green
### Typography
- **Heading Font:** JetBrains Mono
- **Body Font:** IBM Plex Sans
- **Mood:** code, developer, technical, precise, functional, hacker
- **Google Fonts:** [JetBrains Mono + IBM Plex Sans](https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap)
**CSS Import:**
```css
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
```
### Spacing Variables
*Density: 8/10 — Dense / Dashboard*
| Token | Value | Usage |
|-------|-------|-------|
| `--space-xs` | `2px` / `0.125rem` | Tight gaps |
| `--space-sm` | `4px` / `0.25rem` | Icon gaps, inline spacing |
| `--space-md` | `8px` / `0.5rem` | Standard padding |
| `--space-lg` | `12px` / `0.75rem` | Section padding |
| `--space-xl` | `16px` / `1rem` | Large gaps |
| `--space-2xl` | `24px` / `1.5rem` | Section margins |
| `--space-3xl` | `32px` / `2rem` | Hero padding |
### Shadow Depths
| Level | Value | Usage |
|-------|-------|-------|
| `--shadow-sm` | `0 1px 2px rgba(0,0,0,0.05)` | Subtle lift |
| `--shadow-md` | `0 4px 6px rgba(0,0,0,0.1)` | Cards, buttons |
| `--shadow-lg` | `0 10px 15px rgba(0,0,0,0.1)` | Modals, dropdowns |
| `--shadow-xl` | `0 20px 25px rgba(0,0,0,0.15)` | Hero images, featured cards |
---
## Component Specs
### Buttons
```css
/* Primary Button */
.btn-primary {
background: #22C55E;
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 200ms ease;
cursor: pointer;
}
.btn-primary:hover {
opacity: 0.9;
transform: translateY(-1px);
}
/* Secondary Button */
.btn-secondary {
background: transparent;
color: #1E293B;
border: 2px solid #1E293B;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 200ms ease;
cursor: pointer;
}
```
### Cards
```css
.card {
background: #0F172A;
border-radius: 12px;
padding: 24px;
box-shadow: var(--shadow-md);
transition: all 200ms ease;
cursor: pointer;
}
.card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
```
### Inputs
```css
.input {
padding: 12px 16px;
border: 1px solid #E2E8F0;
border-radius: 8px;
font-size: 16px;
transition: border-color 200ms ease;
}
.input:focus {
border-color: #1E293B;
outline: none;
box-shadow: 0 0 0 3px #1E293B20;
}
```
### Modals
```css
.modal-overlay {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
.modal {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: var(--shadow-xl);
max-width: 500px;
width: 90%;
}
```
---
## Style Guidelines
**Style:** Dark Mode (OLED)
**Keywords:** Dark theme, low light, high contrast, deep black, midnight blue, eye-friendly, OLED, night mode, power efficient
**Best For:** Night-mode apps, coding platforms, entertainment, eye-strain prevention, OLED devices, low-light
**Key Effects:** Minimal glow (text-shadow: 0 0 10px), dark-to-light transitions, low white emission, high readability, visible focus
### Page Pattern
**Pattern Name:** FAQ/Documentation Landing
- **Conversion Strategy:** Reduce support tickets. Track search analytics. Show related articles. Contact escalation path.
- **CTA Placement:** Search bar prominent + Contact CTA for unresolved questions
- **Section Order:** Hero with search bar > Popular categories > FAQ accordion > Contact/support CTA
---
## Motion
**Scroll Reveal** (Subtle) — Trigger: scroll (viewport enter) | Duration: 300-400ms | Easing: `power1.out`
```js
gsap.from(el, { opacity: 0, y: 12, duration: 0.35, ease: 'power1.out', scrollTrigger: { trigger: el, start: 'top 90%', toggleActions: 'play none none reverse' } });
```
**Framework notes:** Requires the ScrollTrigger plugin registered once via gsap.registerPlugin(ScrollTrigger); Use matchMedia('(prefers-reduced-motion: reduce)') to skip non-essential motion and render the final state immediately
- ✅ Keep the y offset small (8-16px) so it reads as a fade, not a slide
- ❌ Don't reveal below-the-fold content needed for SEO/crawlers as invisible-by-default without a no-JS fallback
- ⚡ toggleActions 'play none none reverse' avoids re-triggering on every scroll direction change
---
## Anti-Patterns (Do NOT Use)
- ❌ Light mode default
- ❌ Slow performance
### Additional Forbidden Patterns
- ❌ **Emojis as icons** — Use SVG icons (Heroicons, Lucide, Simple Icons)
- ❌ **Missing cursor:pointer** — All clickable elements must have cursor:pointer
- ❌ **Layout-shifting hovers** — Avoid scale transforms that shift layout
- ❌ **Low contrast text** — Maintain 4.5:1 minimum contrast ratio
- ❌ **Instant state changes** — Always use transitions (150-300ms)
- ❌ **Invisible focus states** — Focus states must be visible for a11y
---
## Pre-Delivery Checklist
Before delivering any UI code, verify:
- [ ] No emojis used as icons (use SVG instead)
- [ ] All icons from consistent icon set (Heroicons/Lucide)
- [ ] `cursor-pointer` on all clickable elements
- [ ] Hover states with smooth transitions (150-300ms)
- [ ] Light mode: text contrast 4.5:1 minimum
- [ ] Focus states visible for keyboard navigation
- [ ] `prefers-reduced-motion` respected
- [ ] Responsive: 375px, 768px, 1024px, 1440px
- [ ] No content hidden behind fixed navbars
- [ ] No horizontal scroll on mobile
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
# SQL Server qAI — Spec
**Date:** 2026-09-21
**Owner:** ahmedmohammed
**Status:** agreed in chat, this file is the spec of record
## Goal (verbatim from the owner)
> portal that take xml of sql server query plan and use power of generative ai to
> analysis provide multiple action steps, multiple query rewrite if possible,
> Jev then rank and decide.
## What it is
A containerised web tool. A DBA or consultant logs in, pastes a SQL Server
execution plan (Showplan XML, or a `.sqlplan` file), and gets back:
1. What the plan says is wrong (bottleneck, missing indexes, spills, bad row guesses).
2. **Multiple** candidate action plans — several different remediations, not one.
3. **Multiple** candidate SQL rewrites where a rewrite is possible.
4. A **Jev**-ranked verdict: which candidate to run first, with typed probabilities
and confidence, and why.
5. One final "best fast path": the recommended SQL and the steps to apply it.
6. The result rendered as **structured UI elements** (OpenUI Lang → React), not a
wall of markdown. Export to PDF, copy to clipboard.
The demo value is Jev as the decision-maker: the generative model proposes,
**Jev disposes**. Every ranking number on screen is a typed judgment from
`POST /v1/systemone`, not a string the LLM wrote.
## Product surface
| Screen | Job |
| --- | --- |
| `/signup`, `/login` | Email + password. Nothing else. |
| `/setup` | First-run guide: 3 steps — analyst model, Jev, done. |
| `/app` | Left rail = previous analyses (rename, delete). Main = paste plan → run → live report. |
| `/settings` | Update analyst model (base URL, key, model, extra params), Jev (key, model), email/password, history. |
Report actions: **Export to PDF**, **Copy**. History actions: **rename**, **delete**.
## Actors (two models, strict roles)
- **Analyst** — any OpenAI-compatible endpoint the user configures (`base_url`,
`key`, `model`, extra params). Generates: candidate action plans, candidate SQL
rewrites, and the final OpenUI Lang report. Text in, text out.
- **Jev** — TypeSafe System One (`@typesafe-ai/sdk`, model `jev-latest`). Never
generates prose. Answers typed questions (`score`, `choice`, `noul`) about each
candidate and returns probabilities + confidence. Code combines them.
## Requirements
1. Auth: signup, login, logout, session survives reload. Per-user data isolation.
2. Credentials at rest are encrypted (AES-256-GCM, `APP_SECRET` env). Never echoed
to the browser — masked (`••••1234`).
3. Plan input: paste XML, or drop/select a `.sqlplan`/`.xml` file. Clear inline
error if it is not a ShowPlanXML document.
4. Deterministic digest first, model second: parse the XML in code (operators,
costs, missing indexes, warnings, waits, spills, estimate vs actual). The model
sees the digest, never 40 MB of XML.
5. 2–4 candidates per run. Each candidate: diagnosis, ordered actions with effort
and change-control flag, optional rewrite SQL, expected effect.
6. Jev judges every candidate in parallel on 4 dimensions, then a second call picks
`first_to_run` across all candidates. Composite weights live in code, visible in UI.
7. Safety gate: a candidate Jev rates as semantically unsafe is never presented as
the recommended path without a visible "verify results before deploying" flag.
8. History: every run persisted (input digest, candidates, Jev verdict, rendered
report). Reopening a history item replays the stored report — zero model calls.
9. Streaming: stage indicator while digesting/proposing/judging, then the report
renders token-by-token. No spinner-for-30-seconds.
10. Single container: `docker compose up` → one image, one `/data` volume, no
external DB, no queue, no Redis.
## Non-goals
- No live connection to SQL Server. No plan-from-cache lookup. No automatic index
creation. No multi-user teams, roles, or sharing. No billing. No mobile app.
No markdown editor. No prompt marketplace. No agentic loop with tool calls.
## Success looks like
Paste a real slow-query plan → under 60 s → a ranked set of remediations where the
top pick is defensible because Jev's probabilities are on screen, and the winning
SQL is one click from the clipboard.
+84
View File
@@ -0,0 +1,84 @@
// TYPESAFE_API_KEY=... node scripts/jev-gate.mjs [path-to-plan.md]
// One Jev call: does this plan actually build the goal? Prints YES or NO. No deps, no framework.
import { readFileSync } from "node:fs";
const key = process.env.TYPESAFE_API_KEY ?? process.env.JEV_API_KEY;
if (!key) { console.error("set TYPESAFE_API_KEY"); process.exit(1); }
const file = process.argv[2] ?? "docs/superpowers/plans/2026-09-21-sql-server-qai.md";
const raw = readFileSync(file, "utf8");
// Judge the plan's structure, not its volume: code blocks are ~90% of the bytes and 60k of them
// would silently drop the last third of the plan. Keep headings, steps, prose, and checkbox lines.
const plan = process.argv.includes("--full")
? raw.slice(0, 90_000)
// Judge structure, not volume: code blocks are ~2/3 of the bytes. Replace each one with a marker
// but keep every prose line — filtering prose down to headings hid half the plan from the model.
: raw.replace(/```[\s\S]*?```/gs, "[code]")
.replace(/\n{2,}/g, "\n").slice(0, 90_000);
const goal = `A portal that takes the XML of a SQL Server query plan, uses generative AI to analyse it, provides
multiple action steps and multiple query rewrites where possible, and then has Jev rank the options and decide the
best one, returning the best query too. Output is rendered with OpenUI elements, with copy and export-to-PDF.`;
const res = await fetch("https://api.typesafe.ai/v1/systemone", {
method: "POST",
headers: { authorization: `Bearer ${key}`, "content-type": "application/json" },
body: JSON.stringify({
model: "jev-latest",
state: { goal, plan },
questions: {
matches_goal: {
type: "noul",
instructions: "Would software built exactly as described in `plan` satisfy the goal in `goal`?",
criteria: {
true: "Every part of the goal is built by some task in the plan.",
false: "A part of the goal is missing, or replaced by something else.",
},
},
coverage: {
type: "score",
instructions: "How completely does `plan` cover each separate part of the goal in `goal`?",
criteria: [
"Most of the goal is absent from the plan.",
"The happy path only; failures and edge cases missing.",
"Most parts, with one thin area.",
"Every part has a task with a test.",
"Every part has a task, a test, and a named failure behaviour.",
],
},
biggest_gap: {
type: "choice",
instructions: "For the user to actually reach the goal in `goal`, which single option listed here does `plan` still fail to cover? Choose nothing only if every part of the goal is built and tested by some task.",
criteria: {
nothing: "Nothing is missing: every part of the goal is built and tested by some task.",
get_plan: "Getting a real .sqlplan out of SQL Server and into the portal.",
jev_key: "Obtaining and entering their own Jev (TypeSafe) API key in the settings panel.",
analyst_endpoint: "Knowing which analyst model endpoint to point the app at.",
openui_render: "Rendering the answer as OpenUI elements rather than text.",
copy_pdf: "Copying the output or exporting it to PDF.",
jev_decides: "Jev ranking the options and deciding which one runs first.",
multiple_options: "Several genuinely different action plans and query rewrites.",
trust: "Telling the user whether to believe the ranking on their own data.",
failures: "What happens when the XML, the analyst model, or Jev is broken.",
history: "History with rename and delete, and reopening a stored run.",
container: "Running the whole thing in one container.",
qa: "End-to-end browser QA of the finished app.",
},
},
},
}),
});
if (!res.ok) { console.error(`Jev HTTP ${res.status}: ${(await res.text()).slice(0, 300)}`); process.exit(1); }
const { answers: a, model } = await res.json();
const yes = a.matches_goal.noul >= 0.5 && a.coverage.score >= 3 && a.biggest_gap.choice === "nothing";
console.log(model, "→", yes ? "YES — this plan builds your goal" : "NO — a gap needs closing first");
console.table({
"matches_goal (p yes)": a.matches_goal.noul,
"coverage (0-4)": a.coverage.score,
"coverage confidence": a.coverage.confidence,
"biggest_gap": a.biggest_gap.choice,
"gap confidence": a.biggest_gap.confidence,
});
console.log(Object.entries(a.biggest_gap.probabilities).sort((x, y) => y[1] - x[1]).slice(0, 4));