Built in public · Changelog
How Supernova learned the job.
Product panorama
One deal, one continuous operating loop.
Six agents live in the product today, propose-only, a named human at every gate. Everything below ships; nothing is a mock.
Brief
The Daily Brief opens each cockpit: meetings with exact times, deals needing a touch, the one move.
Draft
The Email Drafter investigates the thread through scoped tools, then a fresh-context critic verifies every claim.
Qualify
Deal Check scores MEDDPICC with the evidence that earned each score, never vibes.
Prep
Meeting Prep briefs every call: who is in the room, where it stands, what to ask.
Track
The Promise Tracker extracts what each side committed to, source attached, resolved in place.
Audit
Every run costed and receipted: model, tokens, verdict, the audit trail behind every artifact.
14
Jul 2026
Tuesday
4 shipped
Fix/design goes espresso: the dark-mode contrast pass, fixed in the reusables
The user's read on "the app feels light but not the landing's way" became a direction: the design page now runs the full espresso dark theme as the proving ground. /design wears .app-theme…
/design goes espresso: the dark-mode contrast pass, fixed in the reusables
The user's read on "the app feels light but not the landing's way" became a direction: the design page now runs the full espresso dark theme as the proving ground. /design wears .app-theme…
The user's read on "the app feels light but not the landing's way" became a direction: the design page now runs the full espresso dark theme as the proving ground. /design wears .app-theme dark, an espresso rail (.section-dark sidebar with the landing wordmark register), the landing's ruled eyebrow on the header, and a dark-aware canvas (faint cream dots, warm glow, never a white haze). Global radius knob turned down 14px→10px (crisper at app density).
The contrast pass then went component by component, every fix in the REUSABLE layer so the whole app inherits:
- Root cause found:
.darkonly remaps variables, so any text without an explicit color class inherited body's light-resolved ink — dark-on-dark across the page. Fix: the dark scope carriestext-foreground(documented in the page). - Table rewritten (
ui/table.tsx): mono uppercase header BAND on a tone step with a stronger rule, real cell padding (px-4 py-2.5), theme-real hover (row-hovertoken, not invisiblemuted/50), selected rows in the warm clay wash, footer on the strong rule. Now reads as a data grid in both themes; every table in the app upgrades for free. - Elevation became theme-aware:
--shadow-rest/raised/floatnow route through--elev-*vars (warm-tinted on cream, real black weight on espresso — a 5% warm shadow is invisible on dark). - Skeleton / Progress / Slider tracks:
bg-muted(a near-zero tone step on espresso) → foreground-relative washes, visible in both themes. - Scrims (dialog/sheet/drawer/alert-dialog):
bg-black/10getsdark:bg-black/45. - Sonner on the dark page pins
theme="dark"(it otherwise follows the OS, not the page scope). - Canvas glow fix shipped to the light app too: the near-white radial that washed every app page pale at the top is now warm cream.
FixProshort: incremental 10-min sync + a false-match fix
The mirror had gone stale (525 recordings, last one 12-Jul) because the only tooling was a full backfill (~10 min of throttled calls — too heavy to run often). Re-ran it (525 → 548, now…
Proshort: incremental 10-min sync + a false-match fix
The mirror had gone stale (525 recordings, last one 12-Jul) because the only tooling was a full backfill (~10 min of throttled calls — too heavy to run often). Re-ran it (525 → 548, now…
The mirror had gone stale (525 recordings, last one 12-Jul) because the only tooling was a full backfill (~10 min of throttled calls — too heavy to run often). Re-ran it (525 → 548, now current through today 14-Jul 11:30), then built the missing incremental path:
- `src/lib/proshort/sync.ts` —
syncProshortIncremental(): walks the recordings list newest-first and stops as soon as a page holds nothing new, so a routine run is 1 list call + N details (usually N=0). Also refreshes the last 2 days of recordings, whose insights Proshort finishes generating after the call. Writes aDELTAbatch row. - `POST/GET /api/proshort/sync` — token-guarded (shared token or Vercel Cron's
Bearer $CRON_SECRET). - Every 10 minutes:
vercel.jsoncron (*/10 * * * *) for deploy, +scripts/proshort/watch.mjsfor local (a loop that hits the route;node scripts/proshort/watch.mjs). - Bug fix — false recording matches:
getMeetingEvent's matcher joined on any shared party email, so a recording could link to a meeting merely because a colleague was in both (only the 30-min window prevented it). Now requires a genuine external party via the sharednonCorporateDomainsSql(which already excludes our own tenants + free providers).
Finding: the "Negotiation Discussion — Right Horizon x Antino" (13-Jul) has no recording because that call was never recorded — the mirror is current and 16 other calls exist from that day; Right Horizons' last recorded call is 03-Jul.
FixTwo calendar-data bugs found via the briefing: recurring subjects + a 5:30 timezone error
The briefing surfaced two real mirror bugs (both now fixed in the shared DB + at the source):
Two calendar-data bugs found via the briefing: recurring subjects + a 5:30 timezone error
The briefing surfaced two real mirror bugs (both now fixed in the shared DB + at the source):
The briefing surfaced two real mirror bugs (both now fixed in the shared DB + at the source):
- 01Recurring occurrences had no subject. 12,813 of 23,523
graph_events(everyevent_type='occurrence') hadsubject/organizernull — Graph puts those on the series master, and occurrences only reference it. Backfilled all 12,813 from their masters (subject,organizer,is_online_meeting,location,body_preview). "(no subject)" is gone. - 02Every meeting was 5:30 early (UTC parsed as IST).
graph/importer.ts'sdt()didnew Date(String(v)). Graph event start/end (dateTimeTimeZone) is a naive timestamp (zone in a separate field, always UTC here); JS parses a bare timestamp as local, so on the IST host every event stored 5:30 early — breaking times AND which-day bucketing (evening meetings fell into the wrong day, so "today's meetings" mis-timed and mis-counted). Fix:dt()now appendsZwhen there's no zone marker (messagereceivedDateTime/sentDateTimealready carryZ, so they're untouched and were always correct). Backfilledgraph_events.start_at/end_at+5:30(one-time; verified against Anisha's real Outlook: 12:30 / 16:00 / 19:00 / 20:00 — exact match). Blast radius confirmed to be events only (the 4dt()call sites: event start/end broken, message received/sent fine).
Regenerated all 17 briefings — times, day, and counts now correct.
FixClose-on-activity: doing the work closes the follow-up (the durable fix)
The backlog rebuilds because "mark done" is a separate step reps skip. So make the work itself close the task. On the SDR lead hub, logging real activity — Send email / Log a call / Book a…
Close-on-activity: doing the work closes the follow-up (the durable fix)
The backlog rebuilds because "mark done" is a separate step reps skip. So make the work itself close the task. On the SDR lead hub, logging real activity — Send email / Log a call / Book a…
The backlog rebuilds because "mark done" is a separate step reps skip. So make the work itself close the task. On the SDR lead hub, logging real activity — Send email / Log a call / Book a meeting — now completes the lead's next open follow-up in the same action (completeNextForLead, subject-matched to the lead), toasts "Follow-up marked done ✓ — you just did it", and refreshes so it vanishes. The manual Done on the lead's task list now persists too (was toast-only). Both write the task_completions overlay + an audit event (reversible, PREVIEW).
- Extracted a shared, role-flexible
src/lib/tasks/actions.ts(completeTasksbulk +completeNextForLead); the cleanup panel re-exports from it.getLeadTasksnow excludes cleared tasks (overlay), so the hub reflects it instantly. Verified end-to-end (lead "Sagar/Anaplan" → "Followup 2" auto-completes + hides). - Not yet wired: the inbox (parallel session's
/ae/inbox) and the AE lead hub (inline, no rail) — same pattern applies when those are touched.
13
Jul 2026
Monday
1 shipped
FixAE deal inbox (Outlook-style workspace) + timeline HTML sanitization
"the AE also needs to have an inbox similar to what we built for SDR — without inbox none of this has any value." Built /ae/inbox, the SDR inbox one level up the ontology (deals, not…
AE deal inbox (Outlook-style workspace) + timeline HTML sanitization
"the AE also needs to have an inbox similar to what we built for SDR — without inbox none of this has any value." Built /ae/inbox, the SDR inbox one level up the ontology (deals, not…
"the AE also needs to have an inbox similar to what we built for SDR — without inbox none of this has any value." Built `/ae/inbox`, the SDR inbox one level up the ontology (deals, not leads). Same two-pane, mail-client shape: left = the AE's deals split into "In conversation" (open deals whose buying committee — primary contact + contact-role members — has a live email thread in the Graph mirror, ranked by most-recent message across the whole pipeline) and "Open · quiet" (open deals with no live thread — the ones going dark, paginated); right = the deal header (stage chip, ₹, account, contact, Deal hub ↗) + the unified thread (emails + meetings + calls + notes + tasks via getDealTimeline) + a Copilot-draft compose box (preview — nothing sends). New data layer getDealInbox (verified 162ms / 12 real conversations for Anisha) and draftReplyForDeal (Haiku, grounded in the deal's real thread). Inbox added as the AE's #2 nav item. Note: the Copilot draft currently 401s — the ANTHROPIC_API_KEY in .env is expired (wiring is correct; SDR copilot fails identically) — a key rotation, not a code fix.
HTML sanitization — the thread was leaking raw markup (<div style="display:flex…">…) from Zoho notes pasted out of Proshort and Outlook body fragments, since we render detail as text. New htmlToText helper (src/lib/format/text.ts: strips tags, keeps block breaks as newlines, decodes the common entities incl. emoji &#…;) wired into `getDealTimeline`, `getLeadTimeline`, and the peek pane (email body + note content). Deal hub, both inboxes, and every peek now render clean prose. Also promoted the deal description to a clay-accented "What they want" brief at the top of the Deal hub Details card (was a muted grey footnote under the field grid) — narrative leads, facts follow.
Perf note (not a bug): /ae/pipeline?peek=… logged 3.5s in dev. Traced it — getPipeline 29ms + peekDeal 24ms = ~60ms of real work; the rest is Next.js dev-mode render overhead (Turbopack + React dev renderer, amplified by concurrent session load). Production build serves that route in ~100ms. No code change; the peek is a full server round-trip by design (URL-driven master-detail, not a client Sheet).
11
Jul 2026
Saturday
1 shipped
FixHEAD_OF_SALES role (admin-tier) + fixed the KPI dashboards
New HEAD_OF_SALES role, admin-tier: it shares the /admin area and sees everything the CXO admins see (Command Board, users, org, audit, integrations). Rohit Naidu (id 163) promoted to it…
HEAD_OF_SALES role (admin-tier) + fixed the KPI dashboards
New HEAD_OF_SALES role, admin-tier: it shares the /admin area and sees everything the CXO admins see (Command Board, users, org, audit, integrations). Rohit Naidu (id 163) promoted to it…
- New `HEAD_OF_SALES` role, admin-tier: it shares the
/adminarea and sees everything the CXO admins see (Command Board, users, org, audit, integrations). Rohit Naidu (id 163) promoted to it (auditedUSER_ROLE_CHANGED;scripts/add-head-of-sales-role.ts, which also runs theALTER TYPE user_role ADD VALUE 'HEAD_OF_SALES' AFTER 'ADMIN'). - Access refactor so a role can share another's area:
ADMIN_ROLES = [ADMIN, HEAD_OF_SALES], newrequireAdmin()in dal.ts (replacesrequireRole('ADMIN')across all 11 admin pages/actions),SEGMENT_ALLOWED_ROLESin roles.ts drives proxy gating (was 1:1SEGMENT_ROLES),roleHome(HEAD_OF_SALES)=/admin,ROLE_NAV[HEAD_OF_SALES]= the admin nav. "Head of Sales" is now an assignable role in/admin/users. - Fixed two real crashes on the KPI dashboards (they were listed "working" but actually threw on render): (1) server components passed formatter functions (
valueFormatter={formatInr}) to the client chart component — forbidden across the RSC boundary; replaced with avalueFormat="inr"|"count"string the client resolves. (2)weekStartfrom Postgres wasn't always a Date →Intl.DateTimeFormatthrew "Invalid time value"; now coerced with a NaN guard. Both/admin/commandand/ae/teamrender clean now. - Verified in Chromium: signed in as
admin@glue.toolsand asrohit.naidu@antino.com— both land on/admin, reach/admin/command, see ₹ figures + 16 chart SVGs, zero console/render errors.
10
Jul 2026
Friday
1 shipped
FixIncremental sync fixed for activity modules; first real delta pulled
First real-world incremental sync surfaced two COQL blind spots: activity modules (Tasks/Calls/Events) reject What_Id — the polymorphic link we must have — and Deals.Stage_Modified_Time /…
Incremental sync fixed for activity modules; first real delta pulled
First real-world incremental sync surfaced two COQL blind spots: activity modules (Tasks/Calls/Events) reject What_Id — the polymorphic link we must have — and Deals.Stage_Modified_Time /…
- First real-world incremental sync surfaced two COQL blind spots: activity modules (Tasks/Calls/Events) reject
What_Id— the polymorphic link we must have — andDeals.Stage_Modified_Time/Calls.CTI_Entry/Events.Participantsare unqueryable. Fix: Tasks/Calls/Events now sync via the same Modified_Time-desc REST walk as Notes (REST returns What_Id fine, deletions still tracked via the deleted API); the COQL path self-heals by dropping any column Zoho names in an INVALID_QUERY error (learned per process, mirroring the bulk-import behavior). - Sync then pulled two days of real CRM activity cleanly: Leads +650 upserts/2 deletes, Tasks +1,548/4, Notes +81, Calls/Accounts/Contacts small. Post-sync counts verified against live Zoho: Leads 19,034 / Tasks 588,206 / Contacts 140,500 all exact.
- Known limitation confirmed in the wild: Zoho exposes no deleted-records API for Notes, so notes deleted in Zoho persist here until the next full import (currently 1 such row).
07
Jul 2026
Tuesday
2 shipped
FixSales leadership designations fixed from the org chart
scripts/fix-sales-designations.ts (idempotent, audited USER_UPDATED): the HR sheet's generic VP/AVP titles were overriding the chart's role labels. Rohit Naidu → Head of Sales (per user;…
Sales leadership designations fixed from the org chart
scripts/fix-sales-designations.ts (idempotent, audited USER_UPDATED): the HR sheet's generic VP/AVP titles were overriding the chart's role labels. Rohit Naidu → Head of Sales (per user;…
scripts/fix-sales-designations.ts(idempotent, auditedUSER_UPDATED): the HR sheet's generic VP/AVP titles were overriding the chart's role labels. Rohit Naidu → Head of Sales (per user; chart label was "Director-Business & Strategy"), Anisha Ratnam → Head of Startup, Nitish Kumar → Head of Growth, Himanshu Gupta → Head of Government. Harshad/Vinay already correct.- Reporting tree needed no changes — all 17 chart edges already matched the image.
- L4 "Key Accounts" people keep their specific HR designations (Business Consultant / Trainee / Intern / Tender Executive); the chart's "Key Accounts" reads as the team grouping, not individual titles.
FixSticky nav fix, login verified, founders added as ADMIN
Sticky nav bug fixed: .section-dark set position: relative outside any cascade layer, which beat the layered sticky utility on the landing nav (unlayered CSS wins). Dropped the position…
Sticky nav fix, login verified, founders added as ADMIN
Sticky nav bug fixed: .section-dark set position: relative outside any cascade layer, which beat the layered sticky utility on the landing nav (unlayered CSS wins). Dropped the position…
- Sticky nav bug fixed:
.section-darksetposition: relativeoutside any cascade layer, which beat the layeredstickyutility on the landing nav (unlayered CSS wins). Dropped theposition(itsisolation: isolatealready provides the stacking context); verified in-browser — nav pinned attop: 0withposition: stickyat scrollY 2400. - Login flow verified in the browser (Playwright/Chromium against the prod build):
admin@glue.tools+ dev password → lands on/admin, shell shows Sign out; DB health confirmed. - Founders added as ADMIN (
scripts/add-founders.ts, idempotent, audited): Rajesh Kumar (Co-Founder & COO,rajesh@antino.io, id 234) and Radhakanth Kodukula (Co-Founder,radhakanth@antino.io, id 235). Emails follow the@antino.ioleadership pattern but are assumed (flagged in the audit context). Vinay was already ADMIN. Admins now: Glue Admin, Vinay, Rajesh, Radhakanth. Users total: 234.