◆ kanex-ai
Fullerton School District Apr 20 2:01 PM
Fullerton School District Celebrates Maple Elementary’s 2026 Green Ribbon Recognition
Maple Elementary School Green Ribbon Recognition announcement from Fullerton School District.
family
Kanex Ai1 Apr 20 1:16 PM
RE: Undeliverable: FW: Cannot add domain sydneeinc.com (and iolocapita... - TrackingID#2604170040009284
Kanex Ai1: RE: Undeliverable: FW: Cannot add domain sydneeinc.com (and
personal
Microsoft Outlook Apr 20 1:12 PM
Undeliverable: FW: Cannot add domain sydneeinc.com (and iolocapita... - TrackingID#2604170040009284
Microsoft Outlook: Undeliverable: FW: Cannot add domain sydneeinc.com (and iolo
employee high
Denise Heinz Apr 20 12:19 PM
Re: Irving- Yan case: Meet and Confer letter and proposal for next steps.
Denise Heinz: Re: Irving- Yan case: Meet and Confer letter and proposal fo
legal-divorce urgent
T Christina Knudsen Apr 20 12:14 PM
[Teams meeting] Inventory/Shipping Team Weekly
Inventory/shipping team weekly: HDCVT SKUs ready to ship.
employee
Newegg Apr 20 12:03 PM
Announcement: 2nd Notice 🚧 CEC - Certified Model Number Requirement
Newegg marketplace compliance notice on CEC certified model number requirements.
vendor
Anthony Patino Apr 20 11:58 AM
Re: [KanexPro Store] Order #1208 placed by Jay Carnevale
Anthony Patino: Re: [KanexPro Store] Order #1208 placed by Jay Carnevale
employee high
iCloud Apr 20 11:42 AM
Hide My Email was used with cheaterscanner.com
iCloud: Hide My Email was used with cheaterscanner.com
vendor
AAA Life Insurance Company Apr 20 10:46 AM
Your insurance payment will be processed soon
AAA Life Insurance payment reminder for policy #3007654936, $166.00.
financial
Tesla Apr 20 10:24 AM
Tesla Service Appointment Confirmation
Tesla service appointment confirmed for April 28 at 11:30 AM.
personal
[email protected] Apr 20 10:05 AM
Get Ready To Join
Invitation to join Lifestyle Medicine Mastermind speaking event today at 2:30 PM EST.
personal low
Prasad Ramakrishnan Apr 20 10:00 AM
Re: Order #1205 confirmed
Customer inquiry about delivery date for order #1205.
vendor
Uber for Business Apr 20 9:54 AM
Your March travel report for KanexPro is ready
March travel report from Uber for Business ready for review.
vendor low
Network Solutions Apr 20 9:53 AM
🔒Protect your domain now!
Spoofed Network Solutions domain privacy upsell with urgency tactics and suspicious sender.
phishing urgent
T Dhruv Sharma Apr 20 8:57 AM
[Teams group] Webteam
Dhruv Sharma acknowledges message in Teams group chat.
employee low
T Aarti Gupta Apr 20 8:57 AM
[Teams group] Webteam
Dhruv Sharma confirms webteam resource is now open.
employee
T Dhruv Sharma Apr 20 8:56 AM
[Teams group] Webteam
Dhruv Sharma from Teams webteam checking in.
employee
T Aarti Gupta Apr 20 8:52 AM
[Teams group] Webteam
Suspicious Teams message requesting passwords from unknown sender.
phishing urgent
T Dhruv Sharma Apr 20 8:50 AM
[Teams oneOnOne] (Teams DM)
Dhruv reports Victor offline for 3-4 days, seeking status.
employee
T Dhruv Sharma Apr 20 8:50 AM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma Teams one-on-one meeting message.
employee
T Christina Knudsen Apr 20 8:49 AM
[Teams group] Webteam
Christina Knudsen acknowledges message in Teams webteam group.
employee low
[email protected] Apr 20 8:49 AM
Notice of Invoices that have been approved over past week
B&H Photo approved invoice notification for reconciliation and records.
vendor
T Dhruv Sharma Apr 20 8:45 AM
[Teams group] Webteam
SSL certificate renewal notice; website access workaround provided.
employee
T Christina Knudsen Apr 20 8:36 AM
[Teams group] Webteam
Intranet access down; Dhruv Sharma asked to investigate.
employee high
Network Solutions Apr 20 8:29 AM
Monthly Account Statement
Fake Network Solutions statement; spoofed sender domain with hex obfuscation.
phishing urgent
T Anthony Patino Apr 20 8:20 AM
[Teams oneOnOne] (Teams DM)
Anthony Patino reports issues with i.kanex infrastructure; needs assistance.
employee high
Network Solutions Apr 20 8:18 AM
Techincal, don’t miss your monthly account review
Spoofed Network Solutions domain impersonating legitimate account review.
phishing urgent
Meta for Business Apr 20 8:07 AM
Your ad was approved
Meta ad approval notification for KanexPro business account.
vendor
T Aarti Gupta Apr 20 7:47 AM
[Teams oneOnOne] (Teams DM)
Aarti Gupta reports error opening Kanex system, needs technical support.
employee high
Liangbo Li Apr 20 6:58 AM
Re: February Expenses
Liangbo Li: Re: February Expenses
employee high
Liangbo Li Apr 20 6:57 AM
Re: SP-HDPOC1X8
Liangbo Li: Re: SP-HDPOC1X8
employee high
Apeksha Arun Shetvernekar Apr 20 6:35 AM
Cannot add domain sydneeinc.com (and iolocapita... - TrackingID#2604170040009284
Apeksha Arun Shetvernekar: Cannot add domain sydneeinc.com (and iolocapita... - Trackin
vendor
Intuit Developer Group Apr 20 6:07 AM
Intuit Critical Alert: Reminder to migrate to the new webhooks payload
Intuit webhooks migration required by May 15, 2026 deadline.
vendor high
Intuit Developer Group Apr 20 6:06 AM
Intuit Critical Alert: Reminder to migrate to the new webhooks payload
Intuit webhooks migration deadline May 15 — QB Online integration required.
vendor high
Newegg Apr 20 5:30 AM
Announcement: 2nd Notice 🚧 CEC - Certified Model Number Requirement
Newegg marketplace compliance notice on CEC certification requirements for gaming products.
vendor
[email protected] Apr 20 5:30 AM
Open Stocking & DS PO Report-KANEX PRO INC-59515-4202026
TD Synnex requesting open PO report status for KanexPro shipments.
vendor
Benjamin & Williams Apr 20 5:02 AM
Commercial Claim Discovery Documents Our file:D-8222 Debtor: VICTORIA ROPA ELEGANTE
Fake debt collector impersonating law firm; demands payment within 24h.
phishing urgent
Intuit Apr 20 4:22 AM
We received your Intuit subscription payment!
Intuit subscription payment confirmation for $38.00
financial
Sydnee Agent (AI) Apr 20 4:20 AM
Sydnee nightly — entry_flow audit 2026-04-20 — 0P0 3P1 2R
Sydnee Agent (AI): Sydnee nightly — entry_flow audit 2026-04-20 — 0P0 3P1 2R
personal
SoCalGas Apr 20 4:06 AM
SoCalGas Bill Tracker Update
SoCalGas: SoCalGas Bill Tracker Update
personal
Kanex Ai1 Apr 20 2:10 AM
RE: Email push
Kanex Ai1: RE: Email push
personal
Kelvin Yan Apr 20 2:08 AM
Test
Kelvin Yan: Test
personal
Kanex Ai1 Apr 20 2:07 AM
RE: Email push
Kanex Ai1: RE: Email push
personal
Kanex Ai1 Apr 20 2:03 AM
RE: Email push
Kanex Ai1: RE: Email push
personal
Kanex Ai1 Apr 20 2:01 AM
RE: Email push
Kanex Ai1: RE: Email push
personal
Kanex Ai1 Apr 20 1:39 AM
RE: Email push
Kanex Ai1: RE: Email push
personal
Kanex Ai1 Apr 20 1:37 AM
RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MSTR and $GLXY-Video 10 of 10 (April 19, 2026)
Kanex Ai1: RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MS
personal
Kanex Ai1 Apr 20 1:34 AM
RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MSTR and $GLXY-Video 10 of 10 (April 19, 2026)
Kanex Ai1: RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MS
personal
Kanex Ai1 Apr 20 1:32 AM
RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MSTR and $GLXY-Video 10 of 10 (April 19, 2026)
Kanex Ai1: RE: Undeliverable: FW: Dr Cat's Video Insights on $COIN, $MS
personal
KanexPro Store (Shopify) Apr 19 11:49 PM
Payout for Apr 20, 2026 ($2,885.63 USD)
KanexPro Store (Shopify): Payout for Apr 20, 2026 ($2,885.63 USD)
vendor

Sydnee WEEKLY (cross-cutting) audit 2026-04-19 — 2P0 11P1 0R

Sydnee Agent (AI) <[email protected]>
Sunday Apr 19, 2026 · 11:54 AM PT · in [email protected]
AI verdict  personal normal · confidence: high · by self-identity
“Sydnee Agent (AI): Sydnee WEEKLY (cross-cutting) audit 2026-04-19 — 2P0 11P1 0R”
Reasoning: sender is one of Kelvin's own addresses (me_identities), phishing check passed
Sydnee WEEKLY (cross-cutting) audit — 2026-04-19 P0 findings: 2 P1 findings: 11 Risks: 0 - Commits since last weekly: 148 (first weekly audit, covers full recent history) - Files changed (approx last 20 commits): 7 files, +824/-211 lines - Core file sizes: bot.py 13,107 lines · pages.py 8,242 lines · polygon_client.py 429 · strategy.py 115 - **P0:** 1 · **P1:** 10 · Dead code: 3 · Security: 2 · Doc drift: 1 · Perf: 2 · Config/deploy: 3 High-tempo week: 148 commits covering new exit flags (FLAT_EXIT, HOLD_CAP_MIN, OBV_LOSS_EXIT), RSI peak-confirm state machine, sydnee.swing ingestion, UI consolidations, and multiple audit fixes. One P0 SQL injection; ten P1s spanning config default mismatches, dead files, and schema drift. --- Full report (dev branch): https://github.com/kanex1/sydnee.signals/blob/dev/docs/audit_2026-04-19_weekly.md Reply FROM [email protected] to [email protected] to request fixes, e.g.: "code_task on sydnee-signals-dev: apply fix for the P0 about RVOL threshold in bot.py" Sydnee Agent will propose + you APPROVE (or plain 'approve') + auto-push to dev. --- Full audit below (first 12 KB) --- # Weekly Code Audit 2026-04-19 ## Summary - Commits since last weekly: 148 (first weekly audit, covers full recent history) - Files changed (approx last 20 commits): 7 files, +824/-211 lines - Core file sizes: bot.py 13,107 lines · pages.py 8,242 lines · polygon_client.py 429 · strategy.py 115 - **P0:** 1 · **P1:** 10 · Dead code: 3 · Security: 2 · Doc drift: 1 · Perf: 2 · Config/deploy: 3 High-tempo week: 148 commits covering new exit flags (FLAT_EXIT, HOLD_CAP_MIN, OBV_LOSS_EXIT), RSI peak-confirm state machine, sydnee.swing ingestion, UI consolidations, and multiple audit fixes. One P0 SQL injection; ten P1s spanning config default mismatches, dead files, and schema drift. --- ## Findings ### [SECURITY] P0: SQL injection via Python `%` string formatting in `get_api_usage_summary()` **Files:** `core/database.py:618–621` **Evidence:** ```python # core/database.py:618-621 cur.execute(""" SELECT ... WHERE u.timestamp > NOW() - INTERVAL '%s days' """ % days) ``` The `days` value originates from a user-supplied query parameter: `bot.py:9503` → `request.args.get("days", 30)` → `self.db.get_api_usage_summary(days)` → `database.py:621 % days`. Python `%` string formatting is used instead of psycopg2 parameterization — the value is interpolated directly into the SQL string before it reaches the database driver. A request like `GET /api/usage?days=1;DROP TABLE trades--` would execute arbitrary SQL. Compare with the safe pattern used elsewhere in the same file (e.g., database.py:544): `INTERVAL '%s days'` with `(days, ...)` as psycopg2 positional params — psycopg2 substitutes correctly into the interval literal. **Impact:** Unauthenticated? No — the route is protected by `before_request`. But any authenticated session (or anyone with the API key, currently defaulting to "8881") can drop tables or exfiltrate data. At real-money go-live with live positions and P&L data in the DB, this is critical. **Recommendation:** Replace the `% days` formatting with a parameterized query: ```python cur.execute(""" SELECT ... WHERE u.timestamp > NOW() - INTERVAL '%s days' """, (int(days),)) ``` Also validate `days` is an integer before passing to the DB layer. --- ### [DOC DRIFT] P1: CLAUDE.md entry-time table diverged from code **Files:** `CLAUDE.md` table vs `bot.py:3574–3598` **Evidence:** CLAUDE.md table lists these PT windows: | Window | Rule | |---|---| | 08:30 – 10:30 PT | BXt blocked (midday low-conviction) | | 12:00 onwards PT | BXt blocked (R:R decay) | | 12:45 – 13:00 PT | only rsi_extreme (close window) | Code at bot.py:3574–3598 implements: ```python in_open_30 = 9*60+30 <= t_min < 10*60 # 9:30-10:00 ET = 06:30-07:00 PT in_close_hour = 15*60 <= t_min < 16*60 # 3:00-4:00 PM ET = 12:00-13:00 PT ``` - The **08:30–10:30 PT BXt midday block** (= 11:30 AM–1:30 PM ET) does not exist in code. - The **close window** in code is the full 60 min (12:00–13:00 PT), not just 12:45–13:00 PT as documented. - The opening block in code is 06:30–07:00 PT (30 min), **not** what the table implies (the table only lists it under "outside 06:30–13:00" rule). **Impact:** Anyone reading CLAUDE.md to understand trade timing gets wrong expectations. Could lead to mis-diagnosis of why BXt entries are or aren't firing. Also the "(dev only)" label on the off-hours gate is misleading — code applies the same gate to prod. **Recommendation:** Rewrite the CLAUDE.md table to match code exactly. The accurate rules are: - 03:50–04:00 AM ET (00:50–01:00 PT): all blocked - 09:30–10:00 AM ET (06:30–07:00 PT): non-rsi_extreme blocked - 15:00–16:00 ET (12:00–13:00 PT): non-rsi_extreme blocked - Outside 09:30–16:00 ET: non-rsi_extreme blocked Remove the 08:30–10:30 PT BXt row; it never existed in code (or re-add the gate if it was intended). --- ### [DEAD CODE / PERF] P1: Feature-flag env vars read inline per-bar (4 flags, 6+ reads) **Files:** `bot.py:2925, 2969, 3336, 3477, 4334` **Evidence:** ```python # bot.py:2925 (OBV exit loop — runs on every tick) _loss_exit = os.environ.get("OBV_LOSS_EXIT", "").lower() in ("1", "true", "yes") # bot.py:2969 (exit loop) _hold_cap_raw = os.environ.get("HOLD_CAP_MIN", "").strip() # bot.py:3336 (trim path, every bar) _flat_exit = os.environ.get("FLAT_EXIT", "").lower() in ("1", "true", "yes") # bot.py:4334 (entry sizing, every bar) if os.environ.get("FLAT_EXIT", "").lower() in ("1", "true", "yes") ... # bot.py:3477 (RSI peak-confirm, every signal) os.environ.get("RSI_PEAK_CONFIRM_RTH", "").lower() in ("1", "true", "yes") ``` FLAT_EXIT is read in **two separate code paths** (3336 exit and 4334 entry-sizing) with no shared binding. **Impact:** Four `os.environ.get()` calls per bar × (number of open positions) × (bar frequency). Not measurable overhead today but sets bad precedent. More critically, FLAT_EXIT's two read sites could diverge if one is refactored. No single place to see all active flags. **Recommendation:** Cache at module/class level or at `start()`: ```python # At DayTradeBot.start() or module level FLAT_EXIT = os.environ.get("FLAT_EXIT", "").lower() in ("1", "true", "yes") OBV_LOSS_EXIT = os.environ.get("OBV_LOSS_EXIT", "").lower() in ("1", "true", "yes") HOLD_CAP_MIN = int(os.environ.get("HOLD_CAP_MIN") or 0) RSI_PEAK_CONFIRM_RTH = os.environ.get("RSI_PEAK_CONFIRM_RTH", "").lower() in ("1", "true", "yes") ``` --- ### [SECURITY] P1: API key "8881" hardcoded in client-side JavaScript **Files:** `pages.py:5270, 5357, 5657, 5925, 5930, 5933` **Evidence:** ```javascript // pages.py:5270 fetch('/api/stocks/add',{headers:{'X-API-Key':'8881'}, ...}) // pages.py:5357 apiPost("/api/screener/run",{market:market,password:"8881"}) // pages.py:5657, 5925, 5930, 5933 — same literal "8881" ``` Server-side: `bot.py:8478` — `API_KEY = os.environ.get("API_KEY", "8881")` **Impact:** If the `API_KEY` env var is rotated (e.g., at real-money go-live), all client-side JS calls will send the wrong key and fail with 401. The client has no way to know the real key since it's hardcoded at template-render time. The key is also visible in plaintext in the rendered HTML source to any logged-in browser session (though the dashboard itself requires login, so blast radius is limited to already-authenticated users). **Recommendation:** Inject the API key into a JS variable via server-side template rendering, or pass it via a cookie/meta tag at login: ```python # In each page render: return render_template_string(PAGE, api_key=API_KEY) # In page JS: const API_KEY = "{{ api_key }}"; ``` Alternatively, since the dashboard requires session auth anyway, the JS endpoints could rely on the session cookie instead of the API key — remove the key from client JS entirely. --- ### [DEPLOYMENT DRIFT] P1: `trading_stocks` table absent from schema.sql **Files:** `core/database.py:1981–2107` vs `core/schema.sql` **Evidence:** `database.py` defines and calls `get_trading_stock()`, `get_trading_stocks()`, `upsert_trading_stock()`, `update_trading_stock()` — all referencing `trading_stocks`. The table has at least 8 columns (symbol, company_name, sector, added_by, status, added_date, updated_at, plus upsert ON CONFLICT implies a UNIQUE on symbol). `core/schema.sql` has 100+ tables defined but `trading_stocks` does not appear anywhere in the file (confirmed by `grep -c`). **Impact:** A fresh `psql < schema.sql` followed by starting the bot would immediately fail on any `/api/stocks/*` route. The table exists on dev/prod only because it was created manually or via a migration that isn't tracked. This is a silent ops risk for any rebuild, new environment, or disaster-recovery scenario. **Recommendation:** Add to schema.sql: ```sql CREATE TABLE IF NOT EXISTS trading_stocks ( symbol VARCHAR(20) PRIMARY KEY, company_name VARCHAR(200) DEFAULT '', sector VARCHAR(100) DEFAULT '', added_by VARCHAR(50) DEFAULT 'human', status VARCHAR(20) DEFAULT 'active', added_date DATE DEFAULT CURRENT_DATE, updated_at TIMESTAMPTZ DEFAULT NOW() ); ``` --- ### [CONFIG SPRAWL] P1: Critical config fallback mismatches — risk limits and position sizing **Files:** `bot.py:602–609` vs `config.json:3–8` **Evidence:** | Key | config.json | bot.py fallback | Ratio | |---|---|---|---| | `capital` | 50,000 | **25,000** (bot.py:602) | 2× too small | | `daily_loss_limit` | 50,000 | **1,000** (bot.py:606) | **50× too small** | | `max_daily_trades` | 50 | **6** (bot.py:607) | 8× too small | | `max_shares` | 50,000 | **500** (bot.py:608) | 100× too small | | `max_concurrent_positions` | 50 | **3** (bot.py:609) *and* **5** (bot.py:6442, 6530) | inconsistent | **Impact:** If config.json fails to load (file missing, JSON parse error, key renamed), the bot falls back to a $1,000 daily loss limit instead of $50,000. In a live-trading context, the bot halts after a $1K drawdown — abandoning potentially valid positions mid-session. Conversely, if `capital` reads 25K instead of 50K, position sizing is halved, silently. `max_concurrent_positions` has **two different fallback values** (3 and 5) at different call sites — whichever fires depends on code path. **Recommendation:** Either align all fallbacks to match config.json values, or remove fallbacks entirely for safety-critical keys and fail loudly on startup if config is missing. At minimum, log all resolved values at startup so they're visible in container logs. --- ### [CONFIG SPRAWL] P1: `atr_stop_multiplier` fallback diverges from config.json value **Files:** `config.json:5` vs `bot.py:591` **Evidence:** ```json // config.json "atr_stop_multiplier": 1.5 ``` ```python # bot.py:591 self.atr_stop_mult = self.cfg.get("atr_stop_multiplier", 2.0) ``` Fallback default is `2.0` (33% larger than the config value of `1.5`). Same pattern for `atr_target_multiplier`: config says `2.5`, bot default says `2.5` — that one matches. But the stop multiplier has drifted. **Impact:** If config.json is missing or the key is absent (e.g., a new symbol profile that inherits the global), stops will be 33% wider than intended. In a real-money context with a 2% risk-per-trade, a 33% wider stop translates to proportionally larger dollar risk. **Recommendation:** Align the fallback: `self.cfg.get("atr_stop_multiplier", 1.5)`. Also add a startup log line that prints the resolved stop/target multipliers so they're visible in logs. --- ### [CONFIG SPRAWL] P1: Symbol/cashtag drift in config.json **Files:** `config.json:2` (symbols) vs `config.json:37` (cashtags) **Evidence:** ``` symbols: WDC, STX, MU, SNDK, APP, META, TSLA, PLTR cashtags: APP, KORU, MU, SNDK, STX, WDC ``` - **TSLA, META, PLTR** — actively traded but receive no sentiment monitoring. - **KORU** — sentiment-monitored but not in the trading symbols list; sentiment signals for it will be collected but never influence a trade. **Impact:** TSLA is a high-volatility, news-sensitive stock. Trading it without sentiment context means the bot can enter on a technical signal while a breaking adverse headline is in progress — the sentiment emergency-exit gate won't fire for it. **Recommendation:** Either add TSLA/META/PLTR to cashtags (and add relevant sector_keywords), or acknowledge the gap with a comment. Remove KORU from cashtags if it isn't in the trading symbols and won't be soon. --- ### [DEAD CODE] P1: `strategy.py` and `core/dashboard.py` — two fully dead files **Files:** `strategy.py` (115 lines) · `core/dashboard.py` (204 lines) **Evidence:** - `strategy.py` defines `BXtrenderStrategy` class with full entry/exit logic and `StrategyConfig` dataclass. Zero imports of this file exist anywhere in the codebase (`grep -rn "from strategy import\|import strategy"` returns nothing). The live bot re-implements all the same logic inline in bot.py. - `core/dashboard.py` defines `BotDashboard` class (204 lines). Not imported by bot.py or pages.py. The live bot builds its own Flask app in `_run_dashboard()` inside bot.py:8438+. core/dashbo