← All docs changelog/2026-W18.md

Week 18 — Apr 28 – May 4, 2026

Summary

Two new services landed this week: static_site (static.grizzlebear.io) centralizes 5 demo pages under a shared TradeSpark-themed shell with CSS design tokens, JS utilities, and a Markdown blog engine; tsweb (tsweb.grizzlebear.io) quarantines all Supabase tsweb-app integrations into a single deletable boundary module with its own /projects API endpoint. The mobile-session demo was upgraded from free-text UUID inputs to live project/property dropdowns backed by the tsweb API (three-phase rollout: quarantine → endpoint → UI). Earlier in the week, the ML chat/stream endpoint gained per-provider message history and the Bruno test runner got retry logic for transient cold-start failures.

Later in the week, the livekit-recorder gained AES-CBC encryption at rest — recordings are now encrypted before S3 upload, with the Go recorder receiving the account DEK via environment variable. The COLMAP SfM pipeline added checkpoint-based preemption tolerance so Modal spot-instance restarts skip completed stages. LiveKit SDKs were bumped to 1.5.6. A tsweb deployment fix replaced top-level imports with per-function Image.add_local_python_source("tsweb") layering to stop crash loops in unrelated services, and two flaky on-prem chat tests were tagged skip-ci.

12 code commits | 86 files changed | +4,224 / -1,624 lines


Highlights

Static Site Service — Demo Centralization (Apr 30)

Merged from worktree branch. Five demo pages (ml-comparison, ml-dashboard, mobile-session, model-proxy, websocket-test) that were scattered across service modules are now consolidated under dev/static_site/ at static-{env}.grizzlebear.io. Features a shared CSS design system (TradeSpark tokens), JS utility layer (Site.apiFetch with auto-auth, Site.serviceUrl), header/footer templates, and a Markdown content engine with YAML frontmatter for blog posts.

tsweb Quarantine — Three-Phase Rollout (Apr 30)

All code that reads from the external tsweb-app Supabase tables is now isolated in dev/tsweb/:

  • Phase A (0c93938): Moved supabase_queries.py, location.py, and supabase_scraper.py into dev/tsweb/. Nightly scraper cron moved from ml_endpoint to tsweb.scheduled.
  • Phase B (8931ec8): New GET /projects endpoint at tsweb-{env}.grizzlebear.io returning user-scoped projects with joined property data. New get_accessible_account_ids() auth helper. Bruno test coverage added.
  • Phase C (8cedea6): Mobile-session demo's text inputs replaced with <select> dropdowns populated from the tsweb /projects endpoint. Users see actual projects instead of typing UUIDs.

When tsweb-app is retired, the cleanup is a single-directory delete of dev/tsweb/.

Per-Provider Message History for Chat Stream (Apr 28)

New optional messages_by_provider field on ChatStreamRequest lets clients supply a distinct conversation history per provider in the multiplexed /ml/chat/stream endpoint. A provider not covered by the dict falls back to the top-level messages array — fully backward compatible. Bruno test added for two providers with distinct prior turns.

Bruno Test Suite Retry (Apr 28)

Transient failures — Modal cold-start TLS handshake errors, brief upstream blips — were producing one-off canary breaks that pass on re-run. test_app.sh now wraps bru run in a 3-attempt loop and only declares failure if every attempt fails. Whole-suite retry rather than per-test because Bruno tests share auth state through post-response scripts.

LiveKit Recorder Encryption at Rest (May 1)

The Go-based livekit-recorder now encrypts video and depth recordings using AES-CBC before writing to S3, mirroring the Python core.crypto.encrypt_account_data path. The recorder receives the account DEK via DEK_BASE64 env var, loaded by the Python agent before spawning the subprocess. load_dek_in_memory() was updated to return the DEK string. The VIDEO_DATA_BUCKET_NAME reference was removed in favor of the consolidated ASSET_DATA_BUCKET_NAME.

COLMAP Preemption Checkpointing (May 1)

The COLMAP SfM pipeline (colmap_undistorted_sfm_export.sh) now writes a checkpoint after each completed stage. On Modal preemption and restart, step_done()/mark_done() helpers skip already-completed stages. LiveKit SDKs bumped from 1.1.2/1.4.2 to 1.1.5/1.5.6; VAD prewarm disabled due to upstream livekit bug (loads inline via silero.VAD.load() instead). Session recording asset registration re-enabled. session_to_splat timeout extended from 4h to 6h.

tsweb Deployment Fix — Per-Function Image Layering (May 4)

Phase A's top-level from tsweb import ... hoists in auth.py and data_endpoint.py crashed every service that imports AuthContext but doesn't mount tsweb. Replaced with Modal 1.1.0's Image.add_local_python_source("tsweb") on only the users and data functions that actually call into tsweb at runtime. Two flaky on-prem chat tests tagged skip-ci (on-prem Ollama unreachable from dev; 60s timeout × 3 retries was 15+ min).

Temporary Supabase Prod Override (Apr 28)

The new prod Supabase project doesn't yet have anonymous sign-ins enabled or the canary test fixtures (test_project / test_location), so main temporarily uses SupabaseDev. Restoration checklist tracked in IMPROVE.md H19.


Daily Breakdown

May 4 (2 code commits, 3 docs-only)

  • 558983a Mount tsweb on users + data via per-function image layering; skip flaky on-prem chat tests (+33/-11)
  • e3e6cf3 Add descriptors and reorder demo cards on static site (+27/-5)
  • 84a29cc Refresh IMPROVE.md with 2026-05-01 review findings (docs-only)
  • c4d156d Add Apr 30 changelog, update W18 weekly summary (docs-only)
  • 958dd48 Refresh IMPROVE.md with 2026-05-04 review findings (docs-only)

May 1 (2 code commits)

  • d790317 Add checkpointing for Modal preemption, update LiveKit SDKs to 1.5.6, fix anon DEK issue (+282/-153)
  • 434ea24 Make livekit-recorder write encrypted data (AES-CBC, DEK via env var) (+97/-15)

Apr 30 (5 code commits, 2 docs-only)

  • 4867061 Merge static.grizzlebear.io demo centralization into dev (+2,894/-1,355)
  • e349957 Allow bash <script>:* form in Claude Code settings
  • 0c93938 Quarantine tsweb-app Supabase integration into dev/tsweb/ (Phase A)
  • 8931ec8 Add tsweb /projects endpoint at tsweb-{env}.grizzlebear.io (Phase B)
  • 8cedea6 Replace mobile-session text inputs with tsweb-backed dropdowns (Phase C)
  • 19ef58e Refresh IMPROVE.md with 2026-04-30 review findings (docs-only)
  • 12a2523 Add Apr 28-29 changelogs, start W18 weekly summary (docs-only)

Apr 29 (1 commit — docs-only)

  • 4cd1fc5 Refresh IMPROVE.md with 2026-04-29 review findings (docs-only)

Apr 28 (3 code commits, 2 docs-only)

  • 49469f8 Add per-provider message history to /ml/chat/stream
  • 6ea8c3d Point main env at SupabaseDev until new prod Supabase is restored
  • dc4e353 Retry Bruno test suite up to 2x on failure in test_app.sh
  • c78e098 Add Apr 27 changelog, refresh W17 weekly summary (docs-only)
  • 02fbece Refresh IMPROVE.md with 2026-04-28 review findings (docs-only)

Modified Files

May 4

  • dev/users/auth.py — reverted top-level tsweb import; stays lazy in _resolve_location_context
  • dev/data/data_endpoint.py — reverted top-level sync import; tsweb layered onto data image via add_local_python_source
  • dev/users/users_endpoint.py — tsweb layered onto users image via add_local_python_source
  • bruno/.../Chat Stream Multi Provider.bru — added skip-ci tag
  • bruno/.../Chat Stream Per Provider History.bru — added skip-ci tag
  • dev/static_site/templates/index.html — demo list reordered, descriptors added
  • dev/static_site/assets/css/site.css.demo-desc styling

May 1

  • dev/queues/colmap_undistorted_sfm_export.sh — checkpoint-based preemption tolerance
  • dev/queues/session_to_splat.py — timeout 4h → 6h
  • dev/queues/video_to_gsplat.shnew: ffmpeg → COLMAP → splatting helper
  • dev/livekit_ts/agent/agent.py — silero VAD inline, recording asset registration re-enabled, depth track handling
  • dev/livekit_ts/agent/recorder.py — S3 bucket fix, DEK loading + DEK_BASE64 env var
  • dev/livekit_ts/agent/room_agent_worker.py — VAD prewarm disabled
  • dev/livekit-recorder/pkg/participant/data.goencryptBytes() + encryptAndWriteFile() (AES-CBC)
  • dev/livekit-recorder/pkg/participant/processing.go — encrypted writes replace copyFile
  • dev/core/core.pylivekit-protocol pinned to 1.1.5
  • dev/core/data.pyVIDEO_DATA_BUCKET_NAME removed; load_dek_in_memory() returns DEK string
  • dev/users/auth.py — anon DEK handling fixes
  • dev/requirements.txt — LiveKit SDK bumps to 1.5.6
  • dev/queues/1416529-sd_640_360_30fps.mp4, dev/queues/boot.mp4removed (test videos)

Apr 30

  • dev/static_site/new module: endpoint, templates (6 pages + partials), CSS/JS assets, content engine, blog posts
  • dev/tsweb/new module: quarantined tsweb-app integration (queries, location, scraper, endpoint, scheduled cron, client)
  • dev/app.py — includes static_site.app and tsweb.app
  • dev/core/core.pyServiceType.STATIC and ServiceType.TSWEB enums + domain resolution
  • dev/ml/ml_endpoint.py — dropped inline demo routes and nightly scraper cron
  • dev/model_proxy/model_proxy_endpoint.py — dropped inline /demo route
  • dev/users/users_endpoint.py — dropped inline /mobile-session route; auth gains get_accessible_account_ids()
  • dev/websocket/websocket_endpoint.py — dropped inline /test route
  • dev/data/sync.py, dev/data/data_endpoint.py — imports from tsweb.*
  • bruno/.../Tsweb API/ — new folder with List Projects test
  • All 7 Bruno environment files — added tsweb_endpoint variable
  • .claude/settings.json — bash script allow entries
  • dev/model_proxy/demo.htmlremoved (moved to static_site)
  • dev/users/mobile_session.htmlremoved (moved to static_site)
  • dev/websocket/websocket_pages.pyremoved (routes moved to static_site)

Apr 28

  • dev/ml/gateway/chat.pymessages_by_provider field + per-provider message resolution
  • bruno/.../ML API/Chat Stream Per Provider History.bru — new: multi-provider history test
  • dev/core/core.pysupabase_secret_name hardcoded to "SupabaseDev" (temporary)
  • dev/test_app.sh — 3-attempt retry loop with failure detection (+48/-9)
  • dev/test_app.md — updated retry documentation