diff --git a/DECISIONS.md b/DECISIONS.md index becafc8f..b310abdc 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1495,3 +1495,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-09-02] Removed the skattekonto drift email (skattekonto.drift_detected event, handler, /api/extensions/skatteverket/skattekonto/drift route, cron hook) instead of fixing it: it alerted on raw saldo-vs-1630 gaps that unbooked rows explain by construction (2026-09-02: Arcim 35 842 kr, 100% explained, while the Hem notice and reconciliation page said nothing was wrong), repeated every 24 h, and was the only surface of a May-2026 feature whose promised dashboard tile was never built. Since 2026-08-25 the reconciliation page and the Hem notice (detectSkvUnexplained, gated on unexplained_difference) are the surface. Considered gating the mail on unexplained_difference + once per episode (built, then dropped): after that gate it only fires on integrity findings the engine itself calls 'never a user task'. skattekonto_drift_tolerance stays (Hem notice reads it); stale skattekonto_drift_last_alert_at rows in extension_data are inert. [2026-09-02] parties phase 0, golden set stays out of git: the labelling sample is prod voucher text with person names (salary, expense claims) and the repo is public, so the draw SQL is versioned but the rows and labels live in gitignored dev_docs/parties/golden/. [2026-09-02] MCP eager-auth flag (`auth=required`) on the claude.ai connector links instead of reverting lazy auth: claude.ai's two-step Add-custom-connector dialog probes the URL without credentials and pre-fills Authentication "None" when the lazy handshake answers 200, which blocks the sign-in later; per Anthropic's docs a 401 is the only answer it reads as OAuth. The flag lives in the URL, so the links we control (Settings, onboarding checklist, both docs pages, website) get OAuth detected while the bare URL keeps lazy auth for Claude Code, the plugin, Cursor and ChatGPT, and existing connector records stay untouched. Rejected: keying eager auth off `client=claude-connector` (documented as telemetry-only) and sniffing the probe's user agent (fragile, undocumented). +[2026-09-02] Grok links carry auth=required like the claude.ai link (#2159), decided from a live test: on the lazy URL Grok's connector dialog listed all 150+ tools and never opened the sign-in, so it reads the 200 probe as an authless server exactly as claude.ai does. The flag lives in one helper (mcpServerUrl / sideDoorServerUrl in lib/onboarding/checklist.ts) so the settings row, the onboarding side door and the deep link cannot drift; ChatGPT stays lazy because its developer mode honours the 401 on the first protected call. diff --git a/components/onboarding/NewUserChecklist.tsx b/components/onboarding/NewUserChecklist.tsx index 680972a9..492fa818 100644 --- a/components/onboarding/NewUserChecklist.tsx +++ b/components/onboarding/NewUserChecklist.tsx @@ -17,6 +17,9 @@ import { checklistNumbers, claudeConnectorLink, completionPatchBody, + SIDE_DOORS, + sideDoorServerUrl, + type SideDoor, type VatDeadlineLine, } from '@/lib/onboarding/checklist' import { ENABLED_EXTENSION_IDS } from '@/lib/extensions/_generated/enabled-extensions' @@ -47,12 +50,6 @@ interface NewUserChecklistProps { sieSweep?: { auto_linked: number; suggested: number; unmatched: number; errors: number } | null } -/** Clients that get a collapsed "Using X?" side door under the Claude step. - * Each value keys the i18n strings step_claude__link / _steps and the - * telemetry step name. Order is display order. */ -const SIDE_DOORS = ['chatgpt', 'grok'] as const -type SideDoor = (typeof SIDE_DOORS)[number] - /** * Activation funnel events, mirroring the one existing product-event site * (lib/support/submit-feedback.ts): guarded, try/caught, no PII in @@ -276,8 +273,8 @@ export default function NewUserChecklist({ return open === door ? null : door }) } - const copyServerUrl = async () => { - const serverUrl = `${window.location.origin}/api/extensions/ext/mcp-server/mcp?tool_namespace=accounted` + const copyServerUrl = async (door: SideDoor) => { + const serverUrl = sideDoorServerUrl({ origin: window.location.origin, door }) try { await navigator.clipboard.writeText(serverUrl) setServerUrlCopied(true) @@ -495,7 +492,7 @@ export default function NewUserChecklist({

{t(`step_claude_${sideDoor}_steps`, { appName })}

-