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.
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
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
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
T Christina Knudsen
Apr 20 12:14 PM
[Teams meeting] Inventory/Shipping Team Weekly
Inventory/shipping team weekly: HDCVT SKUs ready to ship.
Newegg
Apr 20 12:03 PM
Announcement: 2nd Notice 🚧 CEC - Certified Model Number Requirement
Newegg marketplace compliance notice on CEC certified model number requirements.
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
iCloud
Apr 20 11:42 AM
Hide My Email was used with cheaterscanner.com
iCloud: Hide My Email was used with cheaterscanner.com
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.
Tesla
Apr 20 10:24 AM
Tesla Service Appointment Confirmation
Tesla service appointment confirmed for April 28 at 11:30 AM.
[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.
Prasad Ramakrishnan
Apr 20 10:00 AM
Re: Order #1205 confirmed
Customer inquiry about delivery date for order #1205.
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.
Network Solutions
Apr 20 9:53 AM
🔒Protect your domain now!
Spoofed Network Solutions domain privacy upsell with urgency tactics and suspicious sender.
T Dhruv Sharma
Apr 20 8:57 AM
[Teams group] Webteam
Dhruv Sharma acknowledges message in Teams group chat.
T Aarti Gupta
Apr 20 8:57 AM
[Teams group] Webteam
Dhruv Sharma confirms webteam resource is now open.
T Dhruv Sharma
Apr 20 8:56 AM
[Teams group] Webteam
Dhruv Sharma from Teams webteam checking in.
T Aarti Gupta
Apr 20 8:52 AM
[Teams group] Webteam
Suspicious Teams message requesting passwords from unknown sender.
T Dhruv Sharma
Apr 20 8:50 AM
[Teams oneOnOne] (Teams DM)
Dhruv reports Victor offline for 3-4 days, seeking status.
T Dhruv Sharma
Apr 20 8:50 AM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma Teams one-on-one meeting message.
T Christina Knudsen
Apr 20 8:49 AM
[Teams group] Webteam
Christina Knudsen acknowledges message in Teams webteam group.
[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.
T Dhruv Sharma
Apr 20 8:45 AM
[Teams group] Webteam
SSL certificate renewal notice; website access workaround provided.
T Christina Knudsen
Apr 20 8:36 AM
[Teams group] Webteam
Intranet access down; Dhruv Sharma asked to investigate.
Network Solutions
Apr 20 8:29 AM
Monthly Account Statement
Fake Network Solutions statement; spoofed sender domain with hex obfuscation.
T Anthony Patino
Apr 20 8:20 AM
[Teams oneOnOne] (Teams DM)
Anthony Patino reports issues with i.kanex infrastructure; needs assistance.
Network Solutions
Apr 20 8:18 AM
Techincal, don’t miss your monthly account review
Spoofed Network Solutions domain impersonating legitimate account review.
Meta for Business
Apr 20 8:07 AM
Your ad was approved
Meta ad approval notification for KanexPro business account.
T Aarti Gupta
Apr 20 7:47 AM
[Teams oneOnOne] (Teams DM)
Aarti Gupta reports error opening Kanex system, needs technical support.
Liangbo Li
Apr 20 6:58 AM
Re: February Expenses
Liangbo Li: Re: February Expenses
Liangbo Li
Apr 20 6:57 AM
Re: SP-HDPOC1X8
Liangbo Li: Re: SP-HDPOC1X8
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
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.
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.
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.
[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.
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.
Intuit
Apr 20 4:22 AM
We received your Intuit subscription payment!
Intuit subscription payment confirmation for $38.00
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
SoCalGas
Apr 20 4:06 AM
SoCalGas Bill Tracker Update
SoCalGas: SoCalGas Bill Tracker Update
Kanex Ai1
Apr 20 2:10 AM
RE: Email push
Kanex Ai1: RE: Email push
Kelvin Yan
Apr 20 2:08 AM
Test
Kelvin Yan: Test
Kanex Ai1
Apr 20 2:07 AM
RE: Email push
Kanex Ai1: RE: Email push
Kanex Ai1
Apr 20 2:03 AM
RE: Email push
Kanex Ai1: RE: Email push
Kanex Ai1
Apr 20 2:01 AM
RE: Email push
Kanex Ai1: RE: Email push
Kanex Ai1
Apr 20 1:39 AM
RE: Email push
Kanex Ai1: RE: Email push
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
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
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
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)
Sydnee WEEKLY (cross-cutting) audit 2026-04-19 — 2P0 11P1 0R
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