Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
Lägger docs/production-readiness.md och siax/production-gaps.json enligt SIAX Master Definition of Done. Underlag: git-, kod- och live-evidens 2026-11-11. Nivån är evidensbaserad, inte ett leveransgodkännande.
* fix(agent): hide Anthropic-only assistant surfaces where the provider cannot run them
Self-hosted deployments on an OpenAI-compatible provider (or with no AI
configured) still showed every entry point into the tool-loop runtime
behind /api/agent/invoke, which answers 503 there. The capability lived
server-side only (getAiStatus().assistantAvailable); no UI could read it.
Hand the flag to the client through CompanyContext (useAssistantAvailable,
beside the paid-capability gate) and gate each entry point that opens
AgentChat: the bookkeeping page's "Skapa med assistent" and "Med
assistenten", the inbox workspace's "Fråga assistenten" doors, /chat/intake
and /chat/new?intent=. The floating trigger falls back to general help (the
single-call console runs on any provider) instead of hiding, and AgentChat
itself never fires an invoke without the runtime, so a resumed thread or a
forgotten entry point shows a notice instead of a 503. The Hem checklist's
"Anslut till Claude" step renders only where the assistant runs on Claude
and the mcp-server extension is on. Provider-agnostic AI (ask console,
categorization, extraction) and the server-side 503 are unchanged; on
hosted the flag is true and nothing changes.
Closes#2204
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SaJfqNi4VmsG8FMKq99G6
* test(ai): use a placeholder that cannot match an Anthropic key shape
The new direct-Anthropic status test assigned a string in the exact
format of a live API key, which trips secret scanners on every run. The
config only reads presence, so any non-empty string exercises the path.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* fix(mcp): eager-auth flag on the Grok connector links so Grok starts OAuth
Live test after #2158: pasting the Grok URL into grok.com's custom
connector dialog listed all 150+ tools and never opened the sign-in. Grok
probes the URL without credentials, like claude.ai, and reads the lazy
200 on initialize as an authless server; only the 401 challenge starts
OAuth (#2159 fixed the same thing for the claude.ai link).
- lib/onboarding/checklist.ts: mcpServerUrl() builds the server URL with
an optional eagerAuth flag; sideDoorServerUrl() gives the Grok side door
auth=required and keeps ChatGPT lazy; claudeConnectorLink() reuses it.
SIDE_DOORS / SideDoor move here from the component. Tests for all three.
- NewUserChecklist copies the door-specific URL (now with a client marker).
- ApiKeysPanel's Grok row copies the flagged URL, mirroring the Claude one.
- auth-mode.ts comment records the second consumer; registry entry's Grok
step carries the flag; DECISIONS.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhTJcwgzmN3TsLR8tVHwdi
Signed-off-by: Emil <emilmattsson14@gmail.com>
* docs(mcp): registry Claude.ai step carries auth=required too
Review pass on #2167: the registry entry flagged the Grok install URL
but left the Claude.ai step on the bare URL, which pre-fills "None" in
claude.ai's dialog (#2159). Same file, same flag, now consistent.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhTJcwgzmN3TsLR8tVHwdi
Signed-off-by: Emil <emilmattsson14@gmail.com>
---------
Signed-off-by: Emil <emilmattsson14@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
claude.ai's two-step "Add custom connector" dialog probes the server URL
without credentials and pre-fills the Authentication choice from the
answer. Our lazy-auth endpoint (issue #1814) answers 200 on an anonymous
initialize, which the dialog reads as an authless server: it suggests
"None", and a connector added with that default never opens the sign-in
when the challenge arrives later. Per Anthropic's connector docs a 401 is
the only answer it reads as OAuth ("Claude does not honor a
WWW-Authenticate header on a 200 response").
- `auth=required` on the endpoint URL (extensions/general/mcp-server/
auth-mode.ts) turns lazy auth off for that URL: every tokenless
request, initialize included, answers the 401 + WWW-Authenticate
challenge. Callers with a token are unaffected; the bare URL keeps
lazy auth for Claude Code, the plugin, Cursor and ChatGPT, and existing
connector records are untouched.
- The links we control carry the flag: Settings -> API & MCP (install
link and copy block), the onboarding checklist, both docs pages and
claude-plugin/CONNECTORS.md (plugin 1.2.3). The docs' Path A now
describes the eager flow (sign-in opens on Add) instead of telling
users to override the dialog's "None".
- Tests: eager-auth.test.ts (401 on initialize/tools/list/public tools,
namespaced metadata pointer, token no-op, exact-flag only); checklist
link shape updated.
Companion: gnubok-website PR (Kom igång connector link + regenerated
connect-claude / anslut-claude pages).
Claude-Session: https://claude.ai/code/session_013yw62FMXGSzo6icFDiBwP3
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* fix(mcp): explain the Claude-side steps after "Anslut till Claude" and tick the checklist on a real connection (#2133)
Lazy auth is by design: Claude lists the tools before any sign-in and the
first company-scoped call answers 401, which opens the Accounted sign-in.
Nothing told the user, so a "connected" status with an unanswered first
question read as a broken connection (Axel, Discord).
- Settings -> API & MCP: one sentence of expectation under the button, and
the step-by-step guide link moved from under two disclosures to directly
under the button.
- Docs (connect-claude / anslut-claude): new "What happens after you click"
section for Path A covering the connector dialog, the tools appearing
before sign-in, the first-call login + consent screen, "ask again", and
the "Required when the server asks" auth setting that only the manual
path mentioned.
- Hem checklist step "Anslut till Claude": deep link now carries
client=claude-connector like the settings button (claudeConnectorLink),
the footnote carries the same expectation line plus the guide link, and
the done-signal is an unrevoked api_keys row minted by the MCP OAuth
token route (OAUTH_MCP_KEY_NAME) instead of the in-app AI-profile flag,
which never meant "connected to Claude".
- Tests: claudeStepDone with/without a key row, deep-link snapshot.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W7iJQwKiRTDWSMnRm4WM4L
* fix(mcp): correct consent-page claims, stop the completion PATCH loop, count OAuth keys past RLS (#2133)
Three skeptic refutations on PR #2147, fixed in one pass:
- Docs (EN + SV): the consent page shows the company active in the app and
pre-selects every scope for Claude's connector (founder decision
2026-08-26); it has no company picker and nothing to tick. Steps 3-4 of
the new section, the "Read-only by default" paragraph above it, the
sandbox note and the 10-minute test now describe Endast läs under
Behörigheter instead.
- Checklist completion: users with initial_setup_path NULL (skipped the
books question, then imported) hit the route's "Välj först hur du vill
komma igång" 400 and, with saving as an effect dependency, retried it
forever with a toast. completionPatchBody() records path=migration when
none was chosen, and a rejected PATCH is not retried within the session.
- hasMcpKey: api_keys' SELECT policy is company-scoped, so the user client
could not see companyless (NULL company_id) or archived-company keys and
the step stayed open for the user who had just connected. The head count
now runs through the service client with an explicit user_id filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W7iJQwKiRTDWSMnRm4WM4L
* fix(mcp): surface a failed OAuth-key count and reserve the marker name (#2133)
CodeRabbit round on PR #2147:
- app/(dashboard)/page.tsx: a failed api_keys count answered count null,
which claudeStepDone read as "never connected". Throw to the error
boundary like the settings fetch does instead of guessing.
- app/api/settings/api-keys: reject a hand-minted key named
MCP-klient (OAuth) (400 VALIDATION_ERROR): that name is the marker the
Hem checklist reads as "connected to Claude", so a manual key with it
would tick the step without any connection. Test added.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W7iJQwKiRTDWSMnRm4WM4L
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* feat(onboarding): activation quick wins on the Hem checklist
First implementation slice of the approved activation concept
(artifact de543d57, dev_docs/onboarding_activation_analysis.md §9):
- New "Kvitton och underlag" checklist step, gated on the invoice-inbox
extension like the Skatteverket step; done once the company has ever
received an inbox item (email/WhatsApp/upload). Non-AI companies route
to billing, matching the assistant step.
- Personalized VAT line in the Skatteverket step: the company's real next
momsdeklaration due date from the deadlines table, with an explicit
"välj momsperiod" prompt when vat_registered is set but moms_period is
null (that state silently generates zero VAT deadlines).
- Truthful Att göra empty state: while the setup checklist is open and no
journal entry is posted, the all-clear reads "Bokföringen är tom än"
instead of a false "Allt klart!".
- Activation funnel events (onboarding_setup_step_started / _completed /
_dismissed) via posthog-js, mirroring the existing guarded capture
pattern; sandbox never renders the block so no extra gate is needed.
Pure helpers live in lib/onboarding/checklist.ts with tests; step
numbering now adapts to both optional extensions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: record the receipts-signal and moms-period-guard decisions
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(onboarding): review triage: error-safe emptyLedger, stale-state guard, copy
- A failed posted-entries count no longer reads as an empty ledger.
- Confirming a suggested match books an entry, so the empty-ledger copy
retires for the rest of the session (postedSinceLoad).
- 'Bokföringen är tom än så länge' reads naturally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>