Risks· Authexis· Risk register

Risk register

Open, accepted, and closed risks. Every row is real -- nothing omitted.

How to read this register

Severity

HIGH -- Could cause data loss, security breach, production outage, or significant user harm. Needs active mitigation or tracking.

MEDIUM -- Degrades quality, increases tech debt, or creates exploitable surface. Should be tracked and addressed.

LOW -- Minor, low-probability, or well-understood. Monitor but not urgent.

Status

Open -- Active risk. Not yet mitigated or accepted.

Accepted -- Known tradeoff we've deliberately kept. Revisit if conditions change.

Closed -- Resolved. Historical record retained for context.

Open risks

Risk Severity Tracker Last reviewed Notes
Public API contract can ossify internal route leaks HIGH Open 2026-05-12 GH-2230 turns scattered app/mobile routes into a public contract. If /api/v2 is simply documented as-is, Authexis locks in internal field names, inconsistent scope checks, session-oriented errors, and route behavior that MCP may already duplicate in Python. Mitigation: public contract lives under /api/v1, route behavior reuses shared helpers, OpenAPI/docs are source-of-truth, and public MCP calls REST instead of direct DB writes.
Free-tier quota can be bypassed through alternate content ingress paths HIGH Open 2026-05-12 GH-2229 changes free from read-only to capped creation. Authexis has many creation paths: web/actions/content.ts, shared web/lib/content-logic.ts, API v1/v2 content routes, voice memos, Eclectis article creation, tool handoff, and newsletter/content derivative commands. If each path implements its own read-then-write gate, users can bypass limits or race two creations. Mitigation: central tier gate helper plus a transaction-safe quota claim/RPC, then server-side enforcement at every ingress path.
No error boundaries on user-facing routes MEDIUM Open -- #1787 2026-04-11 30 routes lack error.tsx. Errors show raw Next.js crash pages.
MCP OAuth tokens stored in-memory only MEDIUM Open 2026-05-12 Server restart invalidates all active MCP sessions. Refresh tokens valid 30 days but lost on deploy. Consider persisting to DB, or explicitly keep public MCP Phase 1 bearer-key-only while #2369 reworks MCP as a REST adapter. Recovery: run paulos authexis mcp check; if 401, run paulos authexis mcp reauth and restart Claude Code. Full runbook: docs/mcp-setup.md.
10 of 38 engine handlers have no test coverage MEDIUM Open 2026-04-11 Untested: admin_notify_login, maya_sms_reply, onboarding_invite, onboarding_welcome, onboarding_wizard_incomplete, reengagement_check, social_post_generate_hashtags, workspace_import_content, workspace_learn, workspace_scan. Note: page_scrape test exists but in non-standard location (handlers/tests/ instead of tests/).
Silent-failure pattern in engine handlers MEDIUM Open 2026-04-23 Pattern: broad except that returns {"status": "completed"} or empty results, hiding real failures from the poller. Three instances patched in #2204 (briefing email re-raise, newsletter Claude scoring, daily.pipeline step-swallow). Next scout should specifically grep for except Exception: blocks in engine/handlers/ that don't re-raise, emit a *.step_failed event, or write to a scan_log error_message.
Workspace-ownership filter missing on mutating server actions MEDIUM Open -- #2208 2026-04-25 web/actions/content.ts fully swept: #2202 closed 3 (updateField, updateAdaptation, updateAdaptationStatus); #2207 closed 11 more (updateSeoKeywords, updateContentSettings, updateContentMeta, submitForReview, approveStage, rejectStage, restoreToIdea, deleteContent, deleteAdaptationsByContent, redoStage, restartStage). actions/idea.ts already correct. actions/series.ts still vulnerable -- tracked in #2208. actions/integration.ts swept #2238: 8 test*Connection functions (wordpress, github, linkedin, bluesky, mastodon, threads, eclectis, beehiiv) now call requireWorkspaceMembership. actions/newsletter.ts swept #2238: generateNewsletter now membership-checked. actions/settings.ts swept #2238: generateSearchTerms and runBriefingGenerate now membership-checked. Remaining: series.ts per #2208.
Subprocessor disclosure <> SDK <> DSN <> vendor-side project drift MEDIUM Open 2026-05-01 Authexis sits in "claimed + wired" for Sentry today: web (web/sentry.client.config.ts / sentry.server.config.ts / sentry.edge.config.ts / instrumentation.ts) + engine (engine/engine/main.py sentry_sdk.init) + DSN env on Vercel/Railway + project rows authexis / authexis-engine in the synaxis-ai org + privacy disclosure at web/app/privacy/page.tsx. All four sides must move together. Edit one without pair-verifying the others and the doc-vs-reality drift is invisible until prod traffic exercises it (or, worse, a customer reads the privacy page and the disclosure is structurally false). Anchored cross-fleet by diktura #497 (claimed-but-not-wired today, no project materialized in the org) and scholexis 70f6923 (pre-deploy state-transition risk). Discipline: any edit to Sentry SDK config, SENTRY_DSN envs, the third-party-processor list in web/app/privacy/page.tsx, or vendor-side project settings triggers a four-surface pair-check before the commit lands.
Branded output modes can over-invest before export demand is proven MEDIUM Open 2026-05-12 GH-2226 intentionally keeps Phase 2 usage-gated: plain MD/PDF/DOCX shipped first, then branded PDF/DOCX and Google Slides only after telemetry makes demand visible. Native slides-with-theme is the largest scope trap; do not build an in-house deck design engine unless the Google Slides/partner path fails with clear user demand. EPUB is deferred until long-form institutional demand exists.
Eclectis fetch in (app) layout adds latency to every authenticated page load LOW Open 2026-04-24 fetchEclectisArticles runs server-side in app/(app)/layout.tsx on every authenticated page render. Fast path (integration not connected) returns early. Slow path hits eclectis's /api/v1/articles -- normally <200ms but an eclectis outage would slow every authexis page load by the timeout budget. Mitigation options if this becomes real: move to client-side fetch with skeleton state, add a short server-side timeout, or cache per-user for 60s. Monitor if Sentry shows layout render times regressing.
Web frontend test coverage is shallow LOW Open 2026-04-23 Vitest is configured (7 files, 86 tests). Coverage still misses critical paths: Stripe webhook lifecycle (zero tests), auth/magic-link flows, content creation end-to-end. npm test green on main.

Accepted risks

Deliberate tradeoffs. Known, documented, and tolerated by design. Revisit if conditions change.

Risk Severity Last reviewed Notes
Production database used in development MEDIUM 2026-04-11 By design (see DECISIONS.md). Risk: dev queries/mutations affect prod data.

Closed risks

Resolved. Kept as historical record.

Risk Severity Tracker Last reviewed Notes
DALL-E 3 deprecated May 12, 2026 HIGH Closed -- #1963 2026-04-25 Migration complete. engine/engine/services/image.py uses gpt-image-1 (not gpt-image-1.5 as the original row claimed -- that model name was an error). No DALL-E 3 call sites remain in the codebase.
SSRF in user-URL fetchers (web_scraper, page_scrape, voice_infer) MEDIUM Closed -- #1994, #2203 2026-04-23 Original three fetchers (article.py, web_scraper.py, page_scrape.py) covered by url_validation.py (#1994). voice.infer was a later gap -- email-domain fetch without validate_url; closed in #2203. page.scrape also now logs SSRFError at error level (was swallowed as warning).
Unanchored ignore-globs swallow content trees LOW Closed -- #2258 2026-04-26 .vercelignore had bare *.md (added 9f097c9e for CLI-deploy size) which gitignore-matches recursively, silently excluding web/content/resources/*.md from every Vercel build for 24h+ since #2244. listResources() saw an empty content directory at build time, generateStaticParams returned [], every /resources/<slug> returned 404 while the hub returned 200 with no article links. Fix: anchor to /*.md so only repo-root markdown is ignored (65dd0e61). Tripwire for the future: any new ignore file (.vercelignore, .gcloudignore, .dockerignore) should anchor every glob with / unless recursion is intentional, and the commit message should say which. The hub-200/children-404 failure shape gave zero log signal -- failure should be loud, not invisible.