diff --git a/.gitattributes b/.gitattributes index 6564258..f929e65 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,7 @@ # (without this, core.autocrlf=true smudges the LF blob to CRLF on Windows and # breaks the hash locally). assets/evidence/*.json -text + +# No-key fixture source text is referenced by immutable SHA-256 values in the +# checked-in claim records. Preserve its source bytes across Windows/macOS/Linux. +backend/fixtures/source_evidence/*.txt -text diff --git a/AGENTS.md b/AGENTS.md index 183b14b..091f9ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,10 +6,13 @@ DRIFT is release intelligence for GPU and AI-infrastructure teams. It turns primary release notes into cited, confidence-labelled, engineer-ready answers: what changed, why it matters, and what to check next. -**Current phase:** `v0.7.0` is the current hosted Railway/Vercel release. It -hardens evidence byte integrity, makes human review notes database-only, and -raises the frontend briefing limit to ten. `v0.6.1` is the previously verified -hosted Railway revision, and `v0.5.1` is historical pre-review-gate evidence. The new local +**Current phase:** `v0.8.0` is the current source release. It adds a grounded +frontend chat box and makes the no-key fixture evidence inspectable against +checked-in synthetic source files; hosted deployment verification is pending. +`v0.7.0` is the current verified Railway/Vercel release: it hardens evidence +byte integrity, makes human review notes database-only, and raises the frontend +briefing limit to ten. `v0.6.1` is the previously verified hosted Railway +revision, and `v0.5.1` is historical pre-review-gate evidence. The new local guardrail work adds claim-level evidence, a separate verifier, and a human publication gate. `DRIFT_MODE=live` can make a bounded `backend.pipeline` **draft** capture: persist/reload source @@ -29,6 +32,12 @@ v2.30.7-1, TensorRT 11.1). The hosted `v0.6.1` app was then verified through API-served banner pair. This is a small, bounded reviewed set — not broad or continuous live-release analysis. +The fixture demo now ships typed claim evidence backed by explicit synthetic +source files, so the inspect-claim-evidence panel renders without an API key. +The suite is 150 tests at 100% backend +coverage; `main` branch protection requires the CI quality gate and the Codecov +`pytest` upload is confirmed (both verified 2026-07-17). + ## Key commands ```powershell @@ -170,9 +179,10 @@ The accepted deployment shape is a Vercel project rooted at `frontend/` and a Railway FastAPI service built from the repository root with `Dockerfile` and `railway.json`. The public frontend is `https://dr1ftless.vercel.app` and the API is -`https://drift-api-prod.up.railway.app`. The verified hosted application is -`v0.6.1` in `DRIFT_MODE=live`, with the Vercel origin advertised through CORS. -On 2026-07-16, `/health` reported `v0.6.1`, `/briefing` returned the four +`https://drift-api-prod.up.railway.app`. The current verified hosted application +is `v0.7.0` in `DRIFT_MODE=live`, with the Vercel origin advertised through CORS; +`v0.6.1` was the prior verified revision. On 2026-07-16, `/health` reported +`v0.6.1`, `/briefing` returned the four human-reviewed Insights published that day, `/docs` returned `200`, and the Vercel HTML referenced the canonical API-served banner pair. The Swagger banner frame follows the same light/dark preference as the canonical banners. @@ -200,7 +210,8 @@ Railway URL for local TCP-proxy access; it is not evidence of a hosted run. - `docs/BUILD_SEQUENCE.md` — implementation sequence and publication setup. - `docs/adr/` — durable architectural decisions. - `docs/INITIATIVES.md` — Codex project initiative/session evidence. -- `backend/fixtures/` — deterministic, citation-backed example insights. +- `backend/fixtures/` — deterministic, citation-backed example insights, each + carrying typed claim evidence. - `backend/fixtures/evals/` — claim-grounding calibration cases. - `notebooks/` — local manual capture/review workflow; contains no secrets. - `assets/architecture/` — Mermaid source and themed SVG/PNG renders. diff --git a/CHANGELOG.md b/CHANGELOG.md index bb67413..0088776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,101 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning: The `0.1.0` entry is the initial repository baseline published on GitHub as the annotated `v0.1.0` tag. -## [Unreleased] +## [0.8.0] - 2026-07-17 + +### Codex session record + +- Carried `019f6a78-6fa2-7121-9059-85ac8ceb9904` from reviewed-evidence release + hardening and `v0.7.0` hosted verification through this `v0.8.0` source + release. + +### Added + +- Gave the three fixture Insights typed `claims` arrays backed by frozen, + checked-in synthetic source files. Every span, offset, source URL, and + source-content SHA-256 now follows the same invariant as a live claim; a + regression test rejects mismatched source text, hashes, URLs, offsets, or raw + item IDs. The **Inspect claim evidence** panel now renders in no-key fixture + mode without implying that example text is an upstream release note. The suite + passes 150 tests at 100% backend coverage. +- **Ask DRIFT** grounded-chat box in the frontend (`frontend/app/AskDrift.tsx`): + a single client component that posts a question to `/chat` and renders the + grounded answer, its source citations, the model/audit label, and the grounded + insight IDs, with explicit loading, no-match (HTTP 404), and error states. It + works in both fixture and live mode. The input now matches the `/chat` + contract (3–2,000 characters), reports server errors accurately, and announces + state changes accessibly. The `/chat` contract was verified against the + fixture backend and the production frontend build passes. +- Embedded the reviewed-briefing and claim-evidence screenshots in the README as + live-state visual evidence (`assets/screenshots/03-briefing.png` and + `04-briefing-claim-evidence.png`), alongside the branded Swagger and + architecture assets. +- **Presentation architecture diagram** — a hand-authored, presentation-grade + visual (`assets/architecture/arch-{dark,light}.svg`, generated by + `build_arch.py` + `build_arch_raster.mjs`) that dramatizes the six typed + stages as a first-look **trust boundary**: untrusted feeds → quarantined + machine drafts → the human review gate → trusted, published briefing. The + README and `docs/ARCHITECTURE.md` now lead with it, with the Mermaid pipeline + kept as the maintainable system-of-record in a collapsible section. + +### Changed + +- Restructured the README top for first impression: **The Problem → What DRIFT + Does → Try DRIFT in 60 Seconds**, leading with the hosted demo links and a + one-command `docker compose up` judge path. Reframed the closing **Disclaimer** + as a positive **Trust Model** (untrusted input → frozen source span → separate + verifier pass → human review gate) and kept the Codex/GPT-5.6 usage section + prominent. +- Made the Quick Start cross-platform: promoted `docker compose up` as the + one-command local path and added bash/curl equivalents beside every PowerShell + command (setup, endpoint calls, and the live capture command). +- Corrected the P1 tracker to name the implemented grounded-chat component + honestly. It uses `/chat`, whose retrieve-first backend already performs the + evidence lookup; the separate `/search` endpoint remains available in the API + rather than duplicating live retrieval and provider work in the browser. +- Renamed the tracked UI screenshots to clean kebab-case filenames + (`01-landing`, `02-api-docs`, `03-briefing`, `04-briefing-claim-evidence`) so + they embed reliably in Markdown. +- Rebuilt the Mermaid architecture diagram (`arch-pipeline.mmd`) into three + colour-coded trust zones (untrusted · quarantine · trusted) with the human + review gate as the crossing point, and regenerated all four light/dark + renders. The auto-laid Mermaid is kept acyclic — the "engineer also reviews" + loop-closing edge appears only in the hand-laid presentation diagram — so the + zones read left + to right. +- Renamed the Mermaid architecture assets for clarity: `architecture-diagram*` + → `arch-pipeline*` (source, renders, and theme configs), pairing them with the + new hand-authored `arch-*` presentation diagram, and updated every reference + across the README, `docs/ARCHITECTURE.md`, `CONTRIBUTING.md`, and the asset + guides. +- Elevated the canonical DRIFT brand banners to share the presentation diagram's + visual system — trust-zone palette, node styling, gold human-review gate, + dot-grid field, and a subtle GPU compute-lattice backdrop (circuit traces, + vias, and a PCB edge-connector) behind the evidence-path card — via a new + `assets/brand/build_banner.py` generator (with a `build_banner_raster.mjs` + PNG export). The API-served SVG filenames + (`drift-banner-{dark,light}.svg`) are unchanged, so `backend/main.py` and the + Docker image keep serving them. +- Refreshed the README **Project Structure** tree to match the current backend, + frontend, assets, scripts, migrations, and tooling layout. +- Locked one **DRIFT signature gradient** (teal `#2dd4bf` → indigo `#818cf8` + dark / `#0d9488` → `#4f46e5` light) across the banner wordmark and the + presentation-diagram eyebrow, with the semantic node/trust colours kept for the + diagrams. The endpoints are the diagram's own source-teal → agent-indigo + hues; the locked palette is documented in `assets/brand/README.md`. +- Added a **Powered by GPT-5.6 tiers · Luna · Terra · Sol** credit to the brand + banner, and a GPU compute-lattice backdrop behind the evidence-path card. + +### Repository operations + +- Enabled branch protection on `main` (2026-07-17): the five CI quality-gate + checks (Ruff lint, Mypy type check, Tests and coverage, Frontend build, and + Documentation hygiene) are required, with strict up-to-date merges; admins + retain a bypass for pre-deadline hotfixes. Tag-only release checks are + intentionally excluded. +- Confirmed the Codecov `pytest` upload on the dashboard (2026-07-17): the + tokenless OIDC upload is queued and processed, and the repository and + `flag=pytest` coverage badges both resolve to 100%. ## [0.7.0] - 2026-07-16 @@ -452,7 +546,7 @@ with explicit live-path architecture and publication-ready quality gates. - GitHub Actions gates for Ruff, mypy, pytest/coverage, Codecov upload, frontend build, release quality, and documentation hygiene. - Mermaid architecture source with light/dark SVG and PNG renders, plus - repository-native DRIFT hero banners. + repository-native DRIFT brand banners. - Seven ADRs covering fixture-first execution, typed stages, provenance, budget control, persistence, CI, and deployment topology. - Contribution, security, runbook, architecture, build-sequence, and timed @@ -483,7 +577,7 @@ with explicit live-path architecture and publication-ready quality gates. `019f61fc-c32e-7d92-9d2e-0bd9083d08e7`. - Full scope and submission guidance: [`docs/INITIATIVES.md`](docs/INITIATIVES.md). -[Unreleased]: #unreleased +[0.8.0]: #080---2026-07-17 [0.7.0]: #070---2026-07-16 [0.6.1]: #061---2026-07-16 [0.6.0]: #060---2026-07-16 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9b3ee10..187d62c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,11 +85,12 @@ audit label. ## Documentation and architecture assets -The source of truth for the main architecture visual is -`assets/architecture/architecture-diagram.mmd`. Regenerate its SVG/PNG renders -with the instructions in `assets/architecture/README.md`; do not hand-edit a -rendered diagram. Architecture decisions belong in `docs/adr/`. +The source of truth for the main architecture visual is the pipeline Mermaid +`assets/architecture/arch-pipeline.mmd` and the hand-authored presentation-diagram generator +`assets/architecture/build_arch.py`. Regenerate the SVG/PNG renders with the +instructions in `assets/architecture/README.md`; do not hand-edit a rendered +diagram. Architecture decisions belong in `docs/adr/`. -The nine project initiatives and their Codex Session IDs are recorded in +The ten project initiatives and their Codex Session IDs are recorded in [`docs/INITIATIVES.md`](docs/INITIATIVES.md); update that record if a future initiative materially changes the baseline. diff --git a/README.md b/README.md index d03aed1..da45792 100644 --- a/README.md +++ b/README.md @@ -13,50 +13,91 @@ [![Codecov](https://codecov.io/gh/iarjunganesh/drift/graph/badge.svg)](https://codecov.io/gh/iarjunganesh/drift) [![Release](https://img.shields.io/badge/release-latest-2ea44f?logo=github&logoColor=white)](https://github.com/iarjunganesh/drift/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -[![Watch Video](https://img.shields.io/badge/%E2%96%B6_Watch-3--min_demo-FF0000?logo=youtube&logoColor=white)](#live--interactive-demo) +[![Watch Video](https://img.shields.io/badge/%E2%96%B6_Watch-3--min_demo-FF0000?logo=youtube&logoColor=white)](#try-drift-in-60-seconds) + +[![Agent Pattern](https://img.shields.io/badge/Agent_Pattern-asyncio_typed_stages-3776AB?logo=python&logoColor=white)](backend/agents/base.py) +[![GPT-5.6 Luna](https://img.shields.io/badge/GPT--5.6-Luna-412991?logo=openai&logoColor=white)](https://developers.openai.com/api/docs/models/gpt-5.6-luna) +[![GPT-5.6 Terra](https://img.shields.io/badge/GPT--5.6-Terra-412991?logo=openai&logoColor=white)](https://developers.openai.com/api/docs/models/gpt-5.6-terra) +[![GPT-5.6 Sol](https://img.shields.io/badge/GPT--5.6-Sol-412991?logo=openai&logoColor=white)](https://developers.openai.com/api/docs/models/gpt-5.6-sol) +[![Pydantic](https://img.shields.io/badge/Pydantic-2.13_contracts-E92063?logo=pydantic&logoColor=white)](https://docs.pydantic.dev/) +[![structlog](https://img.shields.io/badge/structlog-JSON_observability-4A90E2)](https://www.structlog.org/) + + +[![Next.js](https://img.shields.io/badge/Next.js-16.2.10-000000?logo=nextdotjs&logoColor=white)](https://nextjs.org/) +[![React](https://img.shields.io/badge/React-19.2.7-61DAFB?logo=react&logoColor=black)](https://react.dev/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![Node.js](https://img.shields.io/badge/Node.js-24-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/) +[![Vercel Hobby](https://img.shields.io/badge/Vercel-Hobby-000000?logo=vercel&logoColor=white)](https://vercel.com) + + [![Python](https://img.shields.io/badge/Python-3.14-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.139-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) +[![Ruff](https://img.shields.io/badge/Ruff-lint%20%2B%20format-D7FF64?logo=ruff&logoColor=111827)](https://docs.astral.sh/ruff/) +[![pytest](https://img.shields.io/badge/pytest-9.1-0A9EDC?logo=pytest&logoColor=white)](https://docs.pytest.org/) +[![Railway Hobby](https://img.shields.io/badge/Railway-Hobby-0B0D0E?logo=railway&logoColor=white)](https://railway.com) + + [![PostgreSQL](https://img.shields.io/badge/PostgreSQL-17-336791?logo=postgresql&logoColor=white)](https://www.postgresql.org/) [![pgvector](https://img.shields.io/badge/pgvector-0.5.0-336791?logo=postgresql&logoColor=white)](https://github.com/pgvector/pgvector) -[![OpenAI](https://img.shields.io/badge/OpenAI-SDK-412991?logo=openai&logoColor=white)](https://platform.openai.com/) -[![Ruff](https://img.shields.io/badge/Ruff-lint%20%2B%20format-D7FF64?logo=ruff&logoColor=111827)](https://docs.astral.sh/ruff/) -[![Next.js](https://img.shields.io/badge/Next.js-16.2.10-000000?logo=nextdotjs&logoColor=white)](https://nextjs.org/) -[![React](https://img.shields.io/badge/React-19.2.7-61DAFB?logo=react&logoColor=black)](https://react.dev/) -[![Node.js](https://img.shields.io/badge/Node.js-24-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/) -[![Railway](https://img.shields.io/badge/Railway-backend-0B0D0E?logo=railway&logoColor=white)](https://drift-api-prod.up.railway.app/docs) -[![Vercel](https://img.shields.io/badge/Vercel-frontend-000000?logo=vercel&logoColor=white)](https://dr1ftless.vercel.app) + +[![Vercel live frontend](https://img.shields.io/badge/Vercel-live_frontend-000000?logo=vercel&logoColor=white)](https://dr1ftless.vercel.app) +[![Railway live API](https://img.shields.io/badge/Railway-live_API-0B0D0E?logo=railway&logoColor=white)](https://drift-api-prod.up.railway.app/docs) --- -## What Is This? +## The Problem + +GPU and AI platforms depend on fast-moving projects such as PyTorch, TensorRT, +Triton, vLLM, Transformers, CUTLASS, JAX, and NCCL. A small upstream change can +alter an image, benchmark, CUDA assumption, or deployment template — but release +review is usually a stream of links and scattered human memory. The signal that +matters is buried: *what changed, whether it touches your workload, and what to +check before rollout.* + +## What DRIFT Does DRIFT is release intelligence for GPU and AI-infrastructure teams. It turns upstream release-note noise into a cited, engineer-ready answer: > **What changed? Why does it matter to my workload? What should I check?** -The first vertical slice is fixture-first and deterministic. The target system -will watch primary release feeds, rank meaningful changes, explain workload -impact, and return a bounded next engineering check without presenting model -output as a deployment verdict. +Every answer keeps the useful middle layer visible: a frozen primary-source +span, a plain-language summary, workload relevance, confidence, severity, and +one bounded action to check. Direct facts stay separate from interpretation, and +nothing reaches a live endpoint until a human reviews it. Built for **OpenAI Build Week 2026 · Developer Tools**. ---- +## Try DRIFT in 60 Seconds -## The Problem +**Hosted — nothing to install.** The live briefing serves four human-reviewed +Insights from one real bounded capture (Transformers v5.14.1, vLLM v0.25.1, +NCCL v2.30.7-1, TensorRT 11.1); `/briefing`, `/search`, and `/chat` were verified +provider-backed on 2026-07-16. -GPU and AI platforms depend on fast-moving projects such as PyTorch, TensorRT, -Triton, vLLM, Transformers, CUTLASS, JAX, and NCCL. A small upstream change can -alter an image, benchmark, CUDA assumption, or deployment template, but release -review is usually a stream of links and scattered human memory. +| Surface | Link | +| --- | --- | +| **Frontend** — briefing with inspectable claim evidence | | +| **API docs** — `/health`, `/briefing`, `/search`, `/chat`, `/openapi.json` | | +| **Grounded chat** — cited answer over reviewed evidence (verified provider-backed) | [`POST /chat` in the API docs](https://drift-api-prod.up.railway.app/docs) | +| **Demo video** — 3-min narrated walkthrough (Codex + GPT-5.6) | [▶ Watch on YouTube](https://youtu.be/TBD) *(recording before submission)* | -DRIFT keeps the useful middle layer visible: source evidence, a plain-language -summary, workload relevance, confidence, severity, and one concrete action to -check. It does not certify compatibility, replace release notes, or authorize -production changes. +**Local — one command, no API key.** The deterministic fixture path brings up the +API, PostgreSQL, and the frontend — including the in-app **Ask DRIFT** +grounded-chat box — together: + +```bash +git clone https://github.com/iarjunganesh/drift.git +cd drift +docker compose up +``` + +Open for the frontend and + for the API. No OpenAI key is required, and every +record is clearly labelled example data. Full setup, cross-platform commands, +and the live capture path are in [Quick Start](#quick-start). --- @@ -78,28 +119,47 @@ The currently working path substitutes committed examples for the unfinished live stages: ```text -backend/fixtures/insights.json → InsightStore → FastAPI → briefing/search/chat +backend/fixtures/source_evidence/*.txt + insights.json → InsightStore → FastAPI → briefing/search/chat ``` -Fixture records are explicitly labelled examples. They are never described as -fresh live release analysis. +Fixture records are explicitly labelled examples, backed by checked-in +synthetic source text whose hashes and spans are verified in tests. They are +never described as fresh live release analysis. --- ## Architecture

- + - - - DRIFT architecture — primary release feeds through Scout, Synthesizer, Insight, and Briefing into FastAPI + + + DRIFT trust boundary — untrusted release feeds pass through machine claim extraction and a separate verifier into quarantined drafts; a human review gate is the only bridge to the trusted, published briefing an engineer sees.

-Click to enlarge: light SVG / dark SVG · Downloadable light PNG / dark PNG · Source: architecture-diagram.mmd +

The trust boundary at a glance. Everything left of the gate is untrusted machine output; a human reviewer is the only path to what an engineer sees. · light SVG / dark SVG

+ +
+Detailed pipeline diagram — the same six typed stages, as the maintainable Mermaid source of truth + +

+ + + + + DRIFT architecture — primary release feeds through Scout, Synthesizer, claim extraction, a separate verifier, a human review gate, and Briefing into FastAPI + + +

+ +Click to enlarge: light SVG / dark SVG · Downloadable light PNG / dark PNG · Source: arch-pipeline.mmd + +
**In short:** the fixture path is complete and no-key. The local live path now persists source evidence, generates and separately verifies claim-grounded @@ -124,7 +184,7 @@ bounded reviewed set, not a broad live-release-analysis claim. ### Codex project initiatives The baseline, publication follow-up, bounded release milestones, and -documentation follow-up are tied to nine project initiatives. The grounded +documentation follow-up are tied to ten project initiatives. The grounded live-chat row remains the primary v0.4.0 implementation session; v0.5.0 adds the bounded local capture path. @@ -133,12 +193,13 @@ the bounded local capture path. | Foundation and inspectable vertical slice | `019f61e7-1ea1-7742-9acc-99d62f39b888` | Fixture API, typed contracts, agent boundaries, safety invariants, tests | | Publication and judge-readiness baseline | `019f61fc-c32e-7d92-9d2e-0bd9083d08e7` | Documentation, architecture assets, CI/Codecov, deployment and submission surfaces | | Hosted deployment and README follow-up | `019f6253-ddfc-7272-8077-e34dfb3aee84` | Railway/Vercel URLs, release badges, and public demo documentation | -| Day 1/Day 2 implementation follow-up | `019f62e8-6715-70e2-a92a-fe28254f7b71` | Scout feeds, async PostgreSQL/pgvector foundation, Tier.DEV embeddings/clustering/classification, session instructions, and status cleanup | | Grounded live chat, resilience, and locked delivery | `019f62b9-10b7-7d82-a463-e6eb1192141c` | Primary `0.2.0` candidate work: local live chat, async safeguards, locked delivery, and full implemented-code coverage | +| Day 1/Day 2 implementation follow-up | `019f62e8-6715-70e2-a92a-fe28254f7b71` | Scout feeds, async PostgreSQL/pgvector foundation, Tier.DEV embeddings/clustering/classification, session instructions, and status cleanup | | Day 3/Day 4 Insight structured output | `019f6336-3690-7022-a8ef-c8c0947e240f` | Standalone `generate_insight()` structured parsing, strict validation, citations, confidence, and model provenance | | Bounded capture, provenance, and status cleanup | `019f66b4-78b8-7943-a41d-91e836d28f00` | One-shot persisted capture, all-call budget/retry controls, live briefing adapter, evidence UI, and documentation synchronization | | Grounding guardrails and capture readiness | `019f6773-0e96-7363-9657-0e0531c3d594` | Claim spans/hashes, separate verifier, review-gated publication, cross-references, calibration cases, manual notebook, and all-source capture preflight | | Submission audit and frontend evidence presentation | `019f6a46-e3eb-7de2-81b1-91515ae80043` | Handwritten-next-step audit, explicit briefing states, system-theme presentation, canonical API-served banners, and status synchronization | +| Reviewed-evidence release hardening, hosted verification, and v0.8.0 source release | `019f6a78-6fa2-7121-9059-85ac8ceb9904` | Evidence-byte integrity, database-only review notes, display-only results artifact, `v0.7.0` hosted verification, and the `v0.8.0` grounded-chat / verifiable-fixture source release | See the full [project initiative record](docs/INITIATIVES.md). @@ -154,7 +215,9 @@ the Day 3/Day 4 Insight implementation session is `019f6336-3690-7022-a8ef-c8c0947e240f`; the grounding guardrail and capture-readiness follow-up is `019f6773-0e96-7363-9657-0e0531c3d594`; and the submission-audit/frontend-presentation follow-up is -`019f6a46-e3eb-7de2-81b1-91515ae80043`. +`019f6a46-e3eb-7de2-81b1-91515ae80043`; the reviewed-evidence hardening, +hosted-verification, and `v0.8.0` source-release session is +`019f6a78-6fa2-7121-9059-85ac8ceb9904`. GPT-5.6 is used only when an operator explicitly enables `DRIFT_MODE=live` and provides an API key. The local capture job routes embeddings, classification, @@ -227,14 +290,14 @@ conservatively; it is never silently treated as free. | Layer | Technology | Role | | --- | --- | --- | -| **Backend** | [![FastAPI](https://img.shields.io/badge/FastAPI-0.139-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) [![Python](https://img.shields.io/badge/Python-3.14-3776AB?logo=python&logoColor=white)](https://www.python.org/) | Typed HTTP API and explicit pipeline stages | +| **Backend** | [![Python](https://img.shields.io/badge/Python-3.14-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-0.139-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) | Typed HTTP API and explicit pipeline stages | | **Contracts** | [![Pydantic](https://img.shields.io/badge/Pydantic-2.13-E92063?logo=pydantic&logoColor=white)](https://docs.pydantic.dev/) | Typed raw-item, insight, briefing, and chat contracts | | **Agent Pattern** | [![asyncio](https://img.shields.io/badge/asyncio-typed%20stages-3776AB?logo=python&logoColor=white)](backend/agents/base.py) | Small lifecycle-wrapped functions; no orchestration framework | | **Release Feeds** | [![feedparser](https://img.shields.io/badge/feedparser-Atom%20%2F%20RSS-3776AB?logo=python&logoColor=white)](https://feedparser.readthedocs.io/) [![PyYAML](https://img.shields.io/badge/PyYAML-sources-3776AB?logo=python&logoColor=white)](https://pyyaml.org/) | Configured primary-source feed definitions and parsing | | **Live Store** | [![PostgreSQL](https://img.shields.io/badge/PostgreSQL-17-336791?logo=postgresql&logoColor=white)](https://www.postgresql.org/) [![pgvector](https://img.shields.io/badge/pgvector-0.5.0-336791?logo=postgresql&logoColor=white)](https://github.com/pgvector/pgvector) | Durable raw items, insights, and vector retrieval | -| **Model Boundary** | [![OpenAI](https://img.shields.io/badge/OpenAI-SDK-412991?logo=openai&logoColor=white)](https://platform.openai.com/) | Provider isolation, model tiers, and budget control | -| **Quality** | [![Ruff](https://img.shields.io/badge/Ruff-0.15.21-D7FF64?logo=ruff&logoColor=111827)](https://docs.astral.sh/ruff/) [![pytest](https://img.shields.io/badge/pytest-9.1-0A9EDC?logo=pytest&logoColor=white)](https://docs.pytest.org/) [![Codecov](https://img.shields.io/badge/Codecov-pytest-f01f7a?logo=codecov&logoColor=white)](https://codecov.io/) | Lint, types, tests, coverage evidence, and CI enforcement | -| **Frontend** | [![Next.js](https://img.shields.io/badge/Next.js-16.2.10-000000?logo=nextdotjs&logoColor=white)](https://nextjs.org/) [![React](https://img.shields.io/badge/React-19.2.7-61DAFB?logo=react&logoColor=black)](https://react.dev/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) | Operator-facing briefing view | +| **Model Boundary** | [![GPT-5.6](https://img.shields.io/badge/OpenAI-GPT--5.6_tiers-412991?logo=openai&logoColor=white)](https://developers.openai.com/api/docs/models) | Provider isolation, GPT-5.6 Luna/Terra/Sol tiers, and budget control | +| **Quality** | [![Codecov](https://img.shields.io/badge/Codecov-pytest-f01f7a?logo=codecov&logoColor=white)](https://codecov.io/) [![pytest](https://img.shields.io/badge/pytest-9.1-0A9EDC?logo=pytest&logoColor=white)](https://docs.pytest.org/) [![Ruff](https://img.shields.io/badge/Ruff-0.15.21-D7FF64?logo=ruff&logoColor=111827)](https://docs.astral.sh/ruff/) | Lint, types, tests, coverage evidence, and CI enforcement | +| **Frontend** | [![Next.js](https://img.shields.io/badge/Next.js-16.2.10-000000?logo=nextdotjs&logoColor=white)](https://nextjs.org/) [![React](https://img.shields.io/badge/React-19.2.7-61DAFB?logo=react&logoColor=black)](https://react.dev/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/Node.js-24-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/) | Operator-facing briefing view | | **Hosting** | [![Railway](https://img.shields.io/badge/Backend-Railway-0B0D0E?logo=railway&logoColor=white)](https://railway.app/) [![Vercel](https://img.shields.io/badge/Frontend-Vercel-000000?logo=vercel&logoColor=white)](https://vercel.com/) | Railway API/database; Vercel Next.js frontend | | **Observability** | [![structlog](https://img.shields.io/badge/structlog-JSON-4A90E2)](https://www.structlog.org/) | Structured logs and explicit request/stage boundaries | @@ -245,56 +308,34 @@ that frozen lockfile. JavaScript dependencies are locked in --- -## Live & Interactive Demo +## Deployment status -The Railway API and Vercel frontend are live. The Vercel project deploys from -`frontend/` using its checked-in build configuration. On 2026-07-16, hosted -`v0.6.1` verified the briefing-state and canonical-banner release after Railway -PostgreSQL reached the review-gate migration. The API-docs banner frame follows -the same system light/dark preference as the canonical banner. +Both tiers are live and were verified on 2026-07-16 — the live links live up top +in [Try DRIFT in 60 Seconds](#try-drift-in-60-seconds): -| | | +| Surface | Status | | --- | --- | -| **Current hosted API** | `v0.7.0` `live` — `/health`, `/briefing` (four reviewed Insights with review notes redacted), `/docs`, and Vercel-origin CORS verified on 2026-07-16; deployed Vercel requests `top_n=10` | -| **Hosted frontend source** | Vercel HTML references the canonical API-served light/dark banner pair; the browser post-fetch empty-state rendering is not separately recorded | -| **API docs branding** | The Swagger banner frame and canonical banner pair follow the same system light/dark preference | -| **Historical evidence** | `v0.5.1` `live` — one unreviewed vLLM Insight served through `/briefing` on 2026-07-15; retained as pre-gate evidence only | -| **Database schema** | Railway PostgreSQL verified at `0003_claim_evidence_review_gate` through its public TCP proxy on 2026-07-16 | -| **Frontend** | [https://dr1ftless.vercel.app](https://dr1ftless.vercel.app) | -| **API** | [https://drift-api-prod.up.railway.app](https://drift-api-prod.up.railway.app) | -| **Swagger** | [`/docs`](https://drift-api-prod.up.railway.app/docs) | -| **OpenAPI** | [`/openapi.json`](https://drift-api-prod.up.railway.app/openapi.json) | -| **Briefing** | [`/briefing`](https://drift-api-prod.up.railway.app/briefing) | -| **Demo Video** | [`https://youtu.be/TBD`](https://youtu.be/TBD) *(≤ 3 min, record before submission)* | -| **Public demo** | Vercel frontend and Railway API are live; Vercel-to-Railway CORS was reverified on 2026-07-16 | - -One unreviewed real-model vLLM capture is saved as historical hosted evidence. -The fixture path remains the reproducible no-key demo. The review-gated code -is deployed with its Railway schema migration. On 2026-07-16 an eight-source -capture produced six verifier-passed drafts; four were published after human -review, so hosted `/briefing`, `/search`, and `/chat` now serve those four -reviewed Insights (verified provider-backed). This is a small, bounded reviewed -set, not broad live-release analysis. - -The Swagger contract groups the backend into **System**, **Briefing**, -**Search**, and **Chat** sections so reviewers can navigate the API by job. +| **Current source release** | `v0.8.0` — grounded Ask DRIFT UI and verifiable synthetic fixture evidence; source tag published, hosted deployment verification pending | +| **Hosted API** | `v0.7.0` `live` — `/health`, `/briefing` (four reviewed Insights, review notes redacted), `/docs`, `/openapi.json`, and Vercel-origin CORS verified; the deployed Vercel bundle requests `top_n=10` | +| **Grounded retrieval** | `/briefing`, `/search`, and `/chat` verified provider-backed from an eight-source capture — six verifier-passed drafts, four published after human review | +| **Database schema** | Railway PostgreSQL at `0003_claim_evidence_review_gate`, verified through its public TCP proxy | +| **Branding** | Swagger banner frame and canonical API-served banner pair follow the same system light/dark preference | +| **Historical** | `v0.5.1` served one unreviewed vLLM Insight through `/briefing` on 2026-07-15 — retained as pre-gate evidence only | + +This is a small, bounded reviewed set, not broad live-release analysis. The +Swagger contract groups the backend into **System**, **Briefing**, **Search**, +and **Chat** sections so reviewers can navigate the API by job. --- ## Screenshots & Evidence -The architecture assets are the current visual evidence and are available in -both SVG and PNG formats: - -The scrubbed hosted capture evidence is stored separately in -[`assets/evidence/`](assets/evidence/), including the verified unreviewed vLLM -briefing response and its explicit operational limitations. After a human -publishes a new notebook capture, its archive cell writes a new dated reviewed -record and SHA-256 manifest there without including review notes or secrets. +These are live-state captures of the hosted app after four human-reviewed +Insights were published — not mockups. Click any image to open it full size. -| Light | Dark | +| Briefing — four reviewed Insights | Inspecting frozen claim evidence | | --- | --- | -| [![DRIFT architecture light](assets/architecture/architecture-diagram-light.png)](assets/architecture/architecture-diagram-light.svg) | [![DRIFT architecture dark](assets/architecture/architecture-diagram-dark.png)](assets/architecture/architecture-diagram-dark.svg) | +| [![DRIFT briefing showing four reviewed Insights](assets/screenshots/03-briefing.png)](assets/screenshots/03-briefing.png) | [![DRIFT briefing expanded to show each claim's primary-source excerpt](assets/screenshots/04-briefing-claim-evidence.png)](assets/screenshots/04-briefing-claim-evidence.png) | The Next.js briefing view exposes each record's status label, confidence, model/audit label, rationale, bounded action, source links, and—when present— @@ -305,11 +346,61 @@ now serves four reviewed Insights instead of the intentional empty state. Railway, CORS, public-contract, and Vercel-bundle checks are recorded in the changelog. This did not re-run paid provider chat. +The branded Swagger contract and the themed architecture assets are also +available as visual evidence: + +| API documentation | Architecture (light / dark) | +| --- | --- | +| [![DRIFT branded Swagger API documentation](assets/screenshots/02-api-docs.png)](assets/screenshots/02-api-docs.png) | [![DRIFT architecture light](assets/architecture/arch-pipeline-light.png)](assets/architecture/arch-pipeline-light.svg)
[![DRIFT architecture dark](assets/architecture/arch-pipeline-dark.png)](assets/architecture/arch-pipeline-dark.svg) | + +The scrubbed hosted capture evidence is stored separately in +[`assets/evidence/`](assets/evidence/), including the verified unreviewed vLLM +briefing response and its explicit operational limitations. After a human +publishes a new notebook capture, its archive cell writes a new dated reviewed +record and SHA-256 manifest there without including review notes or secrets. + --- ## Quick Start -Requirements: Python 3.14, `uv`, and Node.js 24.x for the frontend. +### One command (recommended) + +The fastest judge path brings up the API, PostgreSQL, and the frontend together +in fixture mode — no OpenAI key, identical on macOS, Linux, and Windows: + +```bash +git clone https://github.com/iarjunganesh/drift.git +cd drift +docker compose up +``` + +Open for the frontend and +for the API. Every record is labelled example data. + +### Manual setup + +Requirements: Python 3.14, `uv`, and Node.js 24.x for the frontend. Every +command below is shown for both shells; run whichever matches your platform. + +#### bash — macOS / Linux + +```bash +# 1. Clone the public repository +git clone https://github.com/iarjunganesh/drift.git +cd drift + +# 2. Configure the no-key fixture path +cp .env.example .env + +# 3. Install locked Python dependencies +uv venv .venv +uv sync --locked --group dev + +# 4. Start the API +uv run uvicorn backend.main:app --reload +``` + +#### PowerShell — Windows ```powershell # 1. Clone the public repository @@ -327,7 +418,20 @@ uv sync --locked --group dev uv run uvicorn backend.main:app --reload ``` -Open , or try: +Open , or try the endpoints: + +#### bash / curl + +```bash +curl http://127.0.0.1:8000/health +curl http://127.0.0.1:8000/briefing +curl "http://127.0.0.1:8000/search?q=vllm" +curl -X POST http://127.0.0.1:8000/chat \ + -H "Content-Type: application/json" \ + -d '{"question":"What should I check for vLLM?"}' +``` + +#### PowerShell ```powershell Invoke-RestMethod http://127.0.0.1:8000/health @@ -338,9 +442,11 @@ Invoke-RestMethod http://127.0.0.1:8000/chat ` -Body '{"question":"What should I check for vLLM?"}' ``` -Run the frontend in another terminal: +Run the frontend in another terminal (same command on every platform). This is +also where the in-app **Ask DRIFT** box calls `/chat` for a grounded, cited +answer: -```powershell +```bash npm --prefix frontend ci npm --prefix frontend run dev ``` @@ -370,7 +476,14 @@ The underlying capture command is also draft-only. Enable live mode, provide an API key, and select a deliberately small source set. Start with `dev` for prompt iteration and use `final` only for selected, already-reviewed sources: +```bash +# bash — macOS / Linux +export DRIFT_MODE=live +uv run python -m backend.pipeline --source vllm --source tensorrt --source pytorch --tier dev +``` + ```powershell +# PowerShell — Windows $env:DRIFT_MODE='live' uv run python -m backend.pipeline --source vllm --source tensorrt --source pytorch --tier dev ``` @@ -384,12 +497,16 @@ not a scheduled feed service and does not publish or verify the hosted deploymen The fixture path uses [`backend/fixtures/insights.json`](backend/fixtures/insights.json). These records are committed examples for deterministic development and judging; -they are not current release analysis. Each record preserves the contract that -the live path must also satisfy: +they are not current release analysis. Each record carries typed `claims` with +frozen example excerpts, offsets, and source hashes, so the **Inspect claim +evidence** panel renders in no-key fixture mode exactly as it does for a reviewed +live capture. Each record preserves the contract that the live path must also +satisfy: | Field | Purpose | | --- | --- | | `citations` | Source URLs supporting the insight | +| `claims` | Typed `direct_fact` / `inference` / `recommended_check` statements, each with a frozen example evidence span | | `confidence` | Visible certainty in `[0, 1]` | | `model_used` | Fixture audit label or exact live model identifier | | `what_to_check` | Bounded engineering action | @@ -402,38 +519,42 @@ the live path must also satisfy: ```text drift/ ├── backend/ -│ ├── agents/ # Base, Scout, Synthesizer, Insight, and Briefing stages -│ ├── core/ # Settings, model router, fixture store, and SpendGuard -│ ├── fixtures/ # Deterministic citation-backed example insights -│ ├── models/ # Pydantic domain and API contracts -│ ├── main.py # FastAPI app: health, briefing, search, chat -│ ├── pipeline.py # Bounded one-shot live capture CLI -│ ├── review.py # Explicit human publication gate -│ ├── sources.yaml # Primary release-feed configuration -├── frontend/ # Next.js + React + TypeScript briefing view -│ ├── .nvmrc # Node.js 24.x local/runtime selection -│ └── vercel.json # Vercel build settings and Railway API URL +│ ├── agents/ # base, scout, synthesizer, insight, briefing stages +│ ├── core/ # config, model_router, store, live_store, budget, resilience +│ ├── models/schema.py # Pydantic domain, claim-evidence, and API contracts +│ ├── fixtures/insights.json # deterministic example insights with claim evidence +│ ├── main.py # FastAPI app: health, briefing, search, chat, /brand +│ ├── pipeline.py # bounded one-shot live capture CLI (draft-only) +│ ├── review.py # explicit human publication gate +│ ├── evidence_archive.py # reviewed-evidence archive + SHA-256 manifest writer +│ └── sources.yaml # primary release-feed configuration +├── frontend/ # Next.js + React + TypeScript briefing view +│ ├── app/ # page.tsx, layout.tsx, AskDrift.tsx (grounded chat box) +│ ├── .nvmrc # Node.js 24.x local/runtime selection +│ └── vercel.json # Vercel build settings and Railway API URL ├── assets/ -│ ├── architecture/ # Mermaid source plus themed SVG/PNG renders -│ └── brand/ # Repository-native DRIFT hero banners +│ ├── architecture/ # arch-* presentation (build_arch.py) + arch-pipeline-* Mermaid +│ ├── brand/ # DRIFT brand banners (build_banner.py); API-served +│ ├── evidence/ # scrubbed hosted-capture records + SHA-256 manifests +│ └── screenshots/ # live-state UI captures used in the README ├── tests/ -│ ├── unit/ # Agent, budget, and configuration tests -│ └── integration/ # API and lifespan tests +│ ├── unit/ # agent, budget, resilience, and configuration tests +│ └── integration/ # API, lifespan, and evidence-boundary tests ├── docs/ -│ ├── ARCHITECTURE.md # Runtime and deployment deep dive -│ ├── INITIATIVES.md # Codex project initiative/session records -│ ├── BUILD_SEQUENCE.md # Implementation sequence and GitHub/Codecov setup -│ ├── RUNBOOK.md # Fixture/live demo procedure -│ └── adr/ # Architecture Decision Records 001–010 -├── notebooks/ # Local bounded capture/review workflow -├── submission/ # Developer Tools handoff, checklist, and demo script -├── Dockerfile # Railway image built from frozen uv.lock -├── docker-compose.yml # Local API + PostgreSQL + frontend wiring -├── migrations/ # Alembic schema and provenance revisions -├── railway.json # Railway build and health-check configuration -├── pyproject.toml # Python project, Ruff, mypy, pytest, coverage -├── uv.lock # Reproducible Python dependency resolution -└── .github/workflows/ # CI quality gate and tagged release workflow +│ ├── ARCHITECTURE.md # runtime and deployment deep dive +│ ├── INITIATIVES.md # Codex project initiative/session records +│ ├── BUILD_SEQUENCE.md # implementation sequence and GitHub/Codecov setup +│ ├── RUNBOOK.md · CODEX_PROMPTS.md # demo procedure and prompt records +│ └── adr/ # Architecture Decision Records 001–010 +├── notebooks/ # local bounded capture/review workflow + results record +├── scripts/ # check_openai_spend.py (read-only spend reconciliation) +├── migrations/ # Alembic env + versions (schema and provenance revisions) +├── submission/ # Developer Tools handoff, checklist, Devpost, demo script +├── Dockerfile · docker-compose.yml # Railway image + local API/PostgreSQL/frontend +├── alembic.ini · Makefile · railway.json · codecov.yml # tooling and deploy config +├── pyproject.toml · uv.lock # Python project + reproducible dependency lock +├── .gitattributes # pins evidence JSON to LF for byte-exact manifests +└── .github/workflows/ # CI quality gate and tagged release workflow ``` --- @@ -444,7 +565,7 @@ drift/ push → Ruff → mypy → pytest (100% coverage gate) → Codecov → frontend build → docs hygiene ``` -The current local result is **148 tests passed and 100.00% backend coverage**. +The current local result is **150 tests passed and 100.00% backend coverage**. The enforceable floor is **100% for implemented code**, including branch-critical error paths. Explicit, documented live-pipeline boundaries remain visible while @@ -475,12 +596,16 @@ before any production-readiness claim. ## GitHub + Codecov Operations -GitHub `main`, the Railway API, and the Vercel frontend are published. -The remaining hosted verification operations are documented in -[docs/BUILD_SEQUENCE.md](docs/BUILD_SEQUENCE.md#github-and-codecov-setup): +GitHub `main`, the Railway API, and the Vercel frontend are published. The two +repository-operations steps documented in +[docs/BUILD_SEQUENCE.md](docs/BUILD_SEQUENCE.md#github-and-codecov-setup) are now +complete: -1. confirm the `pytest` upload in Codecov; and -2. enable branch protection requiring the CI quality gate. +1. the `pytest` upload is confirmed on Codecov — the repository and `flag=pytest` + coverage badges both resolve to 100%; and +2. `main` branch protection is enabled, requiring the five CI quality-gate checks + (Ruff lint, Mypy type check, Tests and coverage, Frontend build, Documentation + hygiene) to pass, with strict up-to-date merges. The earlier populated `v0.5.1` `/briefing` response was verified on 2026-07-15. On 2026-07-16, hosted `v0.6.1` health, `/briefing` (four reviewed Insights), @@ -517,13 +642,29 @@ Full decisions and sequencing live in [docs/adr/](docs/adr/), --- -## Disclaimer - -Fixture records are synthetic examples and are not live release analysis. DRIFT -does not certify compatibility, replace upstream release notes, or authorize -changes to production infrastructure. Any live insight must remain cited, -claim-type-labelled, confidence-labelled, model/audit-labelled, reviewed by a -human, and paired with a bounded `what_to_check` action. +## Trust Model + +Release notes are **untrusted input**, and DRIFT treats them that way. That +constraint is the product: it is what makes every answer inspectable instead of +a black-box verdict. + +- **Frozen source span.** Every factual claim carries an exact primary-source + excerpt with character offsets and a source SHA-256 hash, so reasoning is + always traceable back to what the release actually said. +- **Separate verifier pass.** A second, independently routed model call rejects + unsupported or misclassified claims — model-aided screening, not proof. +- **Human review gate.** Verifier-passed drafts stay private until a person + reviews the evidence and records notes; only then can a claim reach + `/briefing`, `/search`, or `/chat`. +- **Facts kept separate from interpretation.** Direct facts, inferences, and + recommended checks are labelled distinctly, and confidence plus the + model/audit label are always visible. + +Because of that boundary, DRIFT deliberately does **not** certify compatibility, +replace upstream release notes, or authorize changes to production +infrastructure. Fixture records are synthetic, clearly labelled examples and are +never presented as live release analysis. `breaking` and `security` are review +priorities, not automation triggers. > Built for the [OpenAI Build Week 2026](https://openai.com/) Developer Tools > track. Human review remains required for source fidelity, prompt iteration, diff --git a/SECURITY.md b/SECURITY.md index fe47385..fcc4167 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,8 @@ development baseline while the live pipeline is being implemented. | Version | Supported | | --- | --- | -| `0.7.0` | ✅ Current source and hosted application; public review notes are redacted and the frontend requests up to ten briefing records | +| `0.8.0` | ✅ Current source release; grounded frontend chat and verifiable synthetic fixture evidence, awaiting hosted deployment verification | +| `0.7.0` | Current verified hosted application; public review notes are redacted and the frontend requests up to ten briefing records | | `0.6.1` | Previously verified hosted application | | `0.5.1` | Historical hosted baseline | @@ -16,7 +17,9 @@ are explicitly operator-enabled and review-gated; the hosted gate returned no live evidence until the first human-reviewed capture. As of 2026-07-16 it serves four human-reviewed Insights from an eight-source capture (six verifier-passed drafts). Version `0.7.0` keeps human review notes database-only; its deployed -`/briefing` and `/openapi.json` boundaries were verified to omit them. +`/briefing` and `/openapi.json` boundaries were verified to omit them. Version +`0.8.0` keeps fixture evidence explicitly synthetic and locally verifiable; it +does not add an unverified hosted claim. ## Reporting a vulnerability diff --git a/assets/architecture/README.md b/assets/architecture/README.md index 9610af9..3bbbba3 100644 --- a/assets/architecture/README.md +++ b/assets/architecture/README.md @@ -5,25 +5,58 @@ architecture deep dive, slides, and the three-minute demo video. ## Files +### Detailed pipeline diagram (Mermaid — system of record) + +| File | Purpose | +| --- | --- | +| `arch-pipeline.mmd` | Canonical Mermaid source; edit this first | +| `arch-pipeline-light.svg` | Scalable light-theme render for README/docs | +| `arch-pipeline-dark.svg` | Scalable dark-theme render for README/docs | +| `arch-pipeline-light.png` | Light-theme raster for slides/video | +| `arch-pipeline-dark.png` | Dark-theme raster for slides/video | +| `arch-pipeline-*.config.json` | Mermaid theme and typography configuration | + +The Mermaid source is the authority for the pipeline. Do not hand-edit an SVG +or PNG to change the architecture; update the MMD and regenerate all four +renders together. + +### Presentation diagram (hand-authored — first-look visual) + | File | Purpose | | --- | --- | -| `architecture-diagram.mmd` | Canonical Mermaid source; edit this first | -| `architecture-diagram-light.svg` | Scalable light-theme render for README/docs | -| `architecture-diagram-dark.svg` | Scalable dark-theme render for README/docs | -| `architecture-diagram-light.png` | Light-theme raster for slides/video | -| `architecture-diagram-dark.png` | Dark-theme raster for slides/video | -| `architecture-diagram-*.config.json` | Mermaid theme and typography configuration | +| `build_arch.py` | Source of truth for the presentation diagram; emits both SVGs | +| `build_arch_raster.mjs` | Rasterizes the presentation SVGs to high-DPI PNG via `sharp` | +| `arch-light.svg` | Light-theme presentation diagram for README top / slides / video | +| `arch-dark.svg` | Dark-theme presentation diagram for README top / slides / video | +| `arch-light.png` | Light-theme presentation raster | +| `arch-dark.png` | Dark-theme presentation raster | -The Mermaid source is the authority. Do not hand-edit an SVG or PNG to change -the architecture; update the MMD and regenerate all four renders together. +The presentation diagram (`arch-*`) dramatizes the same six typed stages as a +first-look **trust boundary** story: untrusted feeds → quarantined machine +drafts → the human review gate → trusted, published briefing. It is a companion, +not a replacement: edit `build_arch.py` (never the SVG/PNG) and regenerate both +themes together. It shares its visual language — trust-zone colours, node +styling, and the gold review gate — with the `assets/brand/` banner. + +The presentation diagram keeps the "engineer also reviews" back-edge; the +Mermaid diagram deliberately omits it. That single edge (`Engineer → review +gate`) closes a cycle through `gate → store → Briefing → API → Engineer`, which +breaks Mermaid's left-to-right ranking and scrambles the zone order. The +hand-laid presentation diagram can show it safely; the auto-laid Mermaid stays +acyclic so the three trust zones read cleanly left to right. ## Diagram design rules - Keep the primary system pipeline horizontal and shallow: Engineer → API → fixture/live path → Scout → Synthesizer → claim extraction → verifier → review gate → Briefing. -- Use subgraphs for live-only behavior so the fixture path remains visually - obvious. +- Group the live stages into the three trust-zone subgraphs — untrusted input, + quarantine, trusted/published — so the human review gate reads as the only + bridge and the fixture path stays visually obvious. +- Keep the Mermaid graph acyclic: no edge may point back into an earlier stage + (e.g. `Engineer → review gate`), because a cycle breaks left-to-right ranking + and scrambles the zones. Show loop-closing edges only in the hand-laid + presentation diagram. - Keep model and persistence dependencies as dashed side paths rather than creating a second competing pipeline. - Use `
` labels for readable node wrapping; avoid paragraphs inside nodes. @@ -37,10 +70,19 @@ the architecture; update the MMD and regenerate all four renders together. From this directory, use the free and open-source Mermaid CLI: ```powershell -npx --yes -p @mermaid-js/mermaid-cli mmdc -i architecture-diagram.mmd -o architecture-diagram-dark.svg -b "#0b1020" -c architecture-diagram-dark.config.json --scale 3 -npx --yes -p @mermaid-js/mermaid-cli mmdc -i architecture-diagram.mmd -o architecture-diagram-light.svg -b "#f5f7fb" -c architecture-diagram-light.config.json --scale 3 -npx --yes -p @mermaid-js/mermaid-cli mmdc -i architecture-diagram.mmd -o architecture-diagram-dark.png -b "#0b1020" -c architecture-diagram-dark.config.json --scale 3 -npx --yes -p @mermaid-js/mermaid-cli mmdc -i architecture-diagram.mmd -o architecture-diagram-light.png -b "#f5f7fb" -c architecture-diagram-light.config.json --scale 3 +npx --yes -p @mermaid-js/mermaid-cli mmdc -i arch-pipeline.mmd -o arch-pipeline-dark.svg -b "#0b1020" -c arch-pipeline-dark.config.json --scale 3 +npx --yes -p @mermaid-js/mermaid-cli mmdc -i arch-pipeline.mmd -o arch-pipeline-light.svg -b "#f5f7fb" -c arch-pipeline-light.config.json --scale 3 +npx --yes -p @mermaid-js/mermaid-cli mmdc -i arch-pipeline.mmd -o arch-pipeline-dark.png -b "#0b1020" -c arch-pipeline-dark.config.json --scale 3 +npx --yes -p @mermaid-js/mermaid-cli mmdc -i arch-pipeline.mmd -o arch-pipeline-light.png -b "#f5f7fb" -c arch-pipeline-light.config.json --scale 3 +``` + +Then regenerate the presentation diagram (both themes, then the PNG rasters). The rasterizer +reuses the `sharp` install under `frontend/`, so run `npm --prefix ../../frontend ci` +first if `node_modules` is absent: + +```powershell +python build_arch.py +node build_arch_raster.mjs ``` No paid design, image-generation, or hosting service is required. The SVGs @@ -48,7 +90,7 @@ scale without pixelation; the PNGs are convenience exports for decks and video. ## Where the assets are used -- [Project README](../../README.md) — hero architecture visual and clickable +- [Project README](../../README.md) — presentation architecture visual and clickable light/dark renders; - [Architecture deep dive](../../docs/ARCHITECTURE.md) — visual-first system contract; diff --git a/assets/architecture/arch-dark.png b/assets/architecture/arch-dark.png new file mode 100644 index 0000000..c2d9797 Binary files /dev/null and b/assets/architecture/arch-dark.png differ diff --git a/assets/architecture/arch-dark.svg b/assets/architecture/arch-dark.svg new file mode 100644 index 0000000..8de2fb3 --- /dev/null +++ b/assets/architecture/arch-dark.svg @@ -0,0 +1 @@ +DRIFT · RELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTURERelease notes are untrusted input —a human reviewer is the only bridge to what an engineer sees.1humangate2modelpasses6typedstagesUNTRUSTED INPUTprimary release feedsQUARANTINE · MACHINEdrafts · nobody trusts yetTRUSTED · PUBLISHEDreviewed evidence onlyTRUST BOUNDARYGitHub Atom feedsPyTorch · vLLM · TensorRT · …Scoutnormalize + dedupe1raw_items · PostgresSynthesizerembed · cluster · classify2text-embedding-3-smallClaim extractorfacts · inferences · checks3Separate verifierreject unsupported claims4draft insights + frozen spansoffsets · SHA-256 · pgvectorQUARANTINEDGPT-5.6 tiersLuna · Terra · Sol5HUMANREVIEW GATEnotes requiredverifier-passeddrafts onlyHUMAN-GATEDreviewed insights + vectorsPostgres · pgvectorBriefingrank + retrieve6FastAPIbriefing · search · chatEngineerFixture modeno-key · deterministicsubstantive changesembedsubmitpublishedreviewswhat changed · why it matters · what to checkLEGENDSourceAgentStoreModelAPIHumanFixtureCited · Bounded · Inspectable — OpenAI Build Week 2026 · Developer Tools \ No newline at end of file diff --git a/assets/architecture/arch-light.png b/assets/architecture/arch-light.png new file mode 100644 index 0000000..45a9215 Binary files /dev/null and b/assets/architecture/arch-light.png differ diff --git a/assets/architecture/arch-light.svg b/assets/architecture/arch-light.svg new file mode 100644 index 0000000..0055f73 --- /dev/null +++ b/assets/architecture/arch-light.svg @@ -0,0 +1 @@ +DRIFT · RELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTURERelease notes are untrusted input —a human reviewer is the only bridge to what an engineer sees.1humangate2modelpasses6typedstagesUNTRUSTED INPUTprimary release feedsQUARANTINE · MACHINEdrafts · nobody trusts yetTRUSTED · PUBLISHEDreviewed evidence onlyTRUST BOUNDARYGitHub Atom feedsPyTorch · vLLM · TensorRT · …Scoutnormalize + dedupe1raw_items · PostgresSynthesizerembed · cluster · classify2text-embedding-3-smallClaim extractorfacts · inferences · checks3Separate verifierreject unsupported claims4draft insights + frozen spansoffsets · SHA-256 · pgvectorQUARANTINEDGPT-5.6 tiersLuna · Terra · Sol5HUMANREVIEW GATEnotes requiredverifier-passeddrafts onlyHUMAN-GATEDreviewed insights + vectorsPostgres · pgvectorBriefingrank + retrieve6FastAPIbriefing · search · chatEngineerFixture modeno-key · deterministicsubstantive changesembedsubmitpublishedreviewswhat changed · why it matters · what to checkLEGENDSourceAgentStoreModelAPIHumanFixtureCited · Bounded · Inspectable — OpenAI Build Week 2026 · Developer Tools \ No newline at end of file diff --git a/assets/architecture/architecture-diagram-dark.config.json b/assets/architecture/arch-pipeline-dark.config.json similarity index 100% rename from assets/architecture/architecture-diagram-dark.config.json rename to assets/architecture/arch-pipeline-dark.config.json diff --git a/assets/architecture/arch-pipeline-dark.png b/assets/architecture/arch-pipeline-dark.png new file mode 100644 index 0000000..c38d23b Binary files /dev/null and b/assets/architecture/arch-pipeline-dark.png differ diff --git a/assets/architecture/arch-pipeline-dark.svg b/assets/architecture/arch-pipeline-dark.svg new file mode 100644 index 0000000..9a1ccfb --- /dev/null +++ b/assets/architecture/arch-pipeline-dark.svg @@ -0,0 +1 @@ +

published

cited answer

no-key lane

submit

substantive changes

🟢 TRUSTED — reviewed, published

reviewed insights + vectors
Postgres / pgvector

⑥ Briefing
rank + retrieve

FastAPI
briefing · search · chat

🟠 QUARANTINE — machine drafts, nobody trusts yet

③ Claim extractor
facts · inferences · checks

④ Separate verifier
reject unsupported claims

draft insights + frozen spans
offsets · SHA-256 · pgvector

GPT-5.6 tiers
Luna · Terra · Sol

🔴 UNTRUSTED INPUT — primary release feeds

embed

GitHub Atom
release feeds

① Scout
normalize + dedupe

raw_items
Postgres

② Synthesizer
embed · cluster · classify

text-embedding-3-small

Engineer

Fixture mode
no-key · deterministic

⑤ HUMAN REVIEW GATE
notes required · verifier-passed only

\ No newline at end of file diff --git a/assets/architecture/architecture-diagram-light.config.json b/assets/architecture/arch-pipeline-light.config.json similarity index 100% rename from assets/architecture/architecture-diagram-light.config.json rename to assets/architecture/arch-pipeline-light.config.json diff --git a/assets/architecture/arch-pipeline-light.png b/assets/architecture/arch-pipeline-light.png new file mode 100644 index 0000000..bd3fc53 Binary files /dev/null and b/assets/architecture/arch-pipeline-light.png differ diff --git a/assets/architecture/arch-pipeline-light.svg b/assets/architecture/arch-pipeline-light.svg new file mode 100644 index 0000000..3e0184f --- /dev/null +++ b/assets/architecture/arch-pipeline-light.svg @@ -0,0 +1 @@ +

published

cited answer

no-key lane

submit

substantive changes

🟢 TRUSTED — reviewed, published

reviewed insights + vectors
Postgres / pgvector

⑥ Briefing
rank + retrieve

FastAPI
briefing · search · chat

🟠 QUARANTINE — machine drafts, nobody trusts yet

③ Claim extractor
facts · inferences · checks

④ Separate verifier
reject unsupported claims

draft insights + frozen spans
offsets · SHA-256 · pgvector

GPT-5.6 tiers
Luna · Terra · Sol

🔴 UNTRUSTED INPUT — primary release feeds

embed

GitHub Atom
release feeds

① Scout
normalize + dedupe

raw_items
Postgres

② Synthesizer
embed · cluster · classify

text-embedding-3-small

Engineer

Fixture mode
no-key · deterministic

⑤ HUMAN REVIEW GATE
notes required · verifier-passed only

\ No newline at end of file diff --git a/assets/architecture/arch-pipeline.mmd b/assets/architecture/arch-pipeline.mmd new file mode 100644 index 0000000..c8183b1 --- /dev/null +++ b/assets/architecture/arch-pipeline.mmd @@ -0,0 +1,54 @@ +flowchart LR + classDef source fill:#0f766e,stroke:#14b8a6,color:#ffffff + classDef agent fill:#312e81,stroke:#818cf8,color:#ffffff + classDef data fill:#164e63,stroke:#22d3ee,color:#ffffff + classDef model fill:#7c2d12,stroke:#fb923c,color:#ffffff + classDef api fill:#166534,stroke:#4ade80,color:#ffffff + classDef user fill:#7e22ce,stroke:#c084fc,color:#ffffff + classDef note fill:#475569,stroke:#94a3b8,color:#ffffff + classDef gate fill:#0f3f2f,stroke:#fbbf24,color:#fef9c3,stroke-width:3px + + U(["Engineer"]):::user + FIX["Fixture mode
no-key · deterministic"]:::note + + subgraph UNTRUSTED["🔴 UNTRUSTED INPUT — primary release feeds"] + direction TB + FEEDS["GitHub Atom
release feeds"]:::source + SCOUT["① Scout
normalize + dedupe"]:::agent + RAW[("raw_items
Postgres")]:::data + SYNTH["② Synthesizer
embed · cluster · classify"]:::agent + EMB["text-embedding-3-small"]:::model + FEEDS --> SCOUT --> RAW --> SYNTH + SYNTH -.->|embed| EMB + end + + subgraph QUARANTINE["🟠 QUARANTINE — machine drafts, nobody trusts yet"] + direction TB + INSIGHT["③ Claim extractor
facts · inferences · checks"]:::agent + VERIFY["④ Separate verifier
reject unsupported claims"]:::agent + DRAFT[("draft insights + frozen spans
offsets · SHA-256 · pgvector")]:::data + LLM["GPT-5.6 tiers
Luna · Terra · Sol"]:::model + INSIGHT --> VERIFY --> DRAFT + INSIGHT -.-> LLM + VERIFY -.-> LLM + end + + GATE{{"⑤ HUMAN REVIEW GATE
notes required · verifier-passed only"}}:::gate + + subgraph TRUSTED["🟢 TRUSTED — reviewed, published"] + direction TB + DB[("reviewed insights + vectors
Postgres / pgvector")]:::data + BRIEF["⑥ Briefing
rank + retrieve"]:::agent + API["FastAPI
briefing · search · chat"]:::api + DB --> BRIEF --> API + end + + SYNTH ==>|substantive changes| INSIGHT + DRAFT ==>|submit| GATE + GATE ==>|published| DB + API ==>|cited answer| U + FIX -.->|no-key lane| API + + style UNTRUSTED fill:transparent,stroke:#f43f5e,stroke-width:2px,stroke-dasharray:6 4 + style QUARANTINE fill:transparent,stroke:#f59e0b,stroke-width:2px,stroke-dasharray:6 4 + style TRUSTED fill:transparent,stroke:#10b981,stroke-width:2px,stroke-dasharray:6 4 diff --git a/assets/architecture/architecture-diagram-dark.png b/assets/architecture/architecture-diagram-dark.png deleted file mode 100644 index 454c8ec..0000000 Binary files a/assets/architecture/architecture-diagram-dark.png and /dev/null differ diff --git a/assets/architecture/architecture-diagram-dark.svg b/assets/architecture/architecture-diagram-dark.svg deleted file mode 100644 index db7065a..0000000 --- a/assets/architecture/architecture-diagram-dark.svg +++ /dev/null @@ -1 +0,0 @@ -

Live release-intelligence pipeline

GitHub Atom
release feeds

① Scout
normalize + dedupe

raw_items
Postgres

② Synthesizer
embed + cluster + classify

③ Claim extractor
facts · inferences · checks

④ Separate verifier
reject unsupported claims

draft insights + frozen spans
Postgres / pgvector

⑤ Human review gate
notes required

reviewed insights + vectors
Postgres / pgvector

⑥ Briefing
rank + retrieve

text-embedding-3-small

GPT-5.6 tiers
Luna · Terra · Sol

Engineer

FastAPI
briefing · search · chat

Fixture mode
insights.json

\ No newline at end of file diff --git a/assets/architecture/architecture-diagram-light.png b/assets/architecture/architecture-diagram-light.png deleted file mode 100644 index 8c213a0..0000000 Binary files a/assets/architecture/architecture-diagram-light.png and /dev/null differ diff --git a/assets/architecture/architecture-diagram-light.svg b/assets/architecture/architecture-diagram-light.svg deleted file mode 100644 index 390daba..0000000 --- a/assets/architecture/architecture-diagram-light.svg +++ /dev/null @@ -1 +0,0 @@ -

Live release-intelligence pipeline

GitHub Atom
release feeds

① Scout
normalize + dedupe

raw_items
Postgres

② Synthesizer
embed + cluster + classify

③ Claim extractor
facts · inferences · checks

④ Separate verifier
reject unsupported claims

draft insights + frozen spans
Postgres / pgvector

⑤ Human review gate
notes required

reviewed insights + vectors
Postgres / pgvector

⑥ Briefing
rank + retrieve

text-embedding-3-small

GPT-5.6 tiers
Luna · Terra · Sol

Engineer

FastAPI
briefing · search · chat

Fixture mode
insights.json

\ No newline at end of file diff --git a/assets/architecture/architecture-diagram.mmd b/assets/architecture/architecture-diagram.mmd deleted file mode 100644 index 43f5392..0000000 --- a/assets/architecture/architecture-diagram.mmd +++ /dev/null @@ -1,41 +0,0 @@ -flowchart LR - classDef source fill:#0f766e,stroke:#14b8a6,color:#ffffff - classDef agent fill:#312e81,stroke:#818cf8,color:#ffffff - classDef data fill:#164e63,stroke:#22d3ee,color:#ffffff - classDef model fill:#7c2d12,stroke:#fb923c,color:#ffffff - classDef api fill:#166534,stroke:#4ade80,color:#ffffff - classDef user fill:#7e22ce,stroke:#c084fc,color:#ffffff - classDef note fill:#475569,stroke:#94a3b8,color:#ffffff - - U(["Engineer"]):::user - API["FastAPI
briefing · search · chat"]:::api - FIX["Fixture mode
insights.json"]:::note - - subgraph live["Live release-intelligence pipeline"] - direction LR - FEEDS["GitHub Atom
release feeds"]:::source - SCOUT["① Scout
normalize + dedupe"]:::agent - RAW[("raw_items
Postgres")]:::data - SYNTH["② Synthesizer
embed + cluster + classify"]:::agent - EMB["text-embedding-3-small"]:::model - INSIGHT["③ Claim extractor
facts · inferences · checks"]:::agent - VERIFY["④ Separate verifier
reject unsupported claims"]:::agent - LLM["GPT-5.6 tiers
Luna · Terra · Sol"]:::model - DRAFT[("draft insights + frozen spans
Postgres / pgvector")]:::data - REVIEW["⑤ Human review gate
notes required"]:::agent - DB[("reviewed insights + vectors
Postgres / pgvector")]:::data - BRIEF["⑥ Briefing
rank + retrieve"]:::agent - - FEEDS --> SCOUT --> RAW --> SYNTH --> INSIGHT --> VERIFY --> DRAFT --> REVIEW --> DB --> BRIEF - SYNTH -.-> EMB - INSIGHT -.-> LLM - VERIFY -.-> LLM - end - - U --> API - U --> REVIEW - API --> FIX - API --> BRIEF - FIX -.-> API - - style live fill:transparent,stroke:#38bdf8,stroke-width:2px,stroke-dasharray:6 3 diff --git a/assets/architecture/build_arch.py b/assets/architecture/build_arch.py new file mode 100644 index 0000000..3d64301 --- /dev/null +++ b/assets/architecture/build_arch.py @@ -0,0 +1,598 @@ +#!/usr/bin/env python3 +"""Generate the DRIFT presentation architecture diagram (dark + light SVG). + +This is a hand-authored, presentation-grade companion to the canonical +Mermaid source (`arch-pipeline.mmd`). The Mermaid file remains the maintainable +system-of-record; this presentation diagram (`arch-*.svg`) dramatizes the same +first-look "trust boundary" story for slides, the demo video, and the README +top. + +One source of truth, two themes. Run: + + python build_arch.py # writes both SVGs + # then rasterize to PNG (needs frontend/ deps): + node build_arch_raster.mjs + +Nothing is hand-edited in the SVG output; change this file and regenerate. +""" + +from __future__ import annotations + +import html +from dataclasses import dataclass + +W, H = 1712, 940 + + +# --------------------------------------------------------------------------- # +# Theme +# --------------------------------------------------------------------------- # +@dataclass(frozen=True) +class Theme: + name: str + bg0: str + bg1: str + grid: str + panel_stroke: str + ink: str # primary text on background + ink_soft: str # secondary text on background + line: str # pipeline connector + dep: str # dashed dependency connector + # per-kind node styling: (fill, stroke, text) + kinds: dict + zone_untrusted: str + zone_quarantine: str + zone_trusted: str + gate_fill0: str + gate_fill1: str + gate_stroke: str + gate_ink: str + boundary: str + # DRIFT signature gradient (teal → indigo), theme-adapted. Kept identical + # to assets/brand/build_banner.py so brand and diagram read as one system. + brand0: str = "#2dd4bf" + brand1: str = "#818cf8" + + +DARK = Theme( + name="dark", + bg0="#0b1020", + bg1="#060912", + grid="#1b2438", + panel_stroke="#233047", + ink="#f8fafc", + ink_soft="#94a3b8", + line="#7c8aa5", + dep="#5b6b86", + kinds={ + "source": ("#0f766e", "#2dd4bf", "#ecfeff"), + "agent": ("#312e81", "#a5b4fc", "#eef2ff"), + "data": ("#164e63", "#38d9f0", "#ecfeff"), + "model": ("#7c2d12", "#fb923c", "#fff7ed"), + "api": ("#166534", "#4ade80", "#f0fdf4"), + "user": ("#6b21a8", "#d8b4fe", "#faf5ff"), + "note": ("#33415560", "#7c8aa5", "#cbd5e1"), + }, + zone_untrusted="#f43f5e", + zone_quarantine="#f59e0b", + zone_trusted="#10b981", + gate_fill0="#0f3f2f", + gate_fill1="#12261f", + gate_stroke="#fbbf24", + gate_ink="#fef9c3", + boundary="#fbbf24", +) + +LIGHT = Theme( + name="light", + bg0="#f6f8fc", + bg1="#e9eef7", + grid="#dbe3ef", + panel_stroke="#cbd5e1", + ink="#0f172a", + ink_soft="#64748b", + line="#7688a1", + dep="#94a3b8", + kinds={ + "source": ("#d5f5f0", "#0d9488", "#0f3d38"), + "agent": ("#e5e7ff", "#4f46e5", "#1e1b4b"), + "data": ("#d4f2fb", "#0891b2", "#0c3a47"), + "model": ("#ffe9d6", "#ea580c", "#7c2d12"), + "api": ("#d8f5e2", "#16a34a", "#14532d"), + "user": ("#efe1fb", "#9333ea", "#4a1478"), + "note": ("#eef2f8", "#94a3b8", "#475569"), + }, + zone_untrusted="#e11d48", + zone_quarantine="#d97706", + zone_trusted="#059669", + gate_fill0="#ecfdf5", + gate_fill1="#d1fae5", + gate_stroke="#b45309", + gate_ink="#7c2d12", + boundary="#b45309", + brand0="#0d9488", + brand1="#4f46e5", +) + + +def esc(s: str) -> str: + return html.escape(s, quote=True) + + +# --------------------------------------------------------------------------- # +# Primitives +# --------------------------------------------------------------------------- # +FONT = "Inter, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif" + + +def text(x, y, s, *, size, fill, weight=400, anchor="start", spacing=None, + opacity=1.0): + ls = f' letter-spacing="{spacing}"' if spacing is not None else "" + op = f' opacity="{opacity}"' if opacity != 1.0 else "" + return ( + f'{esc(s)}' + ) + + +def rrect(x, y, w, h, r, *, fill, stroke="none", sw=0, opacity=1.0, extra=""): + st = f' stroke="{stroke}" stroke-width="{sw}"' if stroke != "none" else "" + op = f' opacity="{opacity}"' if opacity != 1.0 else "" + return ( + f'' + ) + + +class Node: + def __init__(self, cx, cy, w, h, kind, title, subtitle=None, + badge=None, tag=None, tag_color=None): + self.cx, self.cy, self.w, self.h = cx, cy, w, h + self.kind = kind + self.title = title + self.subtitle = subtitle + self.badge = badge + self.tag = tag + self.tag_color = tag_color + + @property + def x(self): + return self.cx - self.w / 2 + + @property + def y(self): + return self.cy - self.h / 2 + + def top(self): + return (self.cx, self.y) + + def bottom(self): + return (self.cx, self.y + self.h) + + def left(self): + return (self.x, self.cy) + + def right(self): + return (self.x + self.w, self.cy) + + def render(self, t: Theme): + fill, stroke, ink = t.kinds[self.kind] + parts = [ + f'', + rrect(self.x, self.y, self.w, self.h, 14, fill=fill, + stroke=stroke, sw=1.6), + "", + ] + # subtle top sheen + parts.append( + rrect(self.x + 1, self.y + 1, self.w - 2, self.h * 0.5, 13, + fill="url(#sheen)", opacity=0.12) + ) + tx = self.cx + if self.subtitle: + parts.append(text(tx, self.cy - 4, self.title, size=17.5, + fill=ink, weight=700, anchor="middle")) + parts.append(text(tx, self.cy + 16, self.subtitle, size=12.5, + fill=ink, weight=400, anchor="middle", + opacity=0.82)) + else: + parts.append(text(tx, self.cy + 6, self.title, size=17.5, + fill=ink, weight=700, anchor="middle")) + # badge (numbered stage) + if self.badge is not None: + bx, by = self.x + 20, self.y + 20 + parts.append( + f'' + ) + parts.append(text(bx, by + 5, str(self.badge), size=14, + fill=fill, weight=800, anchor="middle")) + # tag pill (e.g. QUARANTINED) + if self.tag: + tc = self.tag_color or stroke + tw = 9 + len(self.tag) * 6.3 + pillx = self.x + self.w - tw - 12 + pilly = self.y + self.h - 22 + parts.append(rrect(pillx, pilly, tw, 17, 8, fill=tc, opacity=0.9)) + parts.append(text(pillx + tw / 2, pilly + 12.5, self.tag, size=10, + fill="#0b1020" if t.name == "dark" else "#ffffff", + weight=800, anchor="middle", spacing="0.06em")) + return "".join(parts) + + +def arrow(p0, p1, *, color, marker, dashed=False, width=2.4, label=None, + t: Theme = DARK, label_dy=-8): + dash = ' stroke-dasharray="6 5"' if dashed else "" + x0, y0 = p0 + x1, y1 = p1 + line = ( + f'' + ) + out = [line] + if label: + mx, my = (x0 + x1) / 2, (y0 + y1) / 2 + label_dy + lw = 12 + len(label) * 6.0 + out.append(rrect(mx - lw / 2, my - 13, lw, 18, 9, fill=t.bg0, + opacity=0.92)) + out.append(text(mx, my, label, size=11.5, fill=t.ink_soft, + weight=600, anchor="middle")) + return "".join(out) + + +def elbow(p0, p1, midx, *, color, marker, dashed=False, width=2.4, + label=None, t: Theme = DARK): + """Orthogonal connector: horizontal to midx, vertical, into p1.""" + x0, y0 = p0 + x1, y1 = p1 + dash = ' stroke-dasharray="6 5"' if dashed else "" + path = ( + f'' + ) + out = [path] + if label: + my = (y0 + y1) / 2 + lw = 12 + len(label) * 6.0 + out.append(rrect(midx - lw / 2, my - 9, lw, 18, 9, fill=t.bg0, + opacity=0.92)) + out.append(text(midx, my + 4.5, label, size=11.5, fill=t.ink_soft, + weight=600, anchor="middle")) + return "".join(out) + + +def zone_panel(x, y, w, h, *, tint, header, sub, t: Theme): + parts = [ + rrect(x, y, w, h, 20, fill=tint, opacity=0.07), + rrect(x, y, w, h, 20, fill="none", stroke=tint, sw=1.4, opacity=0.55, + extra=' stroke-dasharray="2 6"'), + ] + # header chip + chip_w = 14 + len(header) * 8.6 + parts.append(rrect(x + 18, y - 15, chip_w, 30, 15, fill=tint, + opacity=0.92, extra=' filter="url(#soft)"')) + parts.append(text(x + 18 + chip_w / 2, y + 5, header, size=13.5, + fill="#0b1020" if t.name == "dark" else "#ffffff", + weight=800, anchor="middle", spacing="0.08em")) + # sub caption, bottom-left inside the panel + parts.append(text(x + 22, y + h - 20, sub, size=11.5, fill=t.ink_soft, + weight=500, anchor="start", opacity=0.85)) + return "".join(parts) + + +def person_glyph(cx, cy, color): + return ( + f'' + f'' + f'' + ) + + +def lock_glyph(cx, cy, color, ink): + return ( + f'' + f'' + f'' + f'' + f'' + ) + + +# --------------------------------------------------------------------------- # +# Compose +# --------------------------------------------------------------------------- # +def build(t: Theme) -> str: + S = [] + S.append( + f'' + ) + # ---- defs ---- + S.append("") + S.append( + f'' + f'' + f'' + ) + S.append( + '' + '' + '' + '' + ) + S.append( + f'' + f'' + f'' + ) + # DRIFT signature gradient (teal → indigo) + S.append( + f'' + f'' + f'' + ) + S.append( + f'' + f'' + f'' + ) + # soft drop shadow + S.append( + '' + '' + ) + # gate glow + S.append( + f'' + f'' + ) + for mid, col in (("ah", t.line), ("ahflow", t.zone_trusted), + ("ahdash", t.dep), ("ahgold", t.gate_stroke)): + S.append( + f'' + f'' + ) + S.append("") + + # ---- background ---- + S.append(f'') + # faint dot grid + dots = [''] + for gy in range(150, H - 60, 34): + for gx in range(40, W - 20, 34): + dots.append( + f'' + ) + dots.append("") + S.append("".join(dots)) + + # ---- header ---- + S.append(text(52, 52, "DRIFT · RELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTURE", + size=14, fill="url(#word)", weight=800, spacing="0.16em")) + S.append(rrect(52, 62, 232, 3, 1.5, fill="url(#rule)")) + S.append(text(52, 92, "Release notes are untrusted input —", + size=29, fill=t.ink, weight=800)) + S.append(text(52, 126, "a human reviewer is the only bridge to what an engineer sees.", + size=29, fill=t.ink_soft, weight=500)) + # right-side stat pills + pills = [("6", "typed stages"), ("2", "model passes"), ("1", "human gate")] + px = W - 52 + for num, lab in reversed(pills): + pw = 30 + len(lab) * 7.2 + px -= pw + S.append(rrect(px, 62, pw, 40, 12, fill=t.kinds["agent"][0], + stroke=t.kinds["agent"][1], sw=1.3, opacity=0.95)) + S.append(text(px + 20, 88, num, size=20, fill=t.kinds["agent"][1], + weight=800, anchor="middle")) + S.append(text(px + 36, 79, lab.split()[0], size=11, fill=t.ink, + weight=600)) + S.append(text(px + 36, 93, lab.split()[1] if len(lab.split()) > 1 else "", + size=11, fill=t.ink_soft, weight=500)) + px -= 12 + + # ---- zone panels ---- + zy, zh = 176, 604 + zaw = 408 # untrusted + quarantine width (widened to balance trusted) + za_x = 44 + zb_x = 488 + gate_x, gate_w = 944, 150 + zc_x = 1136 + zc_w = W - zc_x - 44 + + S.append(zone_panel(za_x, zy, zaw, zh, tint=t.zone_untrusted, + header="UNTRUSTED INPUT", sub="primary release feeds", + t=t)) + S.append(zone_panel(zb_x, zy, zaw, zh, tint=t.zone_quarantine, + header="QUARANTINE · MACHINE", + sub="drafts · nobody trusts yet", t=t)) + S.append(zone_panel(zc_x, zy, zc_w, zh, tint=t.zone_trusted, + header="TRUSTED · PUBLISHED", + sub="reviewed evidence only", t=t)) + + # ---- trust boundary line at gate right edge ---- + bx = gate_x + gate_w + 20 + S.append( + f'' + ) + S.append( + f'' + + text(0, 0, "TRUST BOUNDARY", size=11, fill=t.boundary, weight=800, + spacing="0.22em") + + "" + ) + + # ---- Zone A nodes ---- + caz = za_x + zaw / 2 + nA1 = Node(caz, 236, zaw - 56, 66, "source", "GitHub Atom feeds", + "PyTorch · vLLM · TensorRT · …") + nA2 = Node(caz, 344, zaw - 56, 66, "agent", "Scout", + "normalize + dedupe", badge=1) + nA3 = Node(caz, 444, zaw - 56, 56, "data", "raw_items · Postgres") + nA4 = Node(caz, 552, zaw - 56, 66, "agent", "Synthesizer", + "embed · cluster · classify", badge=2) + nA5 = Node(caz, 652, zaw - 72, 48, "model", "text-embedding-3-small") + for n in (nA1, nA2, nA3, nA4, nA5): + S.append(n.render(t)) + + # ---- Zone B nodes ---- + cbz = zb_x + zaw / 2 + nB1 = Node(cbz, 236, zaw - 56, 66, "agent", "Claim extractor", + "facts · inferences · checks", badge=3) + nB2 = Node(cbz, 344, zaw - 56, 66, "agent", "Separate verifier", + "reject unsupported claims", badge=4) + nB3 = Node(cbz, 452, zaw - 56, 74, "data", "draft insights + frozen spans", + "offsets · SHA-256 · pgvector", tag="QUARANTINED", + tag_color=t.zone_quarantine) + for n in (nB1, nB2, nB3): + S.append(n.render(t)) + # model dependency (LLM tiers used by claim extraction + verification) + nBm = Node(cbz, 606, zaw - 72, 54, "model", "GPT-5.6 tiers", + "Luna · Terra · Sol") + S.append(nBm.render(t)) + + # ---- Gate (focal element) ---- + gcx = gate_x + gate_w / 2 + gy0, gy1 = 224, 566 + S.append( + f'' + + rrect(gate_x, gy0, gate_w, gy1 - gy0, 20, fill="url(#gate)", + stroke=t.gate_stroke, sw=2.4) + + "" + ) + S.append(rrect(gate_x + 2, gy0 + 2, gate_w - 4, (gy1 - gy0) * 0.4, 18, + fill="url(#sheen)", opacity=0.10)) + # badge 5 + S.append(f'') + S.append(text(gcx, gy0 + 40, "5", size=20, fill=t.gate_fill1, + weight=800, anchor="middle")) + S.append(person_glyph(gcx, gy0 + 92, t.gate_ink)) + S.append(text(gcx, gy0 + 138, "HUMAN", size=17, fill=t.gate_ink, + weight=800, anchor="middle", spacing="0.04em")) + S.append(text(gcx, gy0 + 160, "REVIEW GATE", size=17, fill=t.gate_ink, + weight=800, anchor="middle", spacing="0.02em")) + S.append(text(gcx, gy0 + 186, "notes required", size=12.5, + fill=t.gate_ink, weight=500, anchor="middle", opacity=0.85)) + S.append(lock_glyph(gcx, gy0 + 232, t.gate_stroke, t.gate_fill1)) + S.append(text(gcx, gy0 + 286, "verifier-passed", size=11.5, + fill=t.gate_ink, weight=500, anchor="middle", opacity=0.8)) + S.append(text(gcx, gy0 + 302, "drafts only", size=11.5, + fill=t.gate_ink, weight=500, anchor="middle", opacity=0.8)) + # HUMAN-GATED brand badge directly under the gate + hg, hgink = "HUMAN-GATED", "#04231a" if t.name == "dark" else "#ffffff" + hgw = 26 + len(hg) * 8.6 + S.append(rrect(gcx - hgw / 2, gy1 + 16, hgw, 30, 15, fill=t.zone_trusted, + extra=' filter="url(#soft)"')) + S.append(text(gcx, gy1 + 36, hg, size=13.5, fill=hgink, weight=800, + anchor="middle", spacing="0.08em")) + + # ---- Zone C nodes ---- + ccz = zc_x + zc_w / 2 + nC1 = Node(ccz, 236, zc_w - 64, 66, "data", "reviewed insights + vectors", + "Postgres · pgvector") + nC2 = Node(ccz, 344, zc_w - 64, 66, "agent", "Briefing", + "rank + retrieve", badge=6) + nC3 = Node(ccz, 452, zc_w - 64, 66, "api", "FastAPI", + "briefing · search · chat") + nEng = Node(ccz - 96, 566, 168, 56, "user", "Engineer") + nFix = Node(ccz + 104, 566, 196, 56, "note", "Fixture mode", + "no-key · deterministic") + for n in (nC1, nC2, nC3, nEng, nFix): + S.append(n.render(t)) + + # ---- connectors ---- + a = lambda p0, p1, **k: S.append(arrow(p0, p1, t=t, **k)) + e = lambda p0, p1, mx, **k: S.append(elbow(p0, p1, mx, t=t, **k)) + + # Zone A vertical spine + a(nA1.bottom(), (nA2.cx, nA2.y), color=t.line, marker="ah") + a(nA2.bottom(), (nA3.cx, nA3.y), color=t.line, marker="ah") + a(nA3.bottom(), (nA4.cx, nA4.y), color=t.line, marker="ah") + # A -> B handoff + e(nA4.right(), nB1.left(), (zb_x + za_x + zaw) / 2, color=t.line, + marker="ah", label="substantive changes") + # Zone B vertical spine + a(nB1.bottom(), (nB2.cx, nB2.y), color=t.line, marker="ah") + a(nB2.bottom(), (nB3.cx, nB3.y), color=t.line, marker="ah") + # model deps (dashed): Synthesizer embeds; claim/verify call the LLM tiers + a(nA4.bottom(), (nA5.cx, nA5.y), color=t.dep, marker="ahdash", + dashed=True, width=1.8, label="embed", label_dy=0) + railx = zb_x + 14 + e(nB1.left(), (nBm.x, nBm.cy - 8), railx, color=t.dep, marker="ahdash", + dashed=True, width=1.8) + e(nB2.left(), (nBm.x, nBm.cy + 8), railx, color=t.dep, marker="ahdash", + dashed=True, width=1.8) + # B(drafts) -> Gate + a(nB3.right(), (gate_x, 452), color=t.gate_stroke, marker="ahgold", + width=2.6, label="submit") + # Gate -> Zone C (published) + e((gate_x + gate_w, 300), nC1.left(), (gate_x + gate_w + zc_x) / 2 + 6, + color=t.zone_trusted, marker="ahflow", width=2.8, label="published") + # Zone C vertical spine + a(nC1.bottom(), (nC2.cx, nC2.y), color=t.line, marker="ah") + a(nC2.bottom(), (nC3.cx, nC3.y), color=t.line, marker="ah") + # FastAPI -> Engineer (answer) + e(nC3.bottom(), nEng.top(), nEng.cx, color=t.zone_trusted, + marker="ahflow", width=2.4) + # Fixture -> FastAPI + e(nFix.top(), (nC3.cx + 60, nC3.y + nC3.h), nFix.cx, color=t.ink_soft, + marker="ah", dashed=True, width=2.0) + # Engineer reviews (dashed up to gate) + a((nEng.x, nEng.cy), (gate_x + gate_w + 8, gy1 - 30), color=t.dep, + marker="ahdash", dashed=True, width=1.8, label="reviews", + label_dy=-14) + + # answer caption near Engineer + S.append(text(nEng.cx, nEng.cy + 52, + "what changed · why it matters · what to check", + size=11.5, fill=t.ink_soft, weight=500, anchor="middle")) + + # ---- legend / footer ---- + ly = H - 44 + legend = [("source", "Source"), ("agent", "Agent"), ("data", "Store"), + ("model", "Model"), ("api", "API"), ("user", "Human"), + ("note", "Fixture")] + lx = 52 + S.append(text(lx, ly - 1, "LEGEND", size=10.5, fill=t.ink_soft, + weight=700, spacing="0.14em")) + lx += 66 + for kind, lab in legend: + fill, stroke, _ = t.kinds[kind] + S.append(rrect(lx, ly - 12, 15, 15, 4, fill=fill, stroke=stroke, + sw=1.4)) + S.append(text(lx + 22, ly, lab, size=12, fill=t.ink_soft, weight=500)) + lx += 34 + len(lab) * 7.4 + S.append(text(W - 52, ly, + "Cited · Bounded · Inspectable — OpenAI Build Week 2026 · Developer Tools", + size=12, fill=t.ink_soft, weight=600, anchor="end")) + + S.append("") + return "".join(S) + + +def main() -> None: + import pathlib + here = pathlib.Path(__file__).parent + for t, fname in ((DARK, "arch-dark.svg"), + (LIGHT, "arch-light.svg")): + (here / fname).write_text(build(t), encoding="utf-8") + print(f"wrote {fname}") + + +if __name__ == "__main__": + main() diff --git a/assets/architecture/build_arch_raster.mjs b/assets/architecture/build_arch_raster.mjs new file mode 100644 index 0000000..0f69224 --- /dev/null +++ b/assets/architecture/build_arch_raster.mjs @@ -0,0 +1,22 @@ +// Rasterize the architecture presentation SVGs to high-DPI PNG using the frontend's +// sharp install. Run from assets/architecture/: node build_arch_raster.mjs +import { readFileSync, writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; + +const require = createRequire("file://" + process.cwd() + "/../../frontend/"); +const sharp = require("sharp"); + +const SCALE = 2; // 1712x940 -> 3424x1880 +const jobs = [ + ["arch-dark.svg", "arch-dark.png"], + ["arch-light.svg", "arch-light.png"], +]; + +for (const [src, out] of jobs) { + const svg = readFileSync(src); + const png = await sharp(svg, { density: 72 * SCALE }) + .png() + .toBuffer(); + writeFileSync(out, png); + console.log(`wrote ${out}`); +} diff --git a/assets/brand/README.md b/assets/brand/README.md index 426dec0..69dc028 100644 --- a/assets/brand/README.md +++ b/assets/brand/README.md @@ -1,12 +1,56 @@ # DRIFT brand assets `drift-banner-dark.svg` and `drift-banner-light.svg` are the canonical -theme-aware DRIFT hero banners. They deliberately tell the same source-neutral -story: a primary release travels through a GPU compute lattice into cited -evidence, human review, and a bounded engineering check. +theme-aware DRIFT brand banners. They share one visual language with the +architecture presentation diagram (`assets/architecture/`): the same trust-zone palette, +rounded node styling, gold human-review gate, dot-grid field, and Inter +typography. The right-side **evidence path** card distills the architecture +story to its core — an untrusted primary release crosses a human gate to become +a cited, bounded briefing — over a subtle GPU compute-lattice backdrop (traces, +vias, and a PCB edge-connector) that ties the brand to the infrastructure it +serves. -Use the dark/light pair in documentation through a `` element. The -Next.js frontend loads the canonical files through FastAPI's `/brand/dark.svg` -and `/brand/light.svg` routes; do not copy, derive, or commit banner SVGs under +## DRIFT palette (locked) + +One palette drives the banner, the presentation diagram, and the Mermaid pipeline +so they read as one system. It is anchored on what DRIFT does — turning raw +release signal into reviewed, trusted intelligence — not on any vendor's colours. + +| Role | Dark | Light | Where | +| --- | --- | --- | --- | +| **Signature gradient** (teal → indigo) | `#2dd4bf` → `#818cf8` | `#0d9488` → `#4f46e5` | wordmark, eyebrows, accent rules | +| Untrusted | `#f43f5e` | `#e11d48` | zone / source dot | +| Quarantine | `#f59e0b` | `#d97706` | zone / model accent | +| Trusted | `#10b981` | `#059669` | zone / API / "reviewed" | +| Human gate | `#fbbf24` | `#b45309` | the review gate only | + +The signature gradient's endpoints are the diagram's own **source-teal → +agent-indigo** node hues, so the brand mark is literally sampled from the +pipeline it describes. The semantic node colours (source, agent, store, model, +API, human, fixture) stay distinct in the diagrams because they carry meaning; +the gradient is the brand identity layered on top. Keep the values in +`build_banner.py` and `assets/architecture/build_arch.py` in sync. + +## Files + +| File | Purpose | +| --- | --- | +| `build_banner.py` | Source of truth; emits both banner SVGs | +| `build_banner_raster.mjs` | Rasterizes the banners to PNG via `sharp` | +| `drift-banner-dark.svg` / `-light.svg` | Canonical API-served banners | +| `drift-banner-dark.png` / `-light.png` | Convenience rasters for decks/video | + +Edit `build_banner.py` (never the SVG/PNG) and regenerate both themes together: + +```powershell +python build_banner.py +node build_banner_raster.mjs # optional PNGs; needs ../../frontend deps +``` + +The SVG **filenames are fixed**: `backend/main.py` serves them at +`/brand/{theme}.svg` and Docker bakes this directory into the API image — do not +rename the SVG outputs. Use the dark/light pair in documentation through a +`` element. The Next.js frontend loads the canonical files through the +FastAPI routes; do not copy, derive, or commit banner SVGs under `frontend/public/`. The FastAPI service uses the same routes for its Swagger -documentation. Docker copies this directory into the API image. +documentation. diff --git a/assets/brand/build_banner.py b/assets/brand/build_banner.py new file mode 100644 index 0000000..9bb1ae3 --- /dev/null +++ b/assets/brand/build_banner.py @@ -0,0 +1,348 @@ +#!/usr/bin/env python3 +"""Generate the canonical DRIFT brand banner (dark + light SVG). + +The banner shares one visual language with the architecture presentation diagram +(`assets/architecture/build_arch.py`): the same trust-zone palette, rounded +node styling with sheen + soft shadow, the gold human-review gate, the dot-grid +field, and Inter typography. The right-side "evidence path" card distills the +architecture diagram's story to its core: an untrusted primary release crosses a +human gate to become a cited, bounded briefing. + +Filenames are fixed: `backend/main.py` serves `drift-banner-dark.svg` and +`drift-banner-light.svg` at `/brand/{theme}.svg`, and Docker bakes this +directory into the API image. Do not rename the SVG outputs. + + python build_banner.py # writes both SVGs + node build_banner_raster.mjs # optional PNG rasters (needs frontend/ deps) +""" + +from __future__ import annotations + +import html +from dataclasses import dataclass + +W, H = 1600, 520 +FONT = "Inter, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif" + + +# Palette mirrors assets/architecture/build_arch.py so the banner and the +# architecture diagram read as one system. +@dataclass(frozen=True) +class Theme: + name: str + bg0: str + bg1: str + grid: str + ink: str + ink_soft: str + panel: str + panel_stroke: str + line: str + emerald: str + rose: str + amber: str + wordmark0: str + wordmark1: str + source: tuple + api: tuple + gate_fill0: str + gate_fill1: str + gate_stroke: str + gate_ink: str + pill_ink: str + + +DARK = Theme( + name="dark", bg0="#0b1020", bg1="#060912", grid="#1b2438", + ink="#f8fafc", ink_soft="#94a3b8", panel="#0e1526", panel_stroke="#233047", + line="#7c8aa5", emerald="#10b981", rose="#f43f5e", amber="#f59e0b", + wordmark0="#2dd4bf", wordmark1="#818cf8", + source=("#0f766e", "#2dd4bf", "#ecfeff"), + api=("#166534", "#4ade80", "#f0fdf4"), + gate_fill0="#0f3f2f", gate_fill1="#12261f", gate_stroke="#fbbf24", + gate_ink="#fef9c3", pill_ink="#5eead4", +) + +LIGHT = Theme( + name="light", bg0="#f6f8fc", bg1="#e9eef7", grid="#dbe3ef", + ink="#0f172a", ink_soft="#64748b", panel="#ffffff", panel_stroke="#cbd5e1", + line="#7688a1", emerald="#059669", rose="#e11d48", amber="#d97706", + wordmark0="#0d9488", wordmark1="#4f46e5", + source=("#d5f5f0", "#0d9488", "#0f3d38"), + api=("#d8f5e2", "#16a34a", "#14532d"), + gate_fill0="#ecfdf5", gate_fill1="#d1fae5", gate_stroke="#b45309", + gate_ink="#7c2d12", pill_ink="#0f766e", +) + + +def esc(s: str) -> str: + return html.escape(s, quote=True) + + +def text(x, y, s, *, size, fill, weight=400, anchor="start", spacing=None, + opacity=1.0): + ls = f' letter-spacing="{spacing}"' if spacing is not None else "" + op = f' opacity="{opacity}"' if opacity != 1.0 else "" + return (f'{esc(s)}') + + +def rrect(x, y, w, h, r, *, fill, stroke="none", sw=0, opacity=1.0, extra=""): + st = f' stroke="{stroke}" stroke-width="{sw}"' if stroke != "none" else "" + op = f' opacity="{opacity}"' if opacity != 1.0 else "" + return (f'') + + +def node(cx, cy, w, h, kind_colors, title, subtitle, dot=None): + fill, stroke, ink = kind_colors + x, y = cx - w / 2, cy - h / 2 + parts = [ + f'', + rrect(x, y, w, h, 13, fill=fill, stroke=stroke, sw=1.6), + "", + rrect(x + 1, y + 1, w - 2, h * 0.5, 12, fill="url(#sheen)", + opacity=0.12), + text(cx, cy - 3, title, size=15.5, fill=ink, weight=700, + anchor="middle"), + text(cx, cy + 15, subtitle, size=11, fill=ink, weight=400, + anchor="middle", opacity=0.82), + ] + if dot: + parts.append(f'') + return "".join(parts) + + +def arrow(x0, y0, x1, y1, color, label=None, t=DARK): + out = [f''] + if label: + mx = (x0 + x1) / 2 + lw = 10 + len(label) * 6.0 + out.append(rrect(mx - lw / 2, y0 - 26, lw, 17, 8, fill=t.bg0, + opacity=0.92)) + out.append(text(mx, y0 - 14, label, size=10.5, fill=color, + weight=700, anchor="middle", spacing="0.04em")) + return "".join(out) + + +def circuit(t: Theme, x, y, w, h) -> str: + """Subtle GPU/PCB connector backdrop, clipped to the evidence-path card. + + Drawn before the nodes, so the opaque node fills sit on top and the traces + read as a compute lattice feeding into and out of the flow. + """ + trace = t.source[1] + gold = t.gate_stroke + op = 0.32 if t.name == "dark" else 0.30 + + def via(cx, cy, c=trace): + return (f'') + + def tp(d, c=trace, sw=1.3): + return (f'') + + P = [f'', + f''] + + # top rails (below the header band) + yA = y + 66 + P.append(tp(f"M {x} {yA} H {x + 118} V {yA + 24} H {x + 250} V {yA} " + f"H {x + 372}")) + for vx, vy in [(x + 118, yA), (x + 250, yA + 24), (x + 372, yA)]: + P.append(via(vx, vy)) + yB = y + 86 + P.append(tp(f"M {x + w} {yB} H {x + w - 96} V {yB + 30} H {x + w - 210}")) + P.append(via(x + w - 96, yB)) + P.append(via(x + w - 210, yB + 30)) + + # a lattice of traces radiating from the centre (behind the gate) + midx, midy = x + w / 2, y + h * 0.58 + P.append(tp(f"M {x} {midy:.1f} H {x + 40}")) + P.append(via(x + 10, midy)) + P.append(tp(f"M {x + w - 40} {midy:.1f} H {x + w}")) + P.append(via(x + w - 10, midy)) + for dy in (-40, 40): + P.append(tp(f"M {midx - 150:.1f} {midy + dy:.1f} H {midx - 40:.1f} " + f"V {midy:.1f}")) + P.append(tp(f"M {midx + 150:.1f} {midy + dy:.1f} H {midx + 40:.1f} " + f"V {midy:.1f}")) + + # bottom rails + yC = y + h - 78 + P.append(tp(f"M {x + 44} {yC} H {x + 168} V {yC + 22} H {x + 330} " + f"V {yC} H {x + 520} V {yC - 20} H {x + w - 44}")) + for vx, vy in [(x + 168, yC), (x + 330, yC + 22), (x + 520, yC), + (x + w - 44, yC - 20)]: + P.append(via(vx, vy)) + + P.append("") + + # PCB edge-connector fingers along the card foot (warmer, own opacity) + fy = y + h - 17 + P.append(f'') + fingers, fw, gap = 13, 11, 9 + startx = x + w / 2 - (fingers * (fw + gap) - gap) / 2 + for i in range(fingers): + P.append(f'') + P.append("") + return "".join(P) + + +def build(t: Theme) -> str: + S = [f''] + + # ---- defs ---- + S.append("") + S.append(f'' + f'' + f'') + S.append(f'' + f'' + f'' + f'') + S.append(f'' + f'' + f'') + S.append(f'' + f'' + f'') + S.append('' + '' + '' + '') + S.append(f'' + f'' + f'') + S.append('' + '') + S.append(f'' + f'') + S.append(f'' + f'') + S.append("") + + # ---- background ---- + S.append(f'') + S.append(f'') + dots = [''] + for gy in range(60, H - 20, 32): + for gx in range(40, W - 20, 32): + dots.append(f'') + dots.append("") + S.append("".join(dots)) + + # ---- left column ---- + lx = 72 + S.append(text(lx, 150, "DRIFT", size=78, fill="url(#word)", weight=800, + spacing="0.10em")) + S.append(text(lx + 4, 186, + "RELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTURE", + size=14.5, fill=t.emerald, weight=700, spacing="0.16em")) + S.append(rrect(lx + 4, 200, 190, 4, 2, fill="url(#rule)")) + S.append(text(lx, 262, "Know the change before", size=41, fill=t.ink, + weight=800)) + S.append(text(lx, 306, "it becomes your incident.", size=41, fill=t.ink, + weight=800)) + S.append(text(lx + 2, 352, + "Primary releases become cited, review-gated engineering checks.", + size=18.5, fill=t.ink_soft, weight=500)) + # trust pill — one centred line so the word gaps are inherently even (the + # SVG renderer ignores textLength, so per-word slots drift). The separators + # are emerald bullet glyphs; only the outer pill padding depends on width, + # and that is symmetric so it can never look lopsided. + pw, ph, py = 358, 42, 384 + cyp = py + ph / 2 + dot = (f'' + f' ● ') + S.append(rrect(lx, py, pw, ph, ph / 2, fill="none", stroke=t.emerald, + sw=1.6)) + S.append( + f'' + f'CITED {dot} BOUNDED {dot} INSPECTABLE' + ) + # model credit + S.append(f'Powered by ' + f'GPT-5.6 tiers' + f' · Luna · Terra · Sol') + + # ---- right card: evidence path ---- + cx0, cy0, cw, ch = 858, 92, 670, 336 + S.append(rrect(cx0, cy0, cw, ch, 22, fill=t.panel, stroke=t.panel_stroke, + sw=1.4, opacity=0.92, extra=' filter="url(#soft)"')) + S.append(circuit(t, cx0, cy0, cw, ch)) + S.append(f'') + S.append(text(cx0 + 40, cy0 + 39, "DRIFT EVIDENCE PATH", size=13.5, + fill=t.ink_soft, weight=700, spacing="0.14em")) + tag = "HUMAN-GATED" + tw = 24 + len(tag) * 8.0 + tagink = "#04231a" if t.name == "dark" else "#ffffff" + S.append(rrect(cx0 + cw - tw - 22, cy0 + 21, tw, 28, 14, fill=t.emerald, + extra=' filter="url(#soft)"')) + S.append(text(cx0 + cw - 22 - tw / 2, cy0 + 39, tag, size=12, + fill=tagink, weight=800, anchor="middle", spacing="0.07em")) + + fy = cy0 + 196 + # source node + S.append(node(cx0 + 118, fy, 168, 78, t.source, "Release feed", + "primary source", dot=t.rose)) + # gate (focal motif) + gcx, gy0, gy1 = cx0 + 335, cy0 + 118, cy0 + 274 + S.append(f'' + + rrect(gcx - 62, gy0, 124, gy1 - gy0, 16, fill="url(#gate)", + stroke=t.gate_stroke, sw=2.2) + "") + S.append(rrect(gcx - 60, gy0 + 2, 120, (gy1 - gy0) * 0.4, 14, + fill="url(#sheen)", opacity=0.10)) + S.append(f'') + S.append(text(gcx, gy0 + 36, "5", size=17, fill=t.gate_fill1, weight=800, + anchor="middle")) + # small person glyph + pgy = gy0 + 72 + S.append(f'') + S.append(text(gcx, gy0 + 108, "HUMAN", size=13.5, fill=t.gate_ink, + weight=800, anchor="middle")) + S.append(text(gcx, gy0 + 126, "GATE", size=13.5, fill=t.gate_ink, + weight=800, anchor="middle")) + # briefing node + S.append(node(cx0 + 552, fy, 168, 78, t.api, "Cited briefing", + "bounded check", dot=t.emerald)) + # arrows + S.append(arrow(cx0 + 202, fy, gcx - 66, fy, t.line, "untrusted", t)) + S.append(arrow(gcx + 66, fy, cx0 + 468, fy, t.emerald, "reviewed", t)) + + S.append("") + return "".join(S) + + +def main() -> None: + import pathlib + here = pathlib.Path(__file__).parent + for t, fname in ((DARK, "drift-banner-dark.svg"), + (LIGHT, "drift-banner-light.svg")): + (here / fname).write_text(build(t), encoding="utf-8") + print(f"wrote {fname}") + + +if __name__ == "__main__": + main() diff --git a/assets/brand/build_banner_raster.mjs b/assets/brand/build_banner_raster.mjs new file mode 100644 index 0000000..c5eaedc --- /dev/null +++ b/assets/brand/build_banner_raster.mjs @@ -0,0 +1,21 @@ +// Rasterize the DRIFT banner SVGs to high-DPI PNG using the frontend's sharp +// install. Run from assets/brand/: node build_banner_raster.mjs +// The API serves the SVGs; the PNGs are convenience exports for decks/video. +import { readFileSync, writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; + +const require = createRequire("file://" + process.cwd() + "/../../frontend/"); +const sharp = require("sharp"); + +const SCALE = 2; // 1600x520 -> 3200x1040 +const jobs = [ + ["drift-banner-dark.svg", "drift-banner-dark.png"], + ["drift-banner-light.svg", "drift-banner-light.png"], +]; + +for (const [src, out] of jobs) { + const svg = readFileSync(src); + const png = await sharp(svg, { density: 72 * SCALE }).png().toBuffer(); + writeFileSync(out, png); + console.log(`wrote ${out}`); +} diff --git a/assets/brand/drift-banner-dark.png b/assets/brand/drift-banner-dark.png new file mode 100644 index 0000000..f6071ac Binary files /dev/null and b/assets/brand/drift-banner-dark.png differ diff --git a/assets/brand/drift-banner-dark.svg b/assets/brand/drift-banner-dark.svg index a55ab72..dbc6dbd 100644 --- a/assets/brand/drift-banner-dark.svg +++ b/assets/brand/drift-banner-dark.svg @@ -1,67 +1 @@ - - DRIFT — release intelligence for AI infrastructure - A dark DRIFT hero banner. A primary release signal enters a GPU-like compute lattice and branches into cited evidence, human review, and a bounded engineering check. - - - - - - - - - - - - - - - - - DRIFT - RELEASE INTELLIGENCE FOR AI INFRASTRUCTURE - - Know the change before - it becomes your incident. - Primary releases become cited, review-gated engineering checks. - - CITED · BOUNDED · INSPECTABLE - - - - - - - DRIFT EVIDENCE PATH - HUMAN-GATED - - - - - - - - - - - - - PRIMARY RELEASE - Release - EVIDENCE - Frozen span - REVIEW - Human notes - CHECK - Bounded action - - - - - - - - GPU - COMPUTE LATTICE - - - +DRIFTRELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTUREKnow the change beforeit becomes your incident.Primary releases become cited, review-gated engineering checks.CITED  ●  BOUNDED  ●  INSPECTABLEPowered by GPT-5.6 tiers · Luna · Terra · SolDRIFT EVIDENCE PATHHUMAN-GATEDRelease feedprimary source5HUMANGATECited briefingbounded checkuntrustedreviewed \ No newline at end of file diff --git a/assets/brand/drift-banner-light.png b/assets/brand/drift-banner-light.png new file mode 100644 index 0000000..156b005 Binary files /dev/null and b/assets/brand/drift-banner-light.png differ diff --git a/assets/brand/drift-banner-light.svg b/assets/brand/drift-banner-light.svg index cfa9e81..44cf3ab 100644 --- a/assets/brand/drift-banner-light.svg +++ b/assets/brand/drift-banner-light.svg @@ -1,64 +1 @@ - - DRIFT — release intelligence for AI infrastructure - A light DRIFT hero banner. A primary release signal enters a GPU-like compute lattice and branches into cited evidence, human review, and a bounded engineering check. - - - - - - - - - - - - - - - - - DRIFT - RELEASE INTELLIGENCE FOR AI INFRASTRUCTURE - - Know the change before - it becomes your incident. - Primary releases become cited, review-gated engineering checks. - - CITED · BOUNDED · INSPECTABLE - - - - - - - DRIFT EVIDENCE PATH - HUMAN-GATED - - - - - - - - - - PRIMARY RELEASE - Release - EVIDENCE - Frozen span - REVIEW - Human notes - CHECK - Bounded action - - - - - - - - GPU - COMPUTE LATTICE - - - +DRIFTRELEASE INTELLIGENCE FOR GPU & AI INFRASTRUCTUREKnow the change beforeit becomes your incident.Primary releases become cited, review-gated engineering checks.CITED  ●  BOUNDED  ●  INSPECTABLEPowered by GPT-5.6 tiers · Luna · Terra · SolDRIFT EVIDENCE PATHHUMAN-GATEDRelease feedprimary source5HUMANGATECited briefingbounded checkuntrustedreviewed \ No newline at end of file diff --git "a/assets/screenshots/01.DRIFT \342\200\224 Release Intelligence for AI Infrastructure.png" b/assets/screenshots/01-landing.png similarity index 100% rename from "assets/screenshots/01.DRIFT \342\200\224 Release Intelligence for AI Infrastructure.png" rename to assets/screenshots/01-landing.png diff --git "a/assets/screenshots/02.DRIFT \342\200\224 Release Intelligence for AI Infrastructure API documentation.png" b/assets/screenshots/02-api-docs.png similarity index 100% rename from "assets/screenshots/02.DRIFT \342\200\224 Release Intelligence for AI Infrastructure API documentation.png" rename to assets/screenshots/02-api-docs.png diff --git a/assets/screenshots/03-briefing.png b/assets/screenshots/03-briefing.png new file mode 100644 index 0000000..42d7c3a Binary files /dev/null and b/assets/screenshots/03-briefing.png differ diff --git "a/assets/screenshots/03.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings.png" "b/assets/screenshots/03.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings.png" deleted file mode 100644 index f75218c..0000000 Binary files "a/assets/screenshots/03.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings.png" and /dev/null differ diff --git a/assets/screenshots/04-briefing-claim-evidence.png b/assets/screenshots/04-briefing-claim-evidence.png new file mode 100644 index 0000000..0edd462 Binary files /dev/null and b/assets/screenshots/04-briefing-claim-evidence.png differ diff --git "a/assets/screenshots/04.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings Expanded.png" "b/assets/screenshots/04.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings Expanded.png" deleted file mode 100644 index 9cb177f..0000000 Binary files "a/assets/screenshots/04.DRIFT \342\200\224 Release intelligence for AI infrastructure - Briefings Expanded.png" and /dev/null differ diff --git a/backend/core/config.py b/backend/core/config.py index 1ff177d..628919f 100644 --- a/backend/core/config.py +++ b/backend/core/config.py @@ -116,7 +116,7 @@ class Settings: "DRIFT_SPEND_LEDGER_PATH", str(REPOSITORY_ROOT / ".drift" / "spend-ledger.json") ) app_name: str = "DRIFT" - app_version: str = "0.7.0" + app_version: str = "0.8.0" def validate(self) -> None: if self.mode not in {"fixture", "live"}: diff --git a/backend/fixtures/insights.json b/backend/fixtures/insights.json index 780717b..cc06427 100644 --- a/backend/fixtures/insights.json +++ b/backend/fixtures/insights.json @@ -1,44 +1,176 @@ [ { "id": 1, - "raw_item_ids": [101], - "title": "Example: review an inference-runtime release before rollout", - "summary": "This fixture demonstrates how DRIFT presents a release item that warrants a deployment review.", - "why_it_matters": "An inference-runtime upgrade can change kernel selection, memory use, or supported hardware. Treat this as an example workflow, not a claim about a specific version.", + "raw_item_ids": [ + 101 + ], + "title": "Example: inference-runtime release changes default attention backend", + "summary": "This labelled example shows how DRIFT presents an inference-runtime release that alters kernel selection and warrants a deployment review.", + "why_it_matters": "An inference-runtime upgrade can change kernel selection, memory use, or supported hardware. Treat this as an example workflow, not a claim about a specific shipped version.", "what_to_check": "Compare the release notes with your pinned runtime, GPU architecture, serving flags, and latency baseline before promoting the upgrade.", "severity": "breaking", - "affected_libraries": ["vllm"], - "source_citations": ["https://github.com/vllm-project/vllm/releases"], + "affected_libraries": [ + "vllm" + ], + "source_citations": [ + "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/101.txt" + ], "confidence": 0.86, "model_used": "fixture-curated", - "created_at": "2026-07-14T09:00:00Z" + "created_at": "2026-07-14T09:00:00Z", + "claims": [ + { + "text": "The default attention backend is now selected automatically from GPU capability, and a flag is added to pin it.", + "kind": "direct_fact", + "evidence": [ + { + "raw_item_id": 101, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/101.txt", + "source_sha256": "13565676f03156171d31f37403d47bba64779d5de79c5488fdb572f77f8fa03b", + "excerpt": "Default attention backend is now chosen automatically based on GPU capability; pass --attention-backend to override the selection.", + "start_char": 63, + "end_char": 193, + "cross_references": [] + } + ] + }, + { + "text": "Automatic backend selection can change latency and memory profiles for operators who previously relied on the implicit default.", + "kind": "inference", + "evidence": [ + { + "raw_item_id": 101, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/101.txt", + "source_sha256": "13565676f03156171d31f37403d47bba64779d5de79c5488fdb572f77f8fa03b", + "excerpt": "automatically based on GPU capability", + "start_char": 103, + "end_char": 140, + "cross_references": [] + } + ] + }, + { + "text": "Re-run your latency and throughput baseline with the attention backend pinned before promoting the upgrade.", + "kind": "recommended_check", + "evidence": [ + { + "raw_item_id": 101, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/101.txt", + "source_sha256": "13565676f03156171d31f37403d47bba64779d5de79c5488fdb572f77f8fa03b", + "excerpt": "pass --attention-backend to override the selection", + "start_char": 142, + "end_char": 192, + "cross_references": [] + } + ] + } + ] }, { "id": 2, - "raw_item_ids": [102], - "title": "Example: validate framework and compiler compatibility", - "summary": "This fixture shows a compatibility-oriented briefing item for a framework release.", + "raw_item_ids": [ + 102, + 104 + ], + "title": "Example: framework release surfaces compiler and extension compatibility", + "summary": "This labelled example shows a compatibility-oriented briefing item for a framework release that touches the compiler path.", "why_it_matters": "Framework releases can expose compiler or extension incompatibilities that only appear in a production build or a less common model path.", "what_to_check": "Run the affected training or inference smoke test with your pinned compiler and custom extensions before changing the production image.", "severity": "minor", - "affected_libraries": ["pytorch", "triton"], - "source_citations": ["https://github.com/pytorch/pytorch/releases", "https://github.com/triton-lang/triton/releases"], + "affected_libraries": [ + "pytorch", + "triton" + ], + "source_citations": [ + "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/102.txt", + "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/104.txt" + ], "confidence": 0.78, "model_used": "fixture-curated", - "created_at": "2026-07-13T09:00:00Z" + "created_at": "2026-07-13T09:00:00Z", + "claims": [ + { + "text": "The release raises the minimum supported compiler toolchain used to build custom extensions.", + "kind": "direct_fact", + "evidence": [ + { + "raw_item_id": 102, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/102.txt", + "source_sha256": "c8ee76c0ebdd69c18701b3e5f82c700c036ff1b1981ed862a48fd308d6ac22f5", + "excerpt": "Custom C++/CUDA extensions now require the updated minimum compiler toolchain to build against this release.", + "start_char": 63, + "end_char": 171, + "cross_references": [] + } + ] + }, + { + "text": "Rebuild your custom C++/CUDA extensions against this release with your pinned compiler before updating the production image.", + "kind": "recommended_check", + "evidence": [ + { + "raw_item_id": 104, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/104.txt", + "source_sha256": "267669aa883213415ff8e76cb8ee1eab58a2eca9e5cbd5ef584e95fbd99e2614", + "excerpt": "Extensions built against the previous toolchain should be recompiled.", + "start_char": 63, + "end_char": 132, + "cross_references": [] + } + ] + } + ] }, { "id": 3, - "raw_item_ids": [103], - "title": "Example: assess a distributed-communication update", - "summary": "This fixture demonstrates a lower-priority item with an explicit confidence signal.", - "why_it_matters": "Distributed communication changes can affect multi-node behavior without altering single-node development results.", + "raw_item_ids": [ + 103 + ], + "title": "Example: distributed-communication update affects multi-node collectives", + "summary": "This labelled example shows a lower-priority item, with an explicit confidence signal, for a distributed-communication release.", + "why_it_matters": "Distributed-communication changes can affect multi-node behavior without altering single-node development results.", "what_to_check": "If you use multi-node training, run a representative collective-communication test before scheduling an upgrade.", "severity": "minor", - "affected_libraries": ["nccl"], - "source_citations": ["https://github.com/NVIDIA/nccl/releases"], + "affected_libraries": [ + "nccl" + ], + "source_citations": [ + "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/103.txt" + ], "confidence": 0.69, "model_used": "fixture-curated", - "created_at": "2026-07-12T09:00:00Z" + "created_at": "2026-07-12T09:00:00Z", + "claims": [ + { + "text": "The release adjusts the default algorithm used for a common collective operation on multi-node topologies.", + "kind": "direct_fact", + "evidence": [ + { + "raw_item_id": 103, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/103.txt", + "source_sha256": "751e1c443fb130dcfe93b84ff160cb14c5a745306a91ac9f37d31605028eec19", + "excerpt": "The default all-reduce algorithm selection has changed for multi-node configurations in this release.", + "start_char": 63, + "end_char": 164, + "cross_references": [] + } + ] + }, + { + "text": "Run a representative multi-node collective-communication test before scheduling the upgrade.", + "kind": "recommended_check", + "evidence": [ + { + "raw_item_id": 103, + "source_url": "https://github.com/iarjunganesh/drift/blob/v0.8.0/backend/fixtures/source_evidence/103.txt", + "source_sha256": "751e1c443fb130dcfe93b84ff160cb14c5a745306a91ac9f37d31605028eec19", + "excerpt": "multi-node configurations", + "start_char": 122, + "end_char": 147, + "cross_references": [] + } + ] + } + ] } ] diff --git a/backend/fixtures/source_evidence/101.txt b/backend/fixtures/source_evidence/101.txt new file mode 100644 index 0000000..a97e519 --- /dev/null +++ b/backend/fixtures/source_evidence/101.txt @@ -0,0 +1,2 @@ +Synthetic DRIFT fixture source — not an upstream release note. +Default attention backend is now chosen automatically based on GPU capability; pass --attention-backend to override the selection. diff --git a/backend/fixtures/source_evidence/102.txt b/backend/fixtures/source_evidence/102.txt new file mode 100644 index 0000000..60350cc --- /dev/null +++ b/backend/fixtures/source_evidence/102.txt @@ -0,0 +1,2 @@ +Synthetic DRIFT fixture source — not an upstream release note. +Custom C++/CUDA extensions now require the updated minimum compiler toolchain to build against this release. diff --git a/backend/fixtures/source_evidence/103.txt b/backend/fixtures/source_evidence/103.txt new file mode 100644 index 0000000..d7fdc9d --- /dev/null +++ b/backend/fixtures/source_evidence/103.txt @@ -0,0 +1,2 @@ +Synthetic DRIFT fixture source — not an upstream release note. +The default all-reduce algorithm selection has changed for multi-node configurations in this release. diff --git a/backend/fixtures/source_evidence/104.txt b/backend/fixtures/source_evidence/104.txt new file mode 100644 index 0000000..c3314bb --- /dev/null +++ b/backend/fixtures/source_evidence/104.txt @@ -0,0 +1,2 @@ +Synthetic DRIFT fixture source — not an upstream release note. +Extensions built against the previous toolchain should be recompiled. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a9b8f8b..c3d4207 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -5,9 +5,11 @@ This document explains the checked-in architecture visual, the boundaries behind it, and the evidence required before the live path can be called complete. The implementation, publication, and current release work are recorded in the -nine [Codex project initiatives](INITIATIVES.md). +ten [Codex project initiatives](INITIATIVES.md). -> **Current truth:** the fixture path is working and reproducible. The local +> **Current truth:** the fixture path is working and reproducible. Its example +> claims point to checked-in synthetic source text, not mutable upstream pages, +> and retain the same exact-span/source-hash invariant as live claims. The local > capture job persists/reloads primary source evidence, freezes exact claim > spans, separately verifies the draft, embeds it, and stores both model-run > audits. It cannot publish a draft: live read paths admit only human-reviewed, @@ -23,27 +25,41 @@ nine [Codex project initiatives](INITIATIVES.md). ## Visual source of truth -The canonical architecture is maintained in -[`assets/architecture/architecture-diagram.mmd`](../assets/architecture/architecture-diagram.mmd). -The checked-in themed renders are the README and presentation assets: +The canonical *pipeline* is maintained in +[`assets/architecture/arch-pipeline.mmd`](../assets/architecture/arch-pipeline.mmd); +the hand-authored *presentation diagram* (`arch-*`) dramatizes the same six +stages as a first-look trust-boundary story. Both are checked-in README and +presentation assets that share one visual language with the `assets/brand/` +banner.

- + - - - DRIFT architecture — Engineer to FastAPI, fixture mode or live release-intelligence pipeline, and cited briefing output + + + DRIFT trust boundary — untrusted release feeds through machine claim extraction and a separate verifier into quarantined drafts; a human review gate is the only bridge to the trusted, published briefing an engineer sees.

-Open the [light SVG](../assets/architecture/architecture-diagram-light.svg) or -[dark SVG](../assets/architecture/architecture-diagram-dark.svg) for a scalable -version. The corresponding [light PNG](../assets/architecture/architecture-diagram-light.png) -and [dark PNG](../assets/architecture/architecture-diagram-dark.png) are for -slides and video. Regeneration instructions live in the -[architecture asset guide](../assets/architecture/README.md). +

+ + + + + DRIFT pipeline — Engineer to FastAPI, fixture mode or live release-intelligence pipeline through Scout, Synthesizer, claim extraction, a separate verifier, a human review gate, and Briefing + + +

+ +Open the presentation [light SVG](../assets/architecture/arch-light.svg) / +[dark SVG](../assets/architecture/arch-dark.svg) or the pipeline +[light SVG](../assets/architecture/arch-pipeline-light.svg) / +[dark SVG](../assets/architecture/arch-pipeline-dark.svg) for scalable versions; +the matching PNGs are for slides and video. Regeneration instructions live in +the [architecture asset guide](../assets/architecture/README.md). The main diagram stays intentionally horizontal because it describes the pipeline’s ownership sequence. Supporting diagrams below are kept short or @@ -71,7 +87,7 @@ what must be demonstrated before each stage moves to complete. ### Fixture path — complete ```text -backend/fixtures/insights.json +backend/fixtures/source_evidence/*.txt + insights.json │ ▼ InsightStore (read-only, in-memory) @@ -82,8 +98,8 @@ InsightStore (read-only, in-memory) ``` Fixture mode is the default. It needs no database, network, OpenAI key, or -frontend build. Every record is an explicit example and uses -`model_used: fixture-curated`. +frontend build. Every record is an explicit example backed by checked-in +synthetic source text and uses `model_used: fixture-curated`. ### Live path — target @@ -219,7 +235,7 @@ a SHA-256 manifest. It refuses draft/unverified rows and archive overwrites. | `GET /search?q=2..300 chars` | `Insight[]` | Fixture token relevance by default; live mode uses query embeddings/pgvector over reviewed verifier-passed rows only | | `POST /chat` | `ChatRequest → ChatResponse` | Fixture composition by default; retrieve-first model answer from reviewed verifier-passed evidence in live mode | | `GET /docs` | Swagger UI | Generated OpenAPI UI with the canonical theme-aware DRIFT banner | -| `GET /brand/{dark\|light}.svg` | Canonical hero banner | Served from `assets/brand/`; excluded from the OpenAPI contract | +| `GET /brand/{dark\|light}.svg` | Canonical brand banner | Served from `assets/brand/`; excluded from the OpenAPI contract | | `GET /openapi.json` | OpenAPI document | FastAPI-generated; not checked in | The chat path retrieves matching insights first. If no matching evidence exists, @@ -354,7 +370,7 @@ Ruff → mypy → pytest + coverage → Codecov upload → frontend build → do ``` The enforceable floor is 100% for implemented code; the current local suite is -148 tests at 100.00%. Deliberately unimplemented live-stage raises remain explicit and are +150 tests at 100.00%. Deliberately unimplemented live-stage raises remain explicit and are excluded only at the boundary itself. New live behavior must arrive with tests that preserve the 100% floor. diff --git a/docs/BUILD_SEQUENCE.md b/docs/BUILD_SEQUENCE.md index 0c836c6..7e324f1 100644 --- a/docs/BUILD_SEQUENCE.md +++ b/docs/BUILD_SEQUENCE.md @@ -55,6 +55,10 @@ AI-infrastructure release intelligence. - [x] Operator: deployed `v0.7.0`; Railway `/health`/`/docs`, Vercel CORS, review-note redaction in `/briefing` and `/openapi.json`, and the deployed frontend's `top_n=10` request were verified +- [x] Codex: released `v0.8.0` source changes — Ask DRIFT validates the public + `/chat` boundary, and no-key fixture claims point to checked-in synthetic + source text with verified offsets and hashes; hosted verification remains + a separate required observation - [x] No new model calls — the current UI remains presentation-only ## Day 8 — Final content + docs @@ -87,14 +91,18 @@ The public repository is `iarjunganesh/drift`, and the README already points to its repository-specific Codecov badge. 1. GitHub `main` is published; continue verifying `.github/workflows/ci.yml`. -2. Confirm the `pytest` upload appears in Codecov. -3. Confirm the README badge resolves to the project report: +2. The `pytest` upload is confirmed on Codecov (2026-07-17) — the repository and + `flag=pytest` coverage badges both resolve to 100%. +3. The README badge resolves to the project report: ```markdown [![Codecov](https://codecov.io/gh/iarjunganesh/drift/graph/badge.svg)](https://codecov.io/gh/iarjunganesh/drift) ``` -4. Protect the default branch and require the CI quality gate. +4. The default branch is protected (2026-07-17): `main` requires the five CI + quality-gate checks (Ruff lint, Mypy type check, Tests and coverage, Frontend + build, Documentation hygiene) with strict up-to-date merges; admins retain a + bypass for pre-deadline hotfixes. 5. The Railway API is live at `https://drift-api-prod.up.railway.app`, and the Vercel frontend is live at `https://dr1ftless.vercel.app`. Keep the Vercel Root Directory set to `frontend/`; its checked-in configuration supplies @@ -115,7 +123,7 @@ Insight stage now has structured-output coverage. The baseline, hosted-deployment follow-up, bounded v0.4.0 baseline, v0.5.0 capture-path release, and -implementation follow-ups are supported by nine project initiatives: +implementation follow-ups are supported by ten project initiatives: - Foundation and inspectable vertical slice — `019f61e7-1ea1-7742-9acc-99d62f39b888` @@ -123,10 +131,10 @@ implementation follow-ups are supported by nine project initiatives: `019f61fc-c32e-7d92-9d2e-0bd9083d08e7` - Hosted deployment and README follow-up — `019f6253-ddfc-7272-8077-e34dfb3aee84` -- Day 1/Day 2 implementation follow-up — - `019f62e8-6715-70e2-a92a-fe28254f7b71` - Grounded live chat, resilience, and locked delivery (primary candidate initiative) — `019f62b9-10b7-7d82-a463-e6eb1192141c` +- Day 1/Day 2 implementation follow-up — + `019f62e8-6715-70e2-a92a-fe28254f7b71` - Day 3/Day 4 Insight structured output — `019f6336-3690-7022-a8ef-c8c0947e240f` - Bounded capture/provenance and documentation cleanup — @@ -135,5 +143,7 @@ implementation follow-ups are supported by nine project initiatives: `019f6773-0e96-7363-9657-0e0531c3d594` - Submission audit and frontend evidence presentation — `019f6a46-e3eb-7de2-81b1-91515ae80043` +- Reviewed-evidence hardening, hosted verification, and `v0.8.0` source release — + `019f6a78-6fa2-7121-9059-85ac8ceb9904` See [`INITIATIVES.md`](INITIATIVES.md) for scope and submission usage. diff --git a/docs/CODEX_PROMPTS.md b/docs/CODEX_PROMPTS.md index 83a4c38..8851b3e 100644 --- a/docs/CODEX_PROMPTS.md +++ b/docs/CODEX_PROMPTS.md @@ -221,6 +221,8 @@ changes: readiness - `019f6a46-e3eb-7de2-81b1-91515ae80043` — submission audit and frontend evidence presentation + - `019f6a78-6fa2-7121-9059-85ac8ceb9904` — reviewed-evidence hardening, + hosted verification, and `v0.8.0` source release 4. Leave the Demo video line as-is (placeholder) — recording is a human task, not a Codex task. @@ -237,10 +239,11 @@ rules/FAQ reference copy, not drift's submission draft. - Record and upload the demo video (<3 min, narrated, covers Codex + GPT-5.6 usage) - Confirm which supplied initiative is the primary `/feedback` session for the - Devpost form; retain all nine IDs in the README, changelog, and submission + Devpost form; retain all ten IDs in the README, changelog, and submission notes. -- Verify branch protection and the Codecov upload on the published GitHub - repository. +- Branch protection and the Codecov upload are verified on the published GitHub + repository (2026-07-17): `main` requires the five CI quality-gate checks, and + the `pytest` coverage upload resolves to 100% on Codecov. - Use `notebooks/drift_manual_run.ipynb` against a reachable database to create and review a small draft store, then smoke-test hosted `/search` and `/chat` against that reviewed, cited evidence. Railway PostgreSQL schema `0003`, diff --git a/docs/INITIATIVES.md b/docs/INITIATIVES.md index f601182..bcc39b4 100644 --- a/docs/INITIATIVES.md +++ b/docs/INITIATIVES.md @@ -1,6 +1,6 @@ # DRIFT project initiatives -These are the nine Codex project initiatives associated with the DRIFT baseline, +These are the ten Codex project initiatives associated with the DRIFT baseline, publication follow-up, `0.2.0` release candidate, and the current build-sequence implementation work. They are submission evidence pointers for the build work; they are not model-run provenance and do not turn fixture records into live @@ -250,7 +250,7 @@ capture; this initiative does not turn it into a broad live-analysis claim. ### Implementation addendum — 2026-07-15 -The planned guardrails are now implemented locally and covered by 149 tests at +The planned guardrails are now implemented locally and covered by 150 tests at 100.00% backend coverage: - each live claim has a type, frozen exact primary-source excerpt, character @@ -297,27 +297,37 @@ health, docs, CORS, and Vercel banner source were verified, and a later `/briefing`, `/search`, and `/chat` verified provider-backed. The amended `v0.6.1` release also makes the API-docs banner frame system-theme-aware. +## Initiative 10 — Reviewed-evidence hardening, hosted verification, and v0.8.0 source release + +**Codex Session ID:** `019f6a78-6fa2-7121-9059-85ac8ceb9904` + +**Dates:** 2026-07-16–17 + +This initiative audited and completed the reviewed-evidence release boundary: + +- fixed the Windows evidence-manifest newline mismatch and preserved byte-exact + SHA-256 verification; +- made human review notes database-only in public API serialization and OpenAPI; +- made the saved results notebook Markdown-only and added a regression test; +- verified Railway `v0.7.0`, public redaction, Vercel CORS, and the deployed + ten-item briefing request; and +- synchronized release, architecture, ADR, runbook, and submission records; +- carried the same work through the `v0.8.0` source release: corrected no-key + fixture claims to use explicitly synthetic, checked-in source text with + byte-exact hashes/spans, aligned the Ask DRIFT UI with the `/chat` contract, + added the regression test, and performed the final status/version sweep. + ## Submission usage -Devpost requires one primary `/feedback` session, use Initiative 04. All nine +Devpost requires one primary `/feedback` session, use Initiative 04. All ten IDs should be retained in the project README, changelog, and submission notes. If Devpost requires one primary `/feedback` session, use Initiative 04: `019f62b9-10b7-7d82-a463-e6eb1192141c`. Initiative 05 is the additive Day 1/Day 2 implementation and synchronization record, Initiative 06 is the additive Day 3/Day 4 Insight implementation record, and Initiative 07 is the bounded capture/provenance and cleanup record. Initiative 08 is the additive grounding -guardrail and capture-readiness record, and Initiative 09 is the additive -submission-audit/frontend-presentation record; the earlier sessions remain the -foundation, publication, and hosted-demo follow-up initiatives. - -### Release-hardening addendum — 2026-07-16 - -The `v0.7.0` source release fixes the Windows evidence-manifest newline mismatch, -makes review notes database-only in the public API contract, requests up to ten -reviewed briefing records in the frontend, and replaces the recorded notebook -with a Markdown-only results artifact. It is covered by 149 tests at 100% -backend coverage. The Git-connected deployment was then verified through -`/health` (`0.7.0`), `/docs`, Vercel CORS, a four-record `/briefing` without -review notes, `/openapi.json` without the field, and the Vercel bundle's -`top_n=10` request. Paid chat was not re-invoked for this privacy/frontend-only -release. +guardrail and capture-readiness record, Initiative 09 is the additive +submission-audit/frontend-presentation record, and Initiative 10 is the +reviewed-evidence hardening, hosted-verification, and `v0.8.0` source-release +record; the earlier sessions remain the foundation, publication, and hosted-demo +follow-up initiatives. diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md index ccf7f1f..8dd6c0f 100644 --- a/docs/RUNBOOK.md +++ b/docs/RUNBOOK.md @@ -13,7 +13,9 @@ truth boundary in [`ARCHITECTURE.md`](ARCHITECTURE.md). 4. Open `/docs` and point out the same paired, system-theme-aware DRIFT banners used in the README and frontend, then inspect `/briefing`, search `vllm`, and send a chat question. -5. Point out the source links, confidence, and `fixture-curated` audit label. +5. Point out the source links, confidence, and `fixture-curated` audit label; + each link opens checked-in synthetic source text rather than an upstream + release note. 6. If showing the frontend, run `npm --prefix frontend ci` and `npm --prefix frontend run dev` in a second terminal. @@ -106,7 +108,7 @@ The complete shot list and narration timing are in ## Project initiative records -The nine Codex initiatives associated with this baseline, deployment follow-up, +The ten Codex initiatives associated with this baseline, deployment follow-up, the v0.4.0 baseline, v0.5.0 capture-path release, and implementation follow-ups are listed in [`INITIATIVES.md`](INITIATIVES.md): @@ -123,3 +125,5 @@ are listed in `019f6773-0e96-7363-9657-0e0531c3d594` - Submission audit and frontend evidence presentation: `019f6a46-e3eb-7de2-81b1-91515ae80043` +- Reviewed-evidence hardening, hosted verification, and `v0.8.0` source release: + `019f6a78-6fa2-7121-9059-85ac8ceb9904` diff --git a/docs/adr/007-vercel-railway-deployment.md b/docs/adr/007-vercel-railway-deployment.md index e07bc9a..f63dfb4 100644 --- a/docs/adr/007-vercel-railway-deployment.md +++ b/docs/adr/007-vercel-railway-deployment.md @@ -40,7 +40,7 @@ pre-gate hosted result remains historical evidence only. **2026-07-16 brand-assets addendum:** `assets/brand/drift-banner-dark.svg` and -`assets/brand/drift-banner-light.svg` are the canonical theme-aware hero +`assets/brand/drift-banner-light.svg` are the canonical theme-aware brand banners. The Railway Docker image copies the source pair and FastAPI serves them at `/brand/dark.svg` and `/brand/light.svg`. **2026-07-16 frontend theme addendum:** the Vercel frontend renders those API-served canonical files through diff --git a/docs/adr/010-claim-evidence-and-review-gate.md b/docs/adr/010-claim-evidence-and-review-gate.md index 6a4f7ba..b19ff00 100644 --- a/docs/adr/010-claim-evidence-and-review-gate.md +++ b/docs/adr/010-claim-evidence-and-review-gate.md @@ -68,3 +68,10 @@ database-only in the serialized Insight contract and prevents the live-store reader from copying them into public records. It also tests the public API and OpenAPI boundary. The Git-connected `v0.7.0` deployment was verified to omit the field from `/briefing` and `/openapi.json`. + +**2026-07-17 fixture addendum:** `v0.8.0` makes no-key example claims conform +to the same evidence contract without representing synthetic text as an +upstream release. Each fixture evidence reference resolves to a checked-in, +explicitly synthetic source file; the full-file SHA-256, exact excerpt, offsets, +source URL, and raw-item relationship are asserted by a regression test. This +is source-release behavior only until a hosted deployment is observed. diff --git a/docs/adr/README.md b/docs/adr/README.md index 2f954ba..d6459f8 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -15,7 +15,7 @@ decisions compose. | [007](007-vercel-railway-deployment.md) | Vercel frontend + Railway API and database | Accepted; hosted `v0.7.0` health/docs/CORS, review-note redaction, and Vercel `top_n=10` bundle verified; reviewed `/briefing`/`/search`/`/chat` were provider-backed verified on 2026-07-16 | | [008](008-live-grounded-chat.md) | Live grounded chat over the fixture store | Accepted | | [009](009-bounded-model-resilience-and-locked-delivery.md) | Bounded model resilience and locked delivery | Accepted | -| [010](010-claim-evidence-and-review-gate.md) | Claim-level evidence, separate verification, and review-first publication | Accepted locally and deployed; four human-reviewed Insights published 2026-07-16 with hosted retrieval/chat verified provider-backed | +| [010](010-claim-evidence-and-review-gate.md) | Claim-level evidence, separate verification, and review-first publication | Accepted; `v0.8.0` source makes synthetic fixture evidence verifiable without implying upstream provenance, while four human-reviewed Insights remain the bounded hosted set verified 2026-07-16 | When implementation invalidates a decision, amend the original record or add a new ADR. Do not silently rewrite the decision history in code comments or diff --git a/frontend/app/AskDrift.tsx b/frontend/app/AskDrift.tsx new file mode 100644 index 0000000..5c5d189 --- /dev/null +++ b/frontend/app/AskDrift.tsx @@ -0,0 +1,166 @@ +"use client"; + +import { useState } from "react"; + +type ChatAnswer = { + answer: string; + source_citations: string[]; + model_used: string; + grounded_insight_ids: number[]; +}; + +const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; +const MIN_QUESTION_LENGTH = 3; +const MAX_QUESTION_LENGTH = 2_000; + +const SUGGESTIONS = [ + "What should I check for vLLM?", + "What changed in NCCL collectives?", + "Does TensorRT 11.1 affect my CUDA version?", +]; + +type Status = "idle" | "loading" | "answered" | "empty" | "error"; + +export default function AskDrift() { + const [question, setQuestion] = useState(""); + const [status, setStatus] = useState("idle"); + const [result, setResult] = useState(null); + const [errorMessage, setErrorMessage] = useState(""); + + async function ask(pending: string) { + const trimmed = pending.trim(); + if (trimmed.length < MIN_QUESTION_LENGTH || status === "loading") return; + + setStatus("loading"); + setResult(null); + setErrorMessage(""); + try { + const response = await fetch(`${API_URL}/chat`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ question: trimmed }), + }); + + if (response.status === 404) { + setStatus("empty"); + return; + } + if (!response.ok) { + throw new Error(`The DRIFT API returned ${response.status}.`); + } + + const answer = (await response.json()) as ChatAnswer; + setResult(answer); + setStatus("answered"); + } catch (error) { + setErrorMessage( + error instanceof Error ? error.message : "The DRIFT API could not complete the request." + ); + setStatus("error"); + } + } + + return ( +
+
Grounded chat
+

Ask DRIFT

+

+ Ask about a release and get an answer grounded only in retrieved DRIFT + evidence, returned with its source citations. In live mode the answer is + generated over human-reviewed, verifier-passed Insights; in fixture mode + it is composed from the labelled example records. +

+ +
{ + event.preventDefault(); + void ask(question); + }} + > + + setQuestion(event.target.value)} + autoComplete="off" + /> + +
+ +
+ {SUGGESTIONS.map((suggestion) => ( + + ))} +
+ + {status === "loading" && ( +
+

Retrieving cited evidence…

+
+ )} + + {status === "empty" && ( +
+

No matching insights

+

+ No reviewed DRIFT insight matched that question. Try a specific + library or release, such as vLLM, NCCL, TensorRT, or Transformers. +

+
+ )} + + {status === "error" && ( +
+

The DRIFT API could not complete the request

+

{errorMessage}

+
+ )} + + {status === "answered" && result && ( +
+
Grounded answer
+

{result.answer}

+ {result.source_citations.length > 0 && ( +
+ {result.source_citations.map((citation) => ( + + Source ↗ + + ))} +
+ )} +
+ Model {result.model_used} + {result.grounded_insight_ids.length > 0 && ( + Grounded in insight {result.grounded_insight_ids.join(", ")} + )} +
+
+ )} +
+ ); +} diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 2c33f68..c220fdd 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -105,6 +105,20 @@ h1 { max-width: 760px; font-size: clamp(3.2rem, 8vw, 6.6rem); line-height: .98; .pill.security { background: rgba(251, 146, 60, .16); color: var(--amber); } .pill.breaking { background: rgba(167, 139, 250, .16); color: var(--violet); } .pill.minor { background: rgba(56, 189, 248, .14); color: var(--cyan); } +.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } +.ask-form { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; } +.ask-input { flex: 1 1 320px; min-width: 0; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--ink); font: inherit; padding: 12px 18px; } +.ask-input::placeholder { color: var(--muted); } +.ask-input:focus-visible { outline: none; border-color: rgba(56, 189, 248, .7); } +.button.primary:disabled { opacity: .55; cursor: not-allowed; transform: none; } +.ask-suggestions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; } +.ask-chip { border: 1px solid var(--line); border-radius: 999px; background: transparent; color: var(--muted); font: inherit; font-size: .82rem; font-weight: 600; padding: 7px 13px; cursor: pointer; transition: border-color .2s ease, color .2s ease; } +.ask-chip:hover { border-color: rgba(56, 189, 248, .7); color: var(--cyan); } +.ask-answer { margin-top: 20px; } +.ask-answer h3 { margin: 0 0 8px; } +.ask-answer-label { color: var(--cyan); font-size: .72rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; } +.ask-answer-body { color: var(--ink); line-height: 1.65; margin: 10px 0 0; white-space: pre-wrap; } +.ask-meta { display: flex; gap: 14px; flex-wrap: wrap; color: var(--muted); font-size: .82rem; margin-top: 14px; } .footer { color: var(--muted); font-size: .85rem; padding-top: 30px; } @media (max-width: 800px) { .hero { grid-template-columns: 1fr; padding-top: 64px; } .cards { grid-template-columns: 1fr; } .item { flex-direction: column; } h1 { font-size: clamp(3.3rem, 15vw, 4.6rem); } } @media (max-width: 560px) { .product-line { display: none; } .nav-links { gap: 14px; } .nav-links a:first-child { display: none; } .hero { gap: 34px; padding-bottom: 58px; } .signal { padding: 14px 18px 20px; } .proof-line { line-height: 1.5; } } diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index e40720d..9ee0de1 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -2,6 +2,8 @@ import { useEffect, useState } from "react"; +import AskDrift from "./AskDrift"; + type Insight = { id: number | null; title: string; @@ -79,6 +81,7 @@ export default function Home() { @@ -105,7 +108,7 @@ export default function Home() { DRIFT evidence path: a primary release flows through a GPU compute lattice into cited evidence, human review, and a bounded engineering check
Current operating mode
@@ -193,6 +196,8 @@ export default function Home() { + +
The DRIFT contract

Useful because it stays inspectable.

diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1263c8f..377112b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "drift-frontend", - "version": "0.7.0", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "drift-frontend", - "version": "0.7.0", + "version": "0.8.0", "dependencies": { "next": "^16.2.10", "react": "^19.2.7", diff --git a/frontend/package.json b/frontend/package.json index 43a834c..53183d0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "drift-frontend", - "version": "0.7.0", + "version": "0.8.0", "private": true, "engines": { "node": "24.x" diff --git a/pyproject.toml b/pyproject.toml index 95b1b92..e1de518 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "drift-release-intelligence" -version = "0.7.0" +version = "0.8.0" description = "Release intelligence for GPU and AI-infrastructure teams" readme = "README.md" requires-python = ">=3.14" diff --git a/submission/DEMO_SCRIPT.md b/submission/DEMO_SCRIPT.md index 11f04a7..f76625d 100644 --- a/submission/DEMO_SCRIPT.md +++ b/submission/DEMO_SCRIPT.md @@ -12,7 +12,7 @@ model behavior. | Time | Screen | Narration / action | | --- | --- | --- | -| 0:00–0:10 | DRIFT hero banner | “DRIFT turns GPU and AI-infrastructure release noise into a cited engineering check.” | +| 0:00–0:10 | DRIFT brand banner | “DRIFT turns GPU and AI-infrastructure release noise into a cited engineering check.” | | 0:10–0:28 | README problem section or architecture | “Teams depend on fast-moving projects such as vLLM, PyTorch, Triton, and CUDA. DRIFT answers what changed, why it matters, and what to check next.” | | 0:28–0:42 | Terminal: start API | Run `uv run uvicorn backend.main:app --reload`; show the no-key fixture mode. | | 0:42–1:00 | `/health` and `/briefing` | Show the live reviewed briefing after confirming the deployed version. Point out severity, confidence, citations, and that this is a small bounded four-Insight set—not broad live analysis. | diff --git a/submission/DRIFT_FREEZE_PLAN.md b/submission/DRIFT_FREEZE_PLAN.md new file mode 100644 index 0000000..d49b7bb --- /dev/null +++ b/submission/DRIFT_FREEZE_PLAN.md @@ -0,0 +1,458 @@ +# DRIFT — FREEZE PLAN +## OpenAI Build Week 2026 (Developer Tools) + +> Frozen execution plan. +> +> Goal: maximize judging score while avoiding unnecessary feature creep. + +--- + +# Philosophy + +The repository is already a strong engineering project. + +The remaining work is **not** "adding more AI." + +The remaining work is making judges immediately understand: + +- why DRIFT exists, +- why OpenAI is essential, +- why developers would actually use it. + +Everything below is prioritized for maximum judging impact. + +--- + +# Final Score Matrix + +| Category | Current | Target | Status | +|-----------|---------|--------|--------| +| Problem Selection | 9.6 | 10 | ⬜ | +| Innovation | 9.3 | 10 | ⬜ | +| OpenAI Integration | 8.8 | 10 | ⬜ | +| Technical Difficulty | 9.8 | 10 | ⬜ | +| Engineering Quality | 9.8 | 10 | ⬜ | +| Documentation | 9.8 | 10 | ⬜ | +| Architecture | 9.8 | 10 | ⬜ | +| Safety & Trust | 9.7 | 10 | ⬜ | +| UX | 8.3 | 10 | ⬜ | +| Demo | 8.2 | 10 | ⬜ | +| Submission Quality | 9.0 | 10 | ⬜ | +| OSS Readiness | 9.9 | 10 | ⬜ | + +--- + +# Priority 1 (Mandatory) + +## 1. Produce a world-class demo + +Target: +10/10 + +The first 60 seconds should answer: + +> Why should I care? + +Structure: + +1. Developer problem +2. Real upstream release +3. Ask DRIFT +4. Grounded answer +5. Citations +6. Impact analysis +7. Recommendation + +No architecture yet. + +Only value. + +--- + +## 2. Make OpenAI indispensable + +Judges should conclude: + +> This could not reasonably exist without modern reasoning models. + +Demonstrate: + +- synthesis +- evidence comparison +- ambiguity handling +- grounded responses +- verification + +Avoid describing DRIFT as: + +"AI summarizer" + +Instead: + +"Grounded release intelligence." + +--- + +## 3. Improve UX + +Current: + +Engineering-first. + +Target: + +Developer-first. + +Examples: + +Instead of + +"What changed?" + +Use + +"Will upgrading CUDA break my stack?" + +Instead of + +"Summarize releases" + +Use + +"Do I need to care?" + +--- + +## 4. End-to-end workflow + +One complete story: + +Source release + +↓ + +Evidence ingestion + +↓ + +Verification + +↓ + +Storage + +↓ + +Grounded reasoning + +↓ + +Developer answer + +↓ + +Action recommendation + +--- + +# Priority 2 (Strongly Recommended) + +## MCP Integration + +Add MCP only if it creates new capability. + +Good architecture: + +``` +Cursor + +↓ + +MCP + +↓ + +DRIFT + +↓ + +Verified Release Intelligence + +↓ + +Grounded Response +``` + +Supported clients: + +- Cursor +- Claude Desktop +- VS Code +- Windsurf +- Any MCP-compatible agent + +Example: + +Developer: + +> Did CUDA 13 break vLLM? + +MCP + +↓ + +DRIFT + +↓ + +Returns: + +- evidence +- citations +- impact +- migration notes +- confidence + +This is valuable. + +Simply exposing DRIFT through MCP is not. + +The MCP layer should unlock new workflows. + +--- + +## Tool Calling + +Expose tools such as: + +- search releases +- compare versions +- summarize impact +- dependency lookup +- cite evidence +- timeline + +These naturally map to MCP tools. + +--- + +## Better User Stories + +Create several polished examples. + +Examples: + +- CUDA upgrade +- PyTorch release +- NeMo release +- TensorRT release +- vLLM release + +--- + +# Priority 3 (Nice to Have) + +## Evaluation + +Include measurable quality. + +Examples: + +- grounding rate +- citation coverage +- verifier pass rate +- unsupported claim rate +- retrieval latency + +Even simple metrics improve credibility. + +--- + +## Screenshots + +Include: + +- Home +- Search +- Chat +- Timeline +- Evidence +- Architecture + +--- + +## GIFs + +Short animations: + +- ingestion +- search +- grounded answer + +--- + +## Landing Page Polish + +One sentence. + +One screenshot. + +One animation. + +No long paragraphs above the fold. + +--- + +# Demo Script + +Target: + +3–4 minutes + +Minute 1 + +Problem. + +Minute 2 + +Live workflow. + +Minute 3 + +Architecture. + +Minute 4 + +Future vision. + +Never reverse this order. + +--- + +# Things NOT To Add + +Avoid feature creep. + +Do NOT add: + +- another LLM +- multi-provider support +- autonomous agents +- unnecessary RAG +- unrelated dashboards +- blockchain +- crypto +- gamification + +Every feature should answer: + +"Does this improve developer release intelligence?" + +If not, + +don't build it. + +--- + +# Frozen Feature List + +Core + +✅ Release ingestion + +✅ Verification + +✅ Grounded chat + +✅ Citations + +✅ Review gate + +✅ Evidence database + +✅ Release timeline + +Stretch + +✅ MCP Server + +✅ Tool Calling + +✅ IDE Integration + +--- + +# Submission Checklist + +## Repository + +- [ ] README complete +- [ ] Architecture diagrams +- [ ] Screenshots +- [ ] Demo GIFs +- [ ] Installation tested +- [ ] CI passing +- [ ] License +- [ ] Security policy +- [ ] Contributing guide + +--- + +## Demo + +- [ ] Recorded +- [ ] Audio clean +- [ ] 1080p +- [ ] Under time limit +- [ ] Shows OpenAI reasoning +- [ ] Shows citations +- [ ] Shows verification +- [ ] Shows developer workflow + +--- + +## Devpost + +- [ ] Compelling title +- [ ] Clear one-line tagline +- [ ] Problem statement +- [ ] Why OpenAI +- [ ] Architecture +- [ ] Challenges +- [ ] Future work +- [ ] GitHub +- [ ] Video +- [ ] Screenshots + +--- + +# Final Definition of Done + +A judge should finish the demo thinking: + +> "I immediately understand the problem." + +> "The AI is doing something genuinely useful." + +> "The engineering is exceptional." + +> "I could use this tomorrow." + +> "This deserves to be among the strongest Developer Tools submissions." + +--- + +# Final Rule + +From this point onward: + +Every new commit must satisfy at least one of these: + +1. Improves developer value. +2. Improves OpenAI reasoning. +3. Improves demo quality. +4. Improves judging clarity. + +If it satisfies none of them, + +do not build it. \ No newline at end of file diff --git a/submission/NEXT_STEPS.md b/submission/NEXT_STEPS.md index d8a6259..a6288ff 100644 --- a/submission/NEXT_STEPS.md +++ b/submission/NEXT_STEPS.md @@ -5,9 +5,11 @@ release and submission work only; do P2 polish by hand where possible. **OpenAI API budget (separate from Codex credits):** capture runs and hosted smoke tests draw on the `drift` project key, bounded by `DRIFT_MAX_SPEND_USD=10`. That is enough for several capture runs; do not raise the cap. -Audit verdict: hosted `v0.7.0` is verified (149 tests and 100% backend -coverage), including evidence-byte integrity, public review-note redaction, and -the ten-item frontend request. Railway `/health`/`/docs`, Vercel CORS, +Audit verdict: hosted `v0.7.0` is verified; the `v0.8.0` source release has +150 tests and 100% backend coverage, verifiable synthetic fixture evidence, and +the grounded Ask DRIFT UI, but must not be called hosted until deployment is +observed. `v0.7.0` includes evidence-byte integrity, public review-note +redaction, and the ten-item frontend request. Railway `/health`/`/docs`, Vercel CORS, `/briefing` (four records with no review notes), `/openapi.json` (no review-note field), and the deployed Vercel bundle were checked on 2026-07-16. The reviewed-output blocker is cleared; the demo video remains the final submission @@ -60,38 +62,45 @@ blocker. ## P1 — High leverage (Jul 18–19). Largest scoring uplift per hour. ### 4. Restructure README top (Potential Impact / first impression) -- [ ] First screen: problem → what DRIFT does → live demo links (now showing real +- [x] First screen: problem → what DRIFT does → live demo links (now showing real content) → 60-second judge path (`docker compose up` + hosted URLs). -- [ ] Move the boundary/disclaimer material lower and reframe it as the trust +- [x] Move the boundary/disclaimer material lower and reframe it as the trust model — "release notes are untrusted input; every claim carries a frozen source span, a separate verifier pass, and a human review gate" — not as an apology. -- [ ] Keep the Codex/GPT-5.6 usage section prominent (judges are told to look for it). +- [x] Keep the Codex/GPT-5.6 usage section prominent (judges are told to look for it). -### 5. Add a minimal chat/search box to the frontend (Design) -- [ ] One component against the existing `/search` + `/chat` endpoints; show the - grounded answer with citations. This is the single biggest demo-video uplift. -- [ ] If credits run short, cut this before cutting anything in P0. +### 5. Add a minimal grounded-chat box to the frontend (Design) +- [x] One component (`AskDrift`) against the retrieve-first `/chat` endpoint; + shows the grounded answer with source citations. The separate `/search` + endpoint remains available in the API rather than duplicating live + retrieval in the browser. This is the single biggest demo-video uplift. +- [x] If credits run short, cut this before cutting anything in P0. ### 6. Cross-platform judge path -- [ ] Add bash/curl equivalents beside every PowerShell command in Quick Start +- [x] Add bash/curl equivalents beside every PowerShell command in Quick Start (judges will likely test on macOS/Linux). -- [ ] Promote `docker compose up` as the one-command local path. +- [x] Promote `docker compose up` as the one-command local path. --- ## P2 — Polish (Jul 20). Hand-edit; do not spend Codex credits here. -- [x] README quality result — updated to 149 tests after a verified pytest run. +- [x] README quality result — updated to 150 tests after a verified pytest run. - [x] README clone URL — replaced `git clone ` with: `https://github.com/iarjunganesh/drift.git`. - [x] Scrubbed `bankers-wrapped` references from public surfaces: `backend/main.py` docstring, `.env.example`, `docs/CODEX_PROMPTS.md` intro. -- [ ] Give the 3 fixture records `claims` arrays so the "Inspect claim evidence" +- [x] Give the 3 fixture records `claims` arrays so the "Inspect claim evidence" panel renders in no-key mode; retitle them to read like realistic examples - (still labelled fixtures). -- [ ] Enable branch protection requiring the CI quality gate. -- [ ] Confirm the Codecov `pytest` upload appears on the dashboard. + (still labelled fixtures), then backed them with checked-in synthetic + source text and an integrity regression test. Validated against the + `Insight` model; 150 tests still pass at 100% coverage. +- [x] Enable branch protection requiring the CI quality gate (main: 5 required + checks — Ruff lint, Mypy type check, Tests and coverage, Frontend build, + Documentation hygiene; strict up-to-date; admins retain bypass). +- [x] Confirm the Codecov `pytest` upload appears on the dashboard (tokenless + OIDC upload queued and processed; repo and `flag=pytest` badges both 100%). --- @@ -102,7 +111,7 @@ blocker. - [ ] Video URL: final public YouTube link. - [ ] Repo URL: `https://github.com/iarjunganesh/drift` (public, MIT — already verified). - [ ] Primary `/feedback` Session ID: `019f62b9-10b7-7d82-a463-e6eb1192141c` - (all 9 initiative IDs stay documented in README/`docs/INITIATIVES.md`). + (all 10 initiative IDs stay documented in README/`docs/INITIATIVES.md`). - [ ] Judge testing path: hosted frontend + API links, plus `docker compose up`. - [ ] Re-run the "Do not claim until verified" checklist in `SUBMISSION.md` — after P0 lands, most of those claims become safely claimable. diff --git a/submission/SUBMISSION.md b/submission/SUBMISSION.md index 5d25a82..ae218c3 100644 --- a/submission/SUBMISSION.md +++ b/submission/SUBMISSION.md @@ -19,6 +19,8 @@ `019f6773-0e96-7363-9657-0e0531c3d594` - Submission audit and frontend evidence presentation: `019f6a46-e3eb-7de2-81b1-91515ae80043` + - Reviewed-evidence hardening, hosted verification, and `v0.8.0` source release: + `019f6a78-6fa2-7121-9059-85ac8ceb9904` - [x] Use `019f62b9-10b7-7d82-a463-e6eb1192141c` as the primary `/feedback` Session ID if the Devpost form accepts only one. - [x] Implement local claim-level evidence, separate verification, and diff --git a/tests/integration/test_api.py b/tests/integration/test_api.py index 00a66b9..b8c9115 100644 --- a/tests/integration/test_api.py +++ b/tests/integration/test_api.py @@ -39,7 +39,7 @@ def test_health_and_briefing(api_client) -> None: root = api_client.get("/") health = api_client.get("/health") - assert health.json()["version"] == "0.7.0" + assert health.json()["version"] == "0.8.0" briefing = api_client.get("/briefing") assert root.status_code == 200 diff --git a/tests/unit/test_fixture_evidence.py b/tests/unit/test_fixture_evidence.py new file mode 100644 index 0000000..29049d5 --- /dev/null +++ b/tests/unit/test_fixture_evidence.py @@ -0,0 +1,42 @@ +"""Keep the no-key example claims as inspectable as their live counterparts.""" + +import json +from hashlib import sha256 +from pathlib import Path + +from backend.models.schema import Insight + +_FIXTURE_PATH = Path("backend/fixtures/insights.json") +_SOURCE_DIRECTORY = Path("backend/fixtures/source_evidence") +_SOURCE_URL_PREFIX = ( + "https://github.com/iarjunganesh/drift/blob/v0.8.0/" + "backend/fixtures/source_evidence/" +) + + +def test_fixture_claim_evidence_matches_frozen_synthetic_sources() -> None: + """Fixture evidence is exact, shared per raw item, and never upstream data.""" + insights = [ + Insight.model_validate(item) + for item in json.loads(_FIXTURE_PATH.read_text(encoding="utf-8")) + ] + source_texts = { + int(path.stem): path.read_bytes().decode("utf-8") + for path in _SOURCE_DIRECTORY.glob("*.txt") + } + + referenced_raw_item_ids = set() + for insight in insights: + for claim in insight.claims: + for evidence in claim.evidence: + source_text = source_texts[evidence.raw_item_id] + expected_url = f"{_SOURCE_URL_PREFIX}{evidence.raw_item_id}.txt" + + referenced_raw_item_ids.add(evidence.raw_item_id) + assert evidence.raw_item_id in insight.raw_item_ids + assert evidence.source_url == expected_url + assert evidence.source_url in insight.source_citations + assert evidence.source_sha256 == sha256(source_text.encode("utf-8")).hexdigest() + assert source_text[evidence.start_char : evidence.end_char] == evidence.excerpt + + assert set(source_texts) == referenced_raw_item_ids diff --git a/uv.lock b/uv.lock index cf39498..1e64e78 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "drift-release-intelligence" -version = "0.7.0" +version = "0.8.0" source = { editable = "." } dependencies = [ { name = "alembic" },