- Implement CaptionResult frozen dataclass for structured caption data
- Add parse_srt() to parse SubRip format with flexible timestamp handling
- Add extract_captions() async function using yt-dlp subprocess wrapper
- Prefer manual captions over auto-generated; clean up SRT files after parsing
- Add 16 comprehensive tests covering edge cases (empty input, malformed SRT,
timestamp variations, language extraction, manual vs auto selection)
- Type-safe implementation with full mypy --strict compliance
- Add sample.srt fixture with 3 segments mentioning NVDA for test reference
- Replace all Literal[...] type annotations with corresponding enum classes
(TickerAction, TimeHorizon, MarketOutlook, VideoStatus, TranscriptSource)
for MeetKevinTickerMention, MeetKevinAnalysis, and API response models
(VideoSummary, VideoDetail, StockMention, StockSummary, TimelineBucket)
- Add min_length=1, max_length=10 validation to MeetKevinTickerMention.symbol
- Split test_conviction_edge_cases into two separate boundary tests
- Strengthen test_valid_ticker_mention with assertions for all 6 fields
- Trim no-information docstrings from TranscriptSegment, StockTimeline
- All 60 schema tests pass
22-task plan across 6 phases (data layer, watcher service stages,
API gateway, dashboard, container/deps, K8s revival). Each task
includes TDD checkboxes, file paths, acceptance criteria, and
commit commands. References the design doc (ab382af) for schemas,
prompts, and the Terraform diff.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Design for reviving the trading-bot K8s stack with a new Meet Kevin
YouTube watcher pipeline. v1 scope: poll RSS every 3h, extract
captions via yt-dlp, run transcript through Claude Sonnet 4.6 for
structured per-ticker recommendations and market outlook, surface
in a new ticker-centric UI under /meet-kevin/*. Bot integration
(signal_generator) and auto-trading deferred to v2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- TradeLog: use created_at (from API) instead of timestamp for date display
- EquityCurve: deduplicate data by day before passing to lightweight-charts,
preventing "data must be asc ordered by time" assertion failure when
multiple snapshots exist on the same day
Made-with: Cursor
The buildx plugin was not passing NGINX_CONF build arg correctly,
causing the docker-compose nginx config (with hostname api-gateway)
to be used instead of the K8s one (with localhost).
- Replace pip with uv in Dockerfile.service builder stage (~5-10x faster)
- Replace pip with uv in CI test step
- Separate pyproject.toml copy from source copy in Dockerfile for better
Docker layer caching (deps only reinstalled when pyproject.toml changes)
- Add cache_from for buildx to reuse layers from previous builds
- Remove pip cache workaround from test step (not persisted in K8s)
The woodpeckerci/plugin-docker-buildx was not passing the EXTRAS build
arg correctly (commas in the value were likely being parsed as list
separators), causing the image to only install dev dependencies instead
of all service extras (api, news, sentiment, trading, backtester).
Hardcode the pip install extras directly in the Dockerfile rather than
relying on the build arg.
- Learning engine: expand default weights from 3 to all 9 strategies
- Learning engine: resolve placeholder strategy_id with DB lookup
- Learning engine: pass strategy_sources from trade execution
- Trade executor: respect trading:paused Redis flag in RiskManager
- Portfolio sync: compute actual daily P&L from day-start snapshot
- Portfolio API: cumulative P&L from first snapshot, read pause flag
- Portfolio metrics: compute max drawdown and avg hold duration
- Add strategy_sources field to TradeExecution schema
- Add dev_mode config (TRADING_DEV_MODE) to bypass auth for local dev
- Dashboard: VITE_DEV_MODE bypasses ProtectedRoute and 401 redirects
- Vite proxy target configurable via VITE_API_TARGET
- Add top-level README.md and remaining-work-plan.md
- Update CLAUDE.md with correct counts and remove stale TODOs
- 404 tests passing
Made-with: Cursor
The publish-images step used an alpine container to run skopeo for
re-tagging, but intermittent DNS failures prevent apk from installing
packages. Instead, have the buildx plugin push with both the pipeline
number tag and latest tag directly, eliminating the extra step.
The alembic migration unconditionally called create_hypertable() which
fails if TimescaleDB isn't installed on the PostgreSQL instance. Wrap
in a DO block that checks for the extension first.
Woodpecker pre-processes ${VAR} syntax as CI variables, replacing
undefined ones with empty strings. Use $$ escaping for shell variables
to prevent Woodpecker from consuming them. The ${REPO} variable in
the skopeo publish step was being replaced with empty string.
plugins/docker does not get privileged: true in K8s pods despite being
in WOODPECKER_PLUGINS_PRIVILEGED. woodpeckerci/plugin-docker-buildx
correctly receives privileged mode. Previous build failure with buildx
was a transient network timeout reaching registry-1.docker.io.
The woodpeckerci/plugin-docker-buildx plugin started dockerd correctly
(privileged mode works) but failed DockerHub authentication. Switch back
to plugins/docker which is proven working in realestate-crawler pipeline.
- Use woodpeckerci/plugin-docker-buildx instead of plugins/docker to fix
Docker daemon connection failures (privileged mode not applied)
- Add pip dependency caching between builds via /woodpecker/pip-cache
- Fix slack plugin image (plugins/slack, not woodpeckerci/plugin-slack)
- Use proper buildx cache_from syntax (type=registry,ref=...)
Backend falls back to fetched_at when published_at is NULL in the database,
so the API always returns a meaningful date. Frontend also handles null
defensively to avoid new Date(null) producing Unix epoch 0.
Create nginx-k8s.conf that proxies to localhost:8000 instead of
api-gateway:8000 for K8s pods where both containers share a network
namespace. Update Dockerfile.dashboard to accept a NGINX_CONF build arg
(defaults to docker/nginx.conf for docker-compose compatibility).
- Change BacktestRequest from strategy_weights dict to strategies list to match frontend
- Add tickers field so users can select which stocks to backtest
- Fetch historical bars from Alpaca StockHistoricalDataClient instead of empty data loader
- Register all 9 strategies (momentum, mean_reversion, news_driven, value, macd_crossover,
bollinger_breakout, vwap, liquidity, ma_stack) filtered by user selection
- Fix response format: use frontend field names (max_drawdown, total_trades, win_rate as
0-1 decimal), include equity_curve and run_id in response
- Add ticker selector with checkboxes and custom ticker input to dashboard
- Add alpaca-py to api dependency group in pyproject.toml
8 tasks covering: MarketSnapshot schema changes, indicator computations,
fundamental data providers, DB caching, 6 new strategies, signal generator
wiring, and deployment steps.
6 new strategies (Value, MACD Crossover, Bollinger Breakout, VWAP,
Liquidity, MA Stack) plus fundamental data pipeline with 3 providers
(Alpha Vantage, FMP, Yahoo Finance) and DB-backed caching.
ArticleSentiment referenced db_article.id before the Article was flushed,
causing a NotNullViolationError on the article_id column. Adding an explicit
flush after session.add(db_article) ensures the UUID is populated before
creating the foreign key reference.