Every change we ship to katura1999.com — features, fixes, security patches, the lot. Pulled straight from our private GitHub repository so you can see exactly what was built and when.
By the numbers
Lines of code
943,828
Web platform — TypeScript, React, Prisma, CSS
iOS
79,607
Swift + SwiftUI lines
Android
3,117
Kotlin + Jetpack Compose lines
All platforms
1,026,552
Web + iOS + Android combined (51.0× the King James Bible)
Characters written
40.17M
40,168,559 total characters
Updates pushed
2,265
exact commit count on main
Current version
v1.22.65
build 2265 · d89cabc
Database models
420
across 47 schema files — most SaaS platforms have 20–50
API endpoints
1,052
individually routed — Stripe's public API has ~400
Translated strings
90,960
every string, in 24 languages
System permutations
10^316
2^1,052 endpoint combinations — more than atoms in the observable universe (10^80)
Project age
9mo 16d
since Dec 14, 2025
Pre-AI dev hours
34.2K hrs
1,026,552 lines ÷ 30 LOC/hr — equivalent to 16.5 years (senior engineer, no AI)
With-AI dev hours
8.6K hrs
4× AI productivity multiplier (2024–2026 studies) — equivalent to 1,069 days
Equivalent firm cost
$8,963,582
live ticker · Katura rate: $60 USD/hr
Hours estimated from source line count at 30 LOC/hr (industry benchmark for production-quality TypeScript/React without AI assistance), with a 4× multiplier for AI-assisted development per published 2024–2026 enterprise studies. Equivalent Firm Cost uses a $250/hr loaded billable rate reflecting a premium engineering firm building enterprise-grade SaaS — and ticks up live, because the project is still being actively built.
Commit history
2,265 updates pushed
Showing page 6 of 40 · 251–300 of 2,000 fetched
Saturday, August 15, 2026
4 updates pushed
Docsmeetings5:51 AM · ZRosserMcIntosh
latency 'absolute limit' handoff brief for Fable 5
Six-task implementation plan to drive mic-to-translated-subtitle latency
toward the ~300-500ms physics-adjacent floor at zero/negative cost delta:
persistent translation channel (LiveKit data channel), pre-warm on room
mount, region pinning audit, incremental/speculative translation (cuts
DeepL/OpenAI spend), streaming OpenAI fallback (cost-neutral), and a
client-side hot-phrase cache. Includes current provider status (DeepL 456
quota block, new MEETINGS_OPENAI_API_KEY tier limits), cost constraints,
fix stuck whole-transcript translation when DeepL quota exhausted
Batch the OpenAI fallback (callOpenAIBatch/translateManyViaOpenAI) instead of one HTTP call per transcript line — a 1000+ line transcript translated one-string-at-a-time (even at concurrency 3) blew past the minutes-translation route's 180s timeout whenever DeepL was unavailable, leaving the client stuck on 'TRANSLATED ...' placeholders forever.
Extract detectLanguages/classifyLanguageOpenAI into new src/lib/meetings/language-detect.ts (no @/lib/prisma import) so standalone scripts run via tsx can use them without tripping the server-only guard. translate.ts now re-exports from it.
Add scripts/repair-transcript-languages.ts: one-off/reusable tool to re-detect and correct mislabeled MeetingTranscript.sourceLanguage rows (Smart Mode's old snap-back bug mislabeled some genuinely-English lines as Portuguese) and invalidate stale MeetingMinutesTranslation cache rows so they regenerate with corrected labels.
Ran the repair tool against mtg_1786734013755_vvfuzyyz (Felipe's meeting), fixing 20 mislabeled rows so far; a few more remain pending OpenAI/DeepL rate-limit windows resetting (safe to re-run, idempotent).
default Smart Mode constraint to Auto + actually wire it up on the guest side
Default sttConstraintMode changed smart->auto (host + guest) so Deepgram's real per-utterance detection is trusted instead of overridden by a possibly-wrong declared language.
The guest room's sttConstraintMode/manualLanguages state existed from an earlier pass but was NEVER wired into the actual Deepgram onmessage constraint logic (guest ws.onmessage still ran the old always-on smart snap unconditionally) — added the ref + gated the snap logic exactly like the host room, and added the same Smart/Auto/Manual selector + manual-language chip picker to the guest settings panel (previously guests had no way to see or change this at all).
Updated the guest's toggleBilingual() toast text to reflect the actual active mode instead of a static 'limited to this meeting' message.
callOpenAI now prefers MEETINGS_OPENAI_API_KEY (falls back to the general OPENAI_API_KEY if unset) so this high-volume, retriable translation workload doesn't compete with other product features for the shared key's daily request budget.
Reduced OpenAI fallback timeout 6s->20s and concurrency 6->3 to avoid self-inflicted timeouts/rate-limit bursts.
Fixed a prompt bug: mixed-language batches passed the literal string 'Auto' to GPT as if it were a real source language name ('translate from Auto') instead of asking it to auto-detect.
Added explicit failure-count logging when both DeepL and OpenAI fail for a string, instead of silently passing the original text through.
Tuesday, August 11, 2026
12 updates pushed
Docs9:26 PM · ZRosserMcIntosh
add session log for meetings Classic vs Railgun-beta toggle (2026-08-11)
add Classic vs Railgun-beta engine toggle on the meetings list page
Toggle lives on /admin/meetings list (localStorage-persisted), never inside the live room, so switching engines never re-initializes an active LiveKit session.
Engine choice threaded via ?engine=railgun through list -> prep -> room.
meeting-room-client.tsx reads the flag via useSearchParams and gates the knock-to-enter lobby/admission panel + its polling effect behind Railgun-beta only; Classic mode is untouched from before.
Small 'Railgun Beta' badge shown in-room when active.
multilingual ON by default for everyone; relabel language selector
bilingualMode now defaults to true in both host and guest room clients (state + ref), so every participant can speak any mix of languages out of the box. Still toggleable off (pins a single language) in settings.
Guest pre-join selector relabeled 'My preferred spoken language is' with copy explaining multilingual is on and this is just a primary-language hint.
Friday, August 7, 2026
3 updates pushed
4:51 PM · ZRosserMcIntosh
capture verifiable proof in discovery + upgrade to gpt-5.4 reasoning
Evidence rows now require a verbatim sourceExcerpt proving the claim; rows that can't be quoted are omitted
Advertising rows only created when a public ad library was actually checked (Meta Ad Library / Google Ads Transparency Center URL + dated phrasing); a company website can never prove ad absence
Social/local rows require structured metrics (counts, date ranges, ratings)
Insert now persists sourceExcerpt, sourceTitle, structuredMetrics (previously dropped), so captured proof actually reaches the validator
validate / write / audit now default to gpt-5.4 (PROSPECTING_MODEL) instead of gpt-4o — stronger judgment for weighing evidence, choosing one diagnosis, and auditing claims
Optional PROSPECTING_REASONING_EFFORT applied to writer+audit, guarded so it's only sent to gpt-5 reasoning models (never to gpt-4o)
Discovery stays on gpt-4o (needs the web_search tool), documented
usage.ts: added gpt-5.4/mini/nano pricing; longest-prefix match so gpt-5.4-mini no longer mis-prices as gpt-5.4
New consultation.ts: buildConsultationBrief() turns collected evidence into a meeting agenda where EVERY talking point traces to a real source (URL/excerpt) the analyst can pull up live. Contradicted/unsupported/estimated evidence and anything without a source is filtered OUT (counted as excluded) so nothing unverifiable is raised on the call
Thursday, August 6, 2026
4 updates pushed
9:21 PM · ZRosserMcIntosh
discovery crash fix, pipeline UX, and deal management
Fixed discovery JSON parsing: web-search model now coerces 'Not specified'/ 'N/A'/messy numeric strings (e.g. '~120 reviews') to proper null/Int/Float values; Instagram handles get @ stripped; dedup now per-campaign (name+city or domain within same campaign, allowing re-approach under different offers)
Pipeline UX: grouped list view (By stage / By location toggle), clear dividers and stage labels, yellow NEW badge for prospects <48h old, close % display
Deal page (/admin/saas/prospecting/[id]): anticipated close probability (slider+input), est. monthly value, weighted forecast, next-step tracking with due dates
Meeting notes timeline: log calls/meetings/emails, snapshot close % at each touch so we can track confidence movement and coach close-rate improvement
Deterministic coaching prompts (missing email, stage-specific advice, % probability band recommendations)
Schema: added closeProbability, estMonthlyValue, nextStep, nextStepDueAt, lastContactedAt to JewelerProspect; new ProspectNote model; migration 20260806_prospecting_deal_notes.sql (additive)
PDF: cover logo now white text (Playfair) on dark navy (was invisible dark logo on navy); media-spend copy reworded (you fund and control, billed to you, not 'up to $15k' implying our spend)
Screen shares now render in a dedicated 'watch together' focus view in both the host room and guest room. Controls:
Fit/Fill toggle (object-contain letterbox vs object-cover zoom)
Full screen (theater) — maximizes the share to fill the video area while KEEPING the subtitle overlay on top (browser-native fullscreen would hide captions, so this is an in-app maximize instead) Camera participants become a filmstrip; local self-view stays as a PiP. Filmstrip + PiP hide in theater mode so nothing covers the movie.
Both the two-column transcript view and the single-language minutes transcript view now label every line 'original' or 'translated' (with a tooltip naming the source language), instead of only flagging suspicious untranslated-looking text with '(same)'.
animated join loading screen, subtitle overlay shifts for CAD viewer, invoice checkout width fix, stale minutes-translation cache repair
Fixed the persisted minutes-translation cache never invalidating when the underlying transcript grows after the first translation run — a cached row with fewer transcript entries than the meeting now has was served as-is, leaving every line added since untranslated ('…' in the UI). GET and POST both now compare cached transcript length against the live final-transcript count and treat a mismatch as stale, forcing a fresh translate + overwrite instead of trusting the short array.
Animated the join/token-generation loading screen (host room).
Subtitle overlay now shifts left when a 3D CAD viewer / diamond / invoice tile is open, instead of relying solely on pointer-events-none.
Widened the invoice tile during Stripe embedded checkout so it isn't cramped into the ~38% side-column width that was causing a blank/white screen for guests after clicking pay.
rose gold shininess fix (metalness 1.0) + subtitle overlay no longer blocks tile buttons
Rose gold metalness was 0.92 vs yellow gold's 1.0 — the lower metalness let diffuse/base-color leak through the PBR shading model, making it read as plastic instead of a shiny polished metal. Bumped to 1.0 to match yellow gold's shininess.
Subtitle overlay wrapper (both host + guest rooms) is now pointer-events-none with pointer-events-auto only on its resize handle, so the floating subtitle box never blocks clicks on tiles underneath it (e.g. the 3D CAD viewer's close button when the subtitle box floats over the top-right corner).
Host's own speech translated column stopped populating because it was gated solely on translationLangRef (viewer's own reading-translation choice), which is often unset. Added remoteSpokenLangRef fallback that tracks the other participant's spoken language from broadcast captions and uses it as the translation target for MY OWN speech too.
Restored an unrestricted 'Auto' detection mode (no meeting-language restriction) alongside the existing constrained 'Smart' default.
Added 'Manual' mode to pick 2+ specific languages to constrain Deepgram's per-utterance detection to.
None of this was previously committed/deployed, which is why production was still exhibiting the pre-fix behaviour.
bigger transcript PDF typography, translation-quality heuristic, CAD storageKey sync
Bumped body/text font sizes further (13.5px -> 15.5px body text, 14px -> 16px base, headers/letterhead scaled up to match) and widened the page (760px -> 820px, 24mm->20mm/16mm margins) -- previous pass wasn't enough, still read as small/cramped at real print scale.
New wordOverlapRatio() heuristic in translate.ts: DeepL/OpenAI can return success but silently pass rambling/disfluent transcript lines through nearly unchanged instead of translating them. Every DeepL batch result and every OpenAI call is now checked for suspicious similarity to the source (>55% word overlap, source != target); DeepL results that look untranslated get a second-opinion OpenAI pass, OpenAI itself gets one retry with a more forceful prompt before giving up.
transcript-view.tsx looksUntranslated() upgraded from exact-match to the same fuzzy word-overlap check; client-side auto-retranslate trip-wire lowered from 60% exact-duplicate to 25% fuzzy-untranslated.
rename route now keeps CadFile.storageKey/folder/fileName in sync with Supabase Storage after a move (previously only the storage object moved, breaking DB-driven consumers like the in-meeting 3D display tray)
scripts/fix-cad-storage-keys.ts: repair script for files broken by past moves; ran with --apply, fixed the Rosser/Stella engagement ring row
fix duplicate-language display, speaker color collisions, and PDF typography
Speaker colors now assigned by order of first appearance (guaranteed distinct for <=10 speakers) instead of hash-based lookup, which was colliding two different speakers onto the same color
New looksUntranslated() helper: when a 'translated' column is actually identical text to the original (already same language, or STT mislabeled source), stop rendering it as a highlighted duplicate translation box in both the live view and the transcript PDF export -- this fixed Felipe's English lines showing up highlighted-English twice
Both PDF exports (minutes summary + transcript) now render inside a page-like white card with generous margins/padding on a neutral background, bumped base font sizes and line-height throughout for a properly 'typed document' look instead of edge-to-edge tiny text
real letterhead PDF export for minutes summary + tidy transcript PDF
New GET /api/admin/meetings/[id]/minutes-pdf: dedicated print-ready document (Katura letterhead, Summary, Action Items table, Decisions, Open Questions, Risks, Follow-ups, Participants) covering everything above the transcript section, auto-triggers window.print()
minutes-actions.tsx 'Download PDF' now opens this endpoint in a new tab instead of window.print()-ing the raw app page (which printed sidebar/nav/buttons and looked like a screenshot)
transcript-view.tsx printPdf: tightened spacing, alternating row shading, ellipsis-truncated speaker labels, em-dash placeholder for empty translation cells, print-color-adjust for zebra striping
translateBatch OpenAI fallback now uses bounded concurrency (mapWithConcurrency, limit=6) instead of sequential per-line calls, cutting wall-clock time drastically on long transcripts
bump minutes-translation route maxDuration 60 -> 180 for safety margin
transcript-view.tsx: fetchTranslation now safely parses responses (reads as text first, handles non-JSON error bodies like timeout/HTML pages) instead of blindly calling res.json(), which threw an opaque SyntaxError
surface actual error message in the retranslate failure toast when short enough
redesign transcript PDF/txt/copy export to match on-screen grouped 2-column transcript view with letterhead, color-coded speakers, green translation highlight
SubtitlePanel: new 'plain' prop renders text with just a subtle blur behind it (no visible box/border/tint). Wired into every subtitle render site in both the host and guest rooms, and flipped the default to plain=true so the boxed container is now OFF by default per request.
supabase/migrations/20260814_jeweler_prospecting_v3_sync.sql: the original 20260805 migration only had V1 columns. The Prisma schema has since grown V2/V3 columns (contactEmailVerification, closeProbability, nextStep, validationStatus, proposalV2, messageType, etc.) plus 3 whole tables (ProspectNote, ProspectingAiUsage, ProspectingEvent) that were never applied to the DB -- this is exactly why /admin/saas/prospecting's GET /api/admin/prospecting/prospects (which selects evidence.validationStatus and the meetingNotes/ProspectNote relation) was failing with 'did you run the SQL migration?'. New migration is additive/idempotent (IF NOT EXISTS) and safe to run on top of the existing V1 tables.
translate.ts: add OpenAI gpt-4o-mini fallback when DeepL is missing or fails (quota/expired key/network), so live translation no longer silently shows the untranslated source language.
meeting-room-client + guest-room-client: persist the viewer's per-meeting translation-language choice in localStorage so leaving+rejoining or flipping the Classic/Railgun engine toggle no longer resets it to the browser locale (which disabled translation for a pt-BR-browser viewer in a pt meeting).
Subtitle defaults: XL font on desktop; overlay box 50% wider (640->960px).
New toggle in guest settings (OFF by default) switches their Deepgram STT to Nova-3 language=multi code-switching; per-utterance detected language now drives sourceLanguage on interims, finals, transcript persistence, and the translation source — so a guest speaking mixed languages is captioned in the language actually spoken and translated correctly.
translateSegment gains a realtime fast-path that SKIPS the Postgres cache read (up to 500ms) and the cache write for live/interim captions — LRU + DeepL only. Interim text mutates constantly and never recurs, so the DB round-trip was pure latency. Threaded realtime:true through both admin and guest /translate routes and their interim callers.
fix STT 1011 timeout when muted + guest Yen toggle knob
STT dropped when muted: while the mic is off, the worklet sends zero audio frames to Deepgram, which closes the socket with code 1011 after its ~10s idle timeout ('did not receive audio data'). Added a 5s KeepAlive heartbeat ({"type":"KeepAlive"}) sent only while muted, in both host and guest room clients; cleared on stop and on close. Connection now survives long mutes.
Guest 'Hey Virgil' toggle knob rendered detached/outside the pill: the knob span had no horizontal anchor (translate-x-6 with no left-*). Standardised to the same top-0.5 left-0.5 w-5 h-5 / translate-x-5 pattern as the other toggles.
Root cause: transcript ordered by startMs, which is RELATIVE to each participant's own STT session start (and 0 for guest/remote captions), so speakers didn't interleave — all of Stella's lines jumped to the end. Fixed: order by absolute createdAt (then startMs) in minutes page, end, regenerate-minutes, [id] detail, and minutes-translation routes so the AI and the UI both see true chronology.
New TranscriptView: per-line language chip (EN/PT) identifying what each speaker actually spoke, plus 'Show translation' that pulls the persisted translation package (zero extra tokens) and renders the translated line highlighted beside/below the original; lines already in target skipped.
Bilingual beta mode: Deepgram Nova-3 language=multi code-switching; per-segment detected language feeds transcript persistence + live translation source
MeetingMinutesTranslation: minutes+labels+full transcript translated ONCE via batched DeepL (50 strings/request) then persisted per (meetingId, targetLanguage)
New API: GET/POST /api/admin/meetings/[id]/minutes-translation (idempotent)
Points ranked verified > observed > likely; each carries why-it-matters, a non-leading discussion prompt, and the source to show on screen
Includes suggested agenda, discovery/qualification questions, de-duped complimentary quick wins to give away free, and a next-step recommendation tied to the proposed offer
briefToMarkdown() for one-click copy into notes
Deal page: Consultation brief panel with strength badges, live source links, captured excerpts, agenda, discovery questions, free-value, and next step
New lead-score.ts: 0-100 conversion score + A/B/C/D tier from 7 weighted factors that predict a paid first retainer — reachability (25), decision-maker access (15), ability to pay (20), fixable pain (15), speed to decide (10), commercial fit (10), engagement (5)
Pipeline list: tier badge + score per row; each stage/location section now sorts by conversion likelihood (highest first); ranks by manual close % when set, else the computed score
Deal page: full Conversion likelihood panel — per-factor bars, points, detail, and a 'biggest lever' callout for the highest-impact next action
List route returns lightweight evidence + meetingNotes count for scoring
6-page luxury PDF (Playfair+Geist embedded, real logo, 7.77 imagery); shared buildProposalPdfData() for preview + attachment; controlled image sources only
SEO assessment framework (seo-audit.ts) + complimentary specific quick wins rendered per audit category (free client value in every area)
Expanded launch metros grouped by region (~80, West Coast first)
fix malformed-JSON crash in discovery + AI token cost tracking
discover.ts: robust JSON extraction — repairs trailing commas, smart quotes, stray markdown citations, control chars; falls back to element-by-element salvage so one bad store no longer kills the run (fixes 'Expected comma or ] after array element' error)
fix: remove duplicated '} from "lucide-react"' line in meeting-room-client.tsx that broke the Vercel build
src/lib/prospecting/discover.ts MANUAL-trigger jeweler discovery (no crons anywhere): OpenAI Responses API w/ web_search tool, small-company priority, dedupes, creates prospects as RESEARCH with sourced evidence rows; falls back to knowledge-only clearly labeled 'estimated' if web search unavailable
/api/admin/prospecting/discover POST { count, metro, campaign }
emails/[id] route: new 'mark-sent' action for the manual workflow (Zack copies subject+body, downloads PDF, sends from his own inbox, then records the send)
UI: 'Find jewelers' modal (count/metro/campaign), Copy subject / Copy body buttons, 'Mark sent manually' button; Brevo send kept as optional 'Send via Brevo'
config: new 'design-bench' offer (Design & Bench Support) so proposals can pitch CAD + design + bench work