Instead of sending all 12 tools every request, match the user's message
against keyword groups (status, workload, assign, create, advance, revision)
and only send relevant tools. search_entities always included for name
resolution. Falls back to basic query tools if no keywords match.
This cuts the tool definitions from ~12 to ~2-6 per request, significantly
reducing context size for gemma4.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Filter tools to 12 (from 17) via OLLAMA_TOOL_ALLOWLIST
- Shorten tool descriptions to first sentence only
- Trim system prompt: drop pipeline details and suggestion format, keep Rules
- Reduce num_predict from 4096 to 2048
- Fix system prompt trimming to preserve Rules section (name resolution, mutation flow)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ollama's parser chokes on deeply nested JSON in tool_use/tool_result
structured content blocks. Instead of sending OpenAI-format tool
messages, flatten everything to simple role/content text messages.
Tool results are truncated to 2KB to keep context manageable.
The model still receives tool definitions and can make new tool calls,
but prior tool interactions are shown as plain text in the history.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ollama was receiving chunked transfer encoding from Node.js fetch and
failing to parse the JSON body ("can't find closing '}' symbol").
Sending a Buffer with explicit Content-Length forces a single complete
body write.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logs request size, message count, and detailed error info to help
diagnose the "can't find closing '}'" JSON parsing error from Ollama.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemma 4 loads successfully, supports tool calling with proper
structured output, and responds in ~100ms after initial load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Larger models (mistral-large 122B, qwen3-coder 30B, gpt-oss 20B) all
fail to load due to resource limits. mistral:latest (7.2B) loads and
responds successfully.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
mistral-large:latest requires 420GB RAM, server only has 345GB.
qwen3-coder:30b is a 30.5B MoE model that fits in ~20GB with good
tool calling and reasoning capabilities.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ollama (internal GPU server) is tried first — free
- If Ollama is down, falls back to Claude API with a browser toast:
"Ollama unavailable — using Claude (paid API)"
- Provider badge shows which one is active (orange/purple)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Claude is primary, Ollama (internal GPU server) is automatic fallback
- Provider auto-selects: Claude if API key set, else Ollama if reachable
- Ollama uses mistral-large:latest for chat with full tool calling support
- Removed local Ollama Docker service — uses remote at 10.24.42.219
- Chat panel badge shows "Claude" (purple) or "Ollama" (orange)
- OLLAMA_CHAT_HOST and OLLAMA_CHAT_MODEL env vars for configuration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cap conversation history to last 20 messages
- Truncate tool results over 8KB before sending back to Claude
- Trim long assistant messages in client-side history to 2KB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The env var was in .env but not listed in docker-compose environment
block, so the container never received it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mutation confirmation: all write operations (create, update, assign)
now pause and show a confirmation card before executing. Users must
click Confirm or Cancel.
- RBAC enforcement: Artists blocked from mutations via chat, Producers
blocked from bulk operations. Only Admins get full access.
- Rate limiting: 20 requests/minute per user on the chat endpoint.
- System prompt updated to not instruct Claude to execute directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
upload-service.ts and annotation-service.ts were storing URLs like
/api/uploads/revisions/... in the database. When the app is served at
/hp-prod-tracker, the browser needs /hp-prod-tracker/api/uploads/...
to hit the correct route.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three files had hardcoded /api/ URLs that bypassed the basePath prefix,
causing 404s when the app is served under /hp-prod-tracker.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All hook files had local fetchJson() helpers calling fetch(url) directly,
bypassing the basePath. Now wrapped with apiUrl() so API calls work
under /hp-prod-tracker path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Set basePath in next.config.ts for serving under /hp-prod-tracker
- Create apiUrl() helper to prepend basePath to fetch calls
- Update all 28 fetch("/api/...") calls across 16 files
- Add GCS storage migration plan doc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Source code is now on Bitbucket — IT builds from source directly.
Docker Hub and Cloudflare Tunnel are no longer needed. Removed
profiles gate from app service so docker compose up -d works without
flags. Updated .env.example with organized sections and comments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The standalone Next.js output doesn't include prisma (devDependency)
or dotenv (only used by prisma.config.ts, not app runtime). Install
them explicitly in the runner stage for prisma migrate deploy.
Pin prisma@7.4.2 to avoid npx downloading a non-existent version.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Captures the allowDangerousEmailAccountLinking pattern for linking
pre-seeded users to SSO accounts, org auto-assignment via signIn
event, limbo page for unprovisioned users, and DEV_BYPASS_AUTH
production guard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Configure Microsoft Entra ID as the sole SSO provider with
allowDangerousEmailAccountLinking to link SSO accounts to existing
seeded user records by email match. Add signIn event for automatic
org assignment by domain. Guard DEV_BYPASS_AUTH against production
use. Add branded pending page for authenticated users without org
membership. Remove Google provider for initial rollout simplicity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 2 stale migration files with a single baseline migration
capturing the full 40+ model schema. The database was freshly reset
via clean-slate, making this the ideal time to establish migration
history. Dockerfile now runs prisma migrate deploy before app start.
Updated SETUP.md and ROADMAP.md to reference prisma migrate dev
instead of db push.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents the purge-and-reseed pattern for transitioning from dev to
production data, including FK-safe deletion order, self-referential FK
handling, and backup/restore procedures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix video-only revisions not showing (activeRevisionId fallback)
- Fix SVG coordinate system with viewBox for native→screen mapping
- Fix annotations visible at all times (timestampSeconds dropped in mapping)
- Fix timeline markers missing (use browser duration when DB has 0)
- Fix setState-during-render in duration tracking (ref+interval pattern)
- Fix click propagation toggling play during annotation drawing
- Fix concurrent attachment update race condition (Prisma transaction)
- Fix file handle leaks in uploads streaming route
- Add click-to-seek from feedback sidebar timestamp badges
- Use annotation drawing color for timeline markers
- Add solution documentation for video review bugs
- Add docs/solutions/ discoverability to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix lawn reference URL to https://github.com/pingdotgg/lawn
- Document lawn architecture analysis and adopted/not-adopted patterns
- Mark A7.3 (Timestamped Video Annotations) as in progress
- Update infrastructure built section with video annotation layer details
- Mark Annotation schema fields as complete in data model status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add timestampSeconds and frameThumbnailUrl fields to Annotation model
- New VideoAnnotationLayer component: auto-pause on draw tool activation,
SVG annotation overlay on paused video, time-filtered visibility,
All/Timed toggle, timecode display in toolbar
- New VideoTimelineMarkers: orange=unresolved, green=resolved, clustered
markers on scrub bar with click-to-seek and hover scale
- Thread timestampSeconds through validator, service, and API layers
- Feedback item cards show timestamp badges for video annotations
- VideoPlayer gains renderOverlay, timelineMarkers, pause/seek in state
- Fix "Processing" overlay shown when MP4 is available (FFmpeg fallback)
- Add revision polling when video status is "processing"
- Configure proxyClientMaxBodySize: 500mb for large video uploads
- Fix pre-existing Prisma JSON type error in upload-service.ts
- Update ROADMAP with lawn reference learnings and A7.3 progress
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three related bugs fixed:
1. Form save buttons silently failing — valueAsNumber on empty number inputs
produced NaN, which Zod rejected without visible errors on hidden tabs.
Replaced with setValueAs that converts empty strings to undefined.
2. Unique constraint violation on deliverable stage creation — dynamic pipeline
stages without matching global template slugs all fell back to
globalTemplates[0], creating duplicate (deliverableId, templateId) pairs.
Changed constraint from @@unique([deliverableId, templateId]) to
@@unique([deliverableId, stageDefinitionId]).
3. Stage names showing wrong template — all UI components read
stage.template.name exclusively, ignoring stageDefinition from the dynamic
pipeline system. Updated 13 components, 6 services, and all relevant Prisma
queries to prefer stageDefinition over template for display.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Video upload now works without FFmpeg on PATH — metadata extraction
returns defaults, thumbnail is skipped, HLS transcoding is skipped,
and video is marked as ready with raw MP4 serving only. A one-time
warning is logged. Full HLS pipeline activates when FFmpeg is present
(Docker or local install).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Custom video player with hls.js for instant HLS playback with MP4
fallback. Full keyboard-driven controls matching NLE conventions:
Space/K play/pause, J/L skip 5s, arrow/comma/period frame step,
[/] speed, F fullscreen, M mute. Timecode display in HH:MM:SS:FF.
Components:
- video-player.tsx: Core player with HLS/MP4 source loading
- video-controls.tsx: Play, seek, speed, volume, fullscreen, loop
- video-timeline.tsx: Scrub bar with hover time preview + marker slots
- video-frame-display.tsx: Timecode display (HH:MM:SS:FF)
- video-upload-zone.tsx: Drag-drop upload with progress bar (XHR)
- use-video-player.ts: Player state hook with keyboard shortcuts
Review page integration:
- Auto-detects video vs image attachments per revision
- Image/Video toggle when both exist on same revision
- Upload panel extended with video + reference video zones
- VideoPlayer renders in place of ImageViewer when in video mode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FFmpeg in Docker for transcoding, thumbnail extraction, and metadata
parsing. Videos stored in /data/uploads (mounted volume), served via
streaming API route with Range headers and HLS segment caching. Upload
flow: stream-write MP4 → ffprobe metadata → thumbnail → async HLS
transcode → update revision status to ready.
New files:
- video-service.ts: FFmpeg/ffprobe wrapper (HLS, thumbnails, metadata)
- /api/uploads/[...path]: streaming file server with Range support
Modified:
- upload-service.ts: video handling, 500MB limit, async HLS pipeline
- upload route: accepts video/referenceVideo types
- Dockerfile: ffmpeg + /data/uploads directory
- docker-compose.yml: uploads_data volume
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revised A7.1 spec based on lawn-video-reviewer learnings — HLS-first
streaming for instant playback and smooth seeking instead of raw MP4
serving. Key changes: async HLS transcoding on upload, mounted volume
storage (/data/uploads), streaming API route with Range headers, and
processing status tracking on revision attachments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>