Project: pro-desktop · Branch: master · Mode: · Model: claude-opus-4-7 Stats: 1 user messages, 18 tool calls, tools used: Bash, Read. Conversation Turn 1 — User Review the following PR diff for code quality, architectural patterns, and DDV best practices. The PR is a refactor that removes a dead feature flag useConnectorContextFromElectronSettings from the kbv-ti-connect module of a DDV (Doctolib Pro Desktop) Electron + TypeScript app. PR title: refactor(FHIR-2177): remove dead useConnectorContextFromElectronSettings flag Branch: fhir-2177 → master Author: nivethayadhavan PR Description: Removes the dead useConnectorContextFromElectronSettings flag from TiConnectSettings and all related code. The flag defaulted to false and nothing in DDV or the monolith ever set it to true after the TiConnectChangeMode IPC event was removed in FHIR-2040. Changes include: - Removed flag from type, default, and mock store - Simplified ConfigurationService.obtainConfiguration() to use a guard clause - Made contextFromRequest an explicit required-or-undefined parameter - Fixed gematik-idp-authentication and gematik-e-rezept which were silently broken (calling without context) Full diff: diff --git a/src/modules/de/gematik-e-rezept/services/__tests__/index.test.ts b/src/modules/de/gematik-e-rezept/services/__tests__/index.test.ts index 3d5646cc1b..6b2a59d960 100644 --- a/src/modules/de/gematik-e-rezept/services/__tests__/index.test.ts +++ b/src/modules/de/gematik-e-rezept/services/__tests__/index.test.ts @@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, MockInstance, vi } from 'vitest' import ConfigurationService from '@module/de/kbv-ti-connect/services/configuration-service' import { mockConfigurationService } from '@module/de/kbv-ti-connect/services/configuration-service/configurationService.mock' +import { TiConnectRepository } from '@module/de/kbv-ti-connect/services/ti-connect-repository' import { SpecialistServiceApiResponse } from '../../constants/types' import { ApiResponseMapper } from '../apiResponseMapper' @@ -32,6 +33,7 @@ describe('GematikERezeptEventHandler', () => { beforeEach(() => { vi.restoreAllMocks() + vi.spyOn(TiConnectRepository, 'settings', 'get').mockReturnValue(undefined) apiResponseMapperSpy = vi.spyOn(ApiResponseMapper, 'fromParsedHttpResponse') eRezeptRequestSpy = vi.spyOn(eRezeptModule, 'eRezeptRequest') vi.spyOn(ConfigurationService, 'obtainConfiguration').mockImplementation(() => mockConfigurationService) diff --git a/src/modules/de/gematik-e-rezept/services/index.ts b/src/modules/de/gematik-e-rezept/services/index.ts index ea3cffc10a..597f433a05 100644 --- a/src/modules/de/gematik-e-rezept/services/index.ts +++ b/src/modules/de/gematik-e-rezept/services/index.ts @@ -1,6 +1,7 @@ import { v4 } from 'uuid' import ConfigurationService from '@module/de/kbv-ti-connect/services/configuration-service' +import { TiConnectRepository } from '@module/de/kbv-ti-connect/services/ti-connect-repository' import { ApiResponseMapper } from './apiResponseMapper' import { eRezeptRequest } from './eRezeptRequest' @@ -24,7 +25,13 @@ export class GematikERezeptEventHandler { } const traceId = v4() - const configurationService = ConfigurationService.obtainConfiguration(traceId) + const { settings } = TiConnectRepository + const configurationService = ConfigurationService.obtainConfiguration(traceId, { + mandantId: settings?.mandantId ?? '', + clientSystemId: settings?.clientSystemId ?? '', + workplaceId: settings?.workplaceId ?? '', + userId: settings?.userId ?? '', + }) switch (action) { case 'createERezept': { diff --git a/src/modules/de/gematik-idp-authentication/services/index.ts b/src/modules/de/gematik-idp-authentication/services/index.ts index be601f4ce7..225d73fa29 100644 --- a/src/modules/de/gematik-idp-authentication/services/index.ts +++ b/src/modules/de/gematik-idp-authentication/services/index.ts @@ -3,6 +3,7 @@ import { v4 } from 'uuid' import { IdpAuthenticator } from '@module/de/gematik-idp-auth …(truncated, 3942 more chars) Turn 1 — Assistant I'll review this PR carefully, starting by examining the actual files to verify the diff context and understand the broader module patterns. Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services -type f -name ".ts" | head -50 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/keyStore.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/soap-client-helpers.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/track-certificate-type.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/connection-checker.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/s …(truncated, 5424 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services -type f -name ".ts" 2>/dev/null | head -30 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/eRezeptRequest.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/index.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/apiResponseMapper.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/__tests__/index.test.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/ …(truncated, 198 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services -type f -name ".ts" 2>/dev/null | head -30 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/IdpAuthChallengeCache.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/repository.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/ChallengeValidator.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/idpAccessToken.ts /Users/US …(truncated, 3451 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/configuration-service/index.ts Tool results: → result (ok): 1 import i18n from 'i18next' 2 3 import { 4 ConnectorConfiguration, 5 ConnectorContext, 6 ConnectorContextInput, 7 CryptType, 8 } from '@module/de/kbv-ti-connect/services/types' 9 import { extraLogParser, getNestedKeys } from 'src/utils/extraLogParser.ts' 10 11 import { kbvTiConnectLogger } from '../logger' 12 import { TiConnectRepository } from '../ti-connect-repository' 13 14 export default class ConfigurationService { 15 static readonly configurationService = { name: 'Configurati …(truncated, 4880 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/types.ts Tool results: → result (ok): 1 export type TiConnectAction = 2 | 'startConnection' 3 | 'testConnectorConfiguration' 4 | 'subscribeToEventService' 5 | 'unsubscribeFromEventService' 6 | 'readVsd' 7 | 'readKvk' 8 | 'getSmcbPinStatus' 9 | 'changePin' 10 | 'handleSmcb' 11 | 'unblockPin' 12 | 'enableOfflineMode' 13 | 'enableOnlineMode' 14 | 'verifyCertificate' 15 | 'readCardCertificate' 16 | 'externalAuthenticate' 17 | 'idpAuthenticate' 18 | 'persistConfigurationAndRestartEventServer' 19 | 'che …(truncated, 6982 more chars) Now I have full context on the files being modified and the project rules. Let me check a few more relevant items. Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/index.ts Tool results: → result (ok): 1 import { v4 } from 'uuid' 2 3 import ConfigurationService from '@module/de/kbv-ti-connect/services/configuration-service' 4 5 import { ApiResponseMapper } from './apiResponseMapper' 6 import { eRezeptRequest } from './eRezeptRequest' 7 8 import { 9 EREZEPT_ABORT_URL, 10 EREZEPT_ACTIVATE_URL, 11 EREZEPT_CREATE_URL, 12 EREZEPT_TASK_RESOURCE_URL, 13 } from '../constants/constants' 14 import { GematikERezeptRequest, GematikERezeptResponse } from '../constants/types' 15 16 export class …(truncated, 2912 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/index.ts Tool results: → result (ok): 1 import { v4 } from 'uuid' 2 3 import { IdpAuthenticator } from '@module/de/gematik-idp-authentication/services/idpAuthenticator' 4 import tiConnect from '@module/de/kbv-ti-connect/services' 5 import ConfigurationService from '@module/de/kbv-ti-connect/services/configuration-service' 6 7 import { TiIdpAuthenticatePayload, TiIdpAuthenticateResponse } from '../constants/types' 8 9 // Handles TI IDP Authentication IPC events 10 export class TiIdpAuthenticateEventHandler { 11 authenticate = as …(truncated, 963 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/ti-connect-repository.ts Tool results: → result (ok): 1 import { EMPTY_TI_SETTINGS } from './ti-connect-settings' 2 import { getTiConnectStore, TI_SCHEMA_KEY_INFO, TI_SCHEMA_KEY_SETTINGS } from './ti-connect-store' 3 import { TiConnectionInfo, TiConnectSettings } from './types' 4 5 / 6 TiConnectRepository is a wrapper around the store to retrieve and persist Ti Connect data 7 / 8 export class TiConnectRepository { 9 / Retrieve Ti Connect Settings from the store / 10 static get settings(): TiConnectSettings | undefined { 11 return …(truncated, 1184 more chars) Tools used: - Bash: grep -rn "useConnectorContextFromElectronSettings" /Users/USER/workspace/doctolib/doctolib-pro-desktop/src 2>/dev/null Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-kim/services/__tests__/account.test.ts:29: useConnectorContextFromElectronSettings: false, /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/main/__tests__/ti-connect.test.ts:105: useConnectorContextFromElectronSettings: true, /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/types.ts:160: useConnectorContextFromElectronSettings: boolean /Users/ …(truncated, 1056 more chars) Tools used: - Bash: grep -rn "obtainConfiguration" /Users/USER/workspace/doctolib/doctolib-pro-desktop/src 2>/dev/null Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-specialist-service/main/listeners.ts:66: const configurationService = ConfigurationService.obtainConfiguration(traceId, payload?.context) /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-specialist-service/main/__tests__/listeners.test.ts:46: let obtainConfigurationSpy: MockInstance /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-specialist-service/main/__tests__/list …(truncated, 9016 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/ti-connect-settings.ts Tool results: → result (ok): 1 import { TiConnectSettings } from './types' 2 3 export const EMPTY_TI_SETTINGS: TiConnectSettings = { 4 connectorHost: '', 5 connectorPort: '', 6 eventServiceHost: '', 7 eventServicePort: '', 8 keyStorePath: '', 9 cert: '', 10 privateKey: '', 11 clientSystemId: '', 12 mandantId: '', 13 workplaceId: '', 14 userId: '', 15 useConnectorContextFromElectronSettings: false, 16 serverCertificateFingerprint: '', 17 serverCertificate: '', 18 isCertificatesVerificationEnabl …(truncated, 713 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/configuration-service/__tests__/index.test.ts (1–230) Tool results: → result (ok): 1 import i18n from 'i18next' 2 import { MockInstance } from 'vitest' 3 4 import { TiConnectSettings } from '@module/de/kbv-ti-connect/services/types' 5 6 import ConfigurationService from '../../configuration-service' 7 import { kbvTiConnectLogger } from '../../logger' 8 import { testStore } from '../../mock/mockStore' 9 import { TiConnectRepository } from '../../ti-connect-repository' 10 11 vi.mock('../../logger', () => ({ 12 kbvTiConnectLogger: { 13 debug: vi.fn(), 14 error: vi.fn( …(truncated, 8926 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/mock/mockStore.ts Tool results: → result (ok): 1 import { TiConnectionInfo, TiConnectionInfoStatus, TiConnectSettings } from '../types' 2 3 export interface MockStore { 4 ti_connect: TiConnectSettings 5 ti_connection_info: TiConnectionInfo 6 } 7 8 export const testStore: MockStore = { 9 ti_connect: { 10 connectorHost: 'localhost', 11 connectorPort: '445', 12 eventServiceHost: 'localhost', 13 eventServicePort: '3010', 14 keyStorePath: 'path', 15 cert: 'cert123', 16 privateKey: 'key123', 17 clientSystemI …(truncated, 2965 more chars) Now I have full context. Let me also check the gematik-specialist-service pattern (which already correctly uses payload.context) and the kbv-ti-connect/services/index.ts (which uses payload?.context) to compare against the new gematik-e-rezept and gematik-idp-authentication approach. Tools used: - Bash: grep -n "context" /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/constants/types.ts 2>/dev/null | head -20 Tool results: → result (ok): (Bash completed with no output) Tools used: - Bash: grep -n "context\|cardHandle" /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/constants/types.ts 2>/dev/null | head -20 Tool results: → result (ok): 122: cardHandle?: string Tools used: - Bash: grep -rn "TiConnectRepository" /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules 2>/dev/null | grep -v "kbv-ti-connect" Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-kim/services/__tests__/account.test.ts:67: getSettings = vi.spyOn(TiConnectRepository, 'settings', 'get') /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-kim/services/client/account.ts:160: const tiConfig = TiConnectRepository.settings /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-crypto/main/module.ts:93: const { settings } = TiConnectRepository /Users/USER/w …(truncated, 4097 more chars) Useful — TiConnectRepository is already widely used cross-module (gematik-kim, gematik-crypto, gematik-ti-card-management), so the new gematik-e-rezept and gematik-idp-authentication imports follow established precedent. The pattern in gematik-specialist-service and gematik-ti-card-management and the kbv-ti-connect's own services shows that callers usually pass payload?.context rather than fishing settings out of the repository — so the gematik-e-rezept / gematik-idp-authentication approach is a deviation. Let me confirm whether the e-rezept and idp-authentication payloads actually carry context or not. Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/constants/types.ts Tool results: → result (ok): 1 export interface GematikERezeptCreateEventPayload { 2 payload: string 3 cardHandle: string 4 } 5 6 export interface GematikERezeptActivateEventPayload extends GematikERezeptCreateEventPayload { 7 taskId: string 8 accessCode: string 9 } 10 11 export interface GematikERezeptAbortEventPayload { 12 cardHandle: string 13 taskId: string 14 accessCode: string 15 } 16 17 export type GematikERezeptRequest = 18 | { action: 'createERezept'; payload: GematikERezeptCreateEventPayload } 1 …(truncated, 828 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/constants/types.ts Tool results: → result (ok): 1 import type { EccCertificate, EccJwk } from '@module/de/gematik-crypto' 2 3 interface JwtBody { 4 iat: number 5 exp: number 6 iss?: string 7 jti?: string 8 } 9 10 export interface DiscoveryDocumentHeader { 11 alg: string 12 kid: string 13 typ: string 14 x5c: string[] 15 } 16 17 export interface DiscoveryDocumentBody extends JwtBody { 18 issuer: string 19 jwks_uri: string 20 uri_disc: string 21 authorization_endpoint: string 22 sso_endpoint: string 23 token_endpoi …(truncated, 2871 more chars) Confirmed: neither TiIdpAuthenticatePayload nor any GematikERezept*EventPayload carry a context field. So the gematik-e-rezept and gematik-idp-authentication callers do not have a request context to pass — using TiConnectRepository.settings is the only workable option. That said, the empty-string fallbacks ?? '' are concerning: the connector requires a non-empty MandantId/ClientSystemId/WorkplaceId; passing empty strings silently to the connector would produce SOAP failures rather than a clear "settings missing" error. I now have enough context to deliver the review. --- PR Review: refactor(FHIR-2177): remove dead useConnectorContextFromElectronSettings flag What I reviewed - src/modules/de/kbv-ti-connect/services/configuration-service/index.ts (signature change + branch removal) - src/modules/de/kbv-ti-connect/services/types.ts (flag removed from TiConnectSettings and UserEditableTiConnectSetting) - src/modules/de/kbv-ti-connect/services/ti-connect-settings.ts (default removed in EMPTY_TI_SETTINGS) - src/modules/de/kbv-ti-connect/services/mock/mockStore.ts (test fixture) - src/modules/de/gematik-e-rezept/services/index.ts + tests - src/modules/de/gematik-idp-authentication/services/index.ts - All obtainConfiguration call sites (gematik-specialist-service, gematik-qes, gematik-ti-card-management, kbv-ti-connect/services/index.ts) — to verify the contract change is consistent Critical (90-100) issue: Empty-string fallbacks silently mask a missing-settings error and will surface as opaque SOAP failures (confidence 92) Files: - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/index.ts lines 28-34 - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/index.ts lines 23-29 const { settings } = TiConnectRepository const configurationService = ConfigurationService.obtainConfiguration(traceId, { mandantId: settings?.mandantId ?? '', clientSystemId: settings?.clientSystemId ?? '', workplaceId: settings?.workplaceId ?? '', userId: settings?.userId ?? '', }) The PR description claims gematik-e-rezept and gematik-idp-authentication were "silently broken" — but this fix replaces one silent failure mode with another. When TiConnectRepository.settings is undefined (or fields are blank), ConfigurationService.obtainConfiguration() will not trigger its missing-context branch because contextFromRequest is now a fully-populated object of empty strings. It will: 1. Throw a different error inside obtainConfiguration (line 70-72 — "missing settings", which fires from if (!settings) in the configuration service itself), if settings is undefined. 2. Worse: if settings exists but the user fields are empty (e.g., mandantId: ''), the call will succeed and propagate empty MandantId/ClientSystemId/WorkplaceId into a real SOAP request, causing a remote 4xx with an opaque connector error far from the root cause. Note also that because the configuration service's missing-settings check runs before context normalization, supplying empty-string values when settings is undefined is wasted work and causes redundant default values to leak in if the upstream order ever changes. Recommended fix — guard at the caller and produce a clear, actionable error before invoking obtainConfiguration: const { settings } = TiConnectRepository if (!settings || !isTiContextLocal(settings)) { return { response: { success: false, errors: ['TI connect settings are missing or incomplete'] } } } const configurationService = ConfigurationService.obtainConfiguration(traceId, { mandantId: settings.mandantId, clientSystemId: settings.clientSystemId, workplaceId: settings.workplaceId, userId: settings.userId, }) isTiContextLocal already exists in ti-connect-settings.ts (line 37) and was apparently introduced for exactly this purpose. Reuse it. --- issue: Stale tests still reference useConnectorContextFromElectronSettings and will fail typecheck after types.ts change (confidence 95) The PR removes the field from TiConnectSettings, but four test/fixture sites still set it: - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/configuration-service/__tests__/index.test.ts:57 → useConnectorContextFromElectronSettings: true - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/configuration-service/__tests__/index.test.ts:90 → useConnectorContextFromElectronSettings: false - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/services/mock/mockStore.ts:21 → useConnectorContextFromElectronSettings: true - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-kim/services/__tests__/account.test.ts:29 → useConnectorContextFromElectronSettings: false - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/kbv-ti-connect/main/__tests__/ti-connect.test.ts:105 → useConnectorContextFromElectronSettings: true The PR diff in the prompt does not show these being touched. The configuration-service test file in particular keeps two whole describe blocks — "when context usage from ddv settings is enabled" and "when context usage from ddv settings is disabled" — that test logic the PR is removing. Either: 1. The diff in the prompt is incomplete (these files were updated elsewhere in the PR, not shown), in which case verify by running npm run lint and npm run test:unit -- configuration-service. The CLAUDE.md verification gate explicitly mandates this. 2. They were missed, in which case TS will fail with Object literal may only specify known properties and the whole CI will go red. The mockStore.ts fixture at line 21 must definitely be updated since it's typed as TiConnectSettings. Same for the EMPTY_TI_SETTINGS constant in ti-connect-settings.ts:15. Action: verify the full PR contents and update these files. Drop the two describe blocks in the config-service test that exercise the removed flag, and replace them with a single block that asserts behavior is now unconditional. --- Important (80-89) issue: gematik-idp-authentication and gematik-e-rezept silently fall back to empty-string identifiers — error path goes through generic try/catch with no traceability (confidence 85) File: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/index.ts lines 94-103, and /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/index.ts lines 30-36. When settings are missing, the configuration service now logs via kbvTiConnectLogger.error (which is fine) and throws — but the catch block in these handlers reduces it to (error as Error).message and returns success: false. This loses: - The structured traceId association in the log (it does flow through, OK) - Any indication to the caller that the failure is "TI not configured" vs "TI connector unreachable" Per .claude/rules/architecture/modules.md and the DDV logger skill, structured errors with module-specific codes are preferred. Add an explicit guard before calling obtainConfiguration that returns a typed error code, instead of relying on the generic errors: [errorMessage] shape. This pairs with the previous critical comment. --- suggestion: Module boundary — gematik-e-rezept and gematik-idp-authentication now reach into kbv-ti-connect internals; this is consistent with existing precedent but the PR adds two new such couplings (confidence 80) Files: - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-e-rezept/services/index.ts:6 - /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/de/gematik-idp-authentication/services/index.ts:6 Both modules now import `TiConnectRe …(truncated, 7484 more chars)