All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Versioning note. The active version line is
0.x. The repository also carries older tags (v9.0.0,v6.0.0,v1.6.0,v1.0.0) from a prior numbering scheme; they are historical and do not supersede this line.Tag offset for 0.3.0 — read this before checking out
v0.3.0. Thev0.3.0tag was cut atd63671cc(PR #54), one commit before PR #55 landed the version bump and this changelog entry. Sov0.3.0still carriesversion = "0.2.0"inpyproject.tomland has no[0.3.0]section here. The release described below isv0.3.1(75b6b3a0), which is wherepyproject.tomlreads0.3.0. The tags are left as published rather than force-moved; this note is the correction.
0.4.0 - 2026-09-20
Major architecture transition to declarative workflows, dynamic agent registry, unified LLM tier bindings, Next.js 15 UI extensions, and streamlined single-box operations.
- Declarative Workflow DAG engine (
src/infrastructure/workflow/loader.py,config/workflows/) supporting YAML-driven execution graphs, code node registry, parallel execution layers, and hot-reloading - Dynamic Agent Registry (
src/agents/registry.py,src/agents/impls.py,config/agents/) enabling declarative agent persona definitions and skill bindings - Unified model routing with tier-based configuration (
config/llm_tiers.yaml,config/data_providers.yaml,src/services/cost_profile_service.py) - Turnkey onboarding and single-box operations (
install.sh,scripts/onboarding_wizard.py, rewrittenstart.sh) - Next.js 15 frontend management pages for workflows, agents, extensions, and runtime settings (
frontend/src/app/workflows/,frontend/src/app/agents/, etc.) - Discord channel notification adapter (
src/infrastructure/channels/discord_adapter.py,config/channels.yaml) - Comprehensive test suites covering DAG workflows, dynamic agent registry, and security sanitization (over 2,800 tests)
- Refactored
start.shfrom a 1000+ line script into an operational control CLI tailored for single-box deployments - Re-architected optional dependencies in
pyproject.tomlto prevent GPU/PyTorch bloating in default Docker environments - Replaced hardcoded model configurations with declarative provider catalog and budget-aware tier bindings
- Fixed unawaited coroutines in async service methods
- Cleaned up obsolete database schema references and legacy test cases
- Bumps in uv dependency groups (aiohttp, cryptography, urllib3, soupsieve) and npm packages (Next.js 16.3.3)
0.3.0 - 2026-08-26
Released as tag v0.3.1 — see the tag-offset note above.
First release since v0.2.1 (2026-05-10), covering 83 commits. Headline theme:
the eToro credential incident and the class of silent failures it exposed —
paths that logged an error, returned something plausible, and were never
noticed. See PRs #45, #47, #50, #53, #54.
021_backfill_integrity_checksmigration, idempotently installing the ten CHECK constraints ontransactionsandposition_lotsthat prod never received (#54)- SELL-side churn protection in
TradingProtectionsService, kept fail-open so a query failure cannot lock a user into a position (#50) - Redis
SETNXlock on the Sentinel tick, removing ~18 duplicate paid LLM calls per trading day (#50) weekly-report-triggernow dispatchesWeeklyWorkflow.run_weekly_cycle(); it previously pointed atdispatch_market_intelligence, so no weekly report had ever been generated (#53)- Webhook duplicate detection via URL /
signal_idinWebhookService(#47) - DB schema normalization with updated models and Alembic migration (Phase 1)
- LLM Gateway TTL caching and config chain optimization (Phase 2)
- Sentinel D10 allocation drift detection in
_do_send_alert(Phase 4) - TelegramAdapter with comprehensive unit tests and stabilized dependencies (Phase 5)
BrokerFactorycache fingerprint no longer hashes credentials; it derives from non-sensitive values plus the credential row'ssettings.updated_at, clearing two HIGH CodeQLpy/weak-sensitive-data-hashingalerts at the source rather than suppressing them (#50)InteractionServicestate moved from in-process dictionaries to shared Redis, fixing approval-action desync between the API and worker containers (#47)- Settings writes changed from fire-and-forget to synchronous so callers see the real result (#50)
- Each repository now owns its session; the shared global registry is gone (#50)
- Notification category mapping normalized (
rebalance→trading,daily_digest→report) to match the UI settings (#47) - Consolidated agents:
macro_agentlogic merged intomacro_scout_agent(Phase 3) - Rebalanced complexity detector weights in V2 for improved cognitive layer routing (Phase 6)
- Removed
"list"fromDEESCALATING_KEYWORDSin V1 complexity detector (Phase 6)
UserFocusService.get_user_focus()was synchronous whileEtoroService.get_watchlists()isasync, so the coroutine was never awaited; the resulting'coroutine' object has no attribute 'get'was swallowed by a blanketexcept Exception, leaving user focus permanently empty. Nowasyncand awaited at bothCouncilServicecall sites- OpenRouter transport failures logged as a bare
OpenRouter API error:with an empty message, becausestr(e)is empty forConnectError/ReadTimeout. Both the request and stream paths now log the exception type and model save_positions()wrote topositions, a table dropped byf9861a2caa12during the v8 normalization. Every 5-minutesync_broker_positionsraisedUndefinedTableand, sharing onetry, silently skipped the two steps after it —position_lotsseeding andupdate_daily_snapshot. The dead method is removed and the Celery task now reports the service's error status instead of discarding it and returning"Success"(#54)chk_tx_qty_positiveasserted an unconditionalquantity > 0, which DEPOSIT / WITHDRAWAL legitimately violate (cash movements have no instrument); the constraint is now scoped (#54)SentinelService.close()calledsettings_service.repo, which has never existed — a guaranteedAttributeErrorthat, sharing atrywith the keyword close, leaked two sessions per call. Each close is now caught independently and named in the log (#53)- eToro credentials were misclassified as mock data by a hardcoded prefix check and wiped; the check is removed and the portfolio cache isolated (#50)
RiskManagernow coercesai_trading_enabledwithstr()before reading it, so a JSON boolean no longer breaks.lower()on everyexecute_order(#50)- BUY-side protection queries changed to fail-closed (#50)
- Broker cache now reflects credential and mode changes immediately;
a missing
etoro_modedefaults todemo(#50) - Telegram conversation agent async crash from invalid
to_threadcalls (#45) - MCP WebSocket broadcast loop crash from undefined
summary/positions(#47) - Broken imports/references in
experience_replay_service.pyandmemory_distillation_service.py(Phase 3) - Lowered confidence fallback threshold to 0.4 in
ComplexityDetectorto prevent unintended downgrades (Phase 6) - Signature mismatch in
StructuralFeatures.complexity_score()regardingtext_length(Phase 6)
src/utils/crypto_utils.py, dead code carrying a hardcoded Fernet key used as the "insecure default" whenMASTER_CRYPTO_KEYis absent — and that variable appears in no compose file, k8s manifest or.env.example, so the hardcoded key was the only reachable path. Added toDELETED_MODULESso importing it fails rather than reviving the key. Encryption at rest goes throughAPP_SECRET_KEY/LLM_CREDENTIAL_KEY(#53)- Duplicate Sentinel beat schedule overlapping the minutely tick (#50)
- Redundant prompt files:
prompts/fundamental_scout_agent.txt,prompts/macro_agent.txt,prompts/momentum_scout_agent.txt(Phase 3) - Obsolete Alembic migrations related to cost tracking (Phase 1)
- All 5 CodeQL alerts and 2 bandit medium findings fixed at the source, with no suppressions or dismissals (#50)
secret-scan.ymlonly scanned the PR commit range, so a secret older than every current branch was invisible to CI (#53)
- uv group bumps (#46, #48, #52), npm/yarn group bump (#51), axios (#49)