Project: treatment-plan · Branch: main · Mode: · Model: claude-opus-4-7 Stats: 1 user messages, 38 tool calls, tools used: Bash, Read. Conversation Turn 1 — User Review the changes in PR https://github.com/doctolib/doctolib/pull/240556 (branch fhir-2216_fix-nhr-date-columns-and-document-type). This PR fixes three bugs in the NHR Document List: 1. Procedure date and Share date always showed – because DMP API returns HL7 DTM dates (YYYYMMDD/YYYYMMDDHHMMSS) and the adapter was storing them verbatim — JS Date can't parse these. 2. Document type showed raw numeric code ("10", "52") because dmp:typeCode (LOINC code) was dropped and only dmp:classCode (numeric JDV_J06) was stored. 3. Mock data batches 9-13 had invalid status strings and non-DMP codes. Files changed (all in packages/@doctolib/national-health-records/src/): - business/adapters/DmpNhrAdapter.ts — added parseHl7DateToIso, dual-code classification - variants/dmp/mappers/dmpDocumentHelpers.ts — split DMP_SYSTEM constant, updated getTypeCode, fixed date helpers - mocks/nhrMockedDocuments.ts — replaced invalid mock data - business/adapters/DmpNhrAdapter.test.ts — updated + extended - variants/dmp/mappers/dmpDocumentHelpers.test.ts — fully expanded Please focus on: correctness of the HL7→ISO parsing (edge cases), the isPatientAuthored invariant preservation, TypeScript type safety, test coverage quality, and any issues with the mock data changes. Report actionable items only. Turn 1 — Assistant I'll review this PR by examining the changes in the worktree. Tools used: - Bash: ls /Users/USER/workspace/doctolib/worktrees/treatment-plan/ 2>/dev/null Tool results: → result (ok): fhir-2079 fhir-2081 fhir-2083 FHIR-2091-nhr-document-list-pagination fhir-2168_add-result-count-to-nhr-header fhir-2171 The worktree for this branch doesn't exist locally. Let me check the main treatment-plan repo for this PR's changes. Tools used: - Bash: git branch -a | grep -i "2216\|nhr-date" | head -20 Tools used: - Bash: ls /Users/USER/workspace/doctolib/treatment-plan/packages/@doctolib/national-health-records/src/ 2>/dev/null Tool results: → result (ok): (Bash completed with no output) Tool results: → result (ERROR): Exit code 2 Tools used: - Bash: find /Users/USER/workspace/doctolib -path 'national-health-records' -type d -not -path '/node_modules/' 2>/dev/null | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records /Users/USER/workspace/doctolib/doctolib/.yalc/@doctolib/tpf-national-health-records-ui /Users/USER/workspace/doctolib/doctolib/.yalc/@doctolib/tpf-national-health-records /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-re …(truncated, 1311 more chars) The PR is in the doctolib monorepo, not treatment-plan. Let me examine the PR files there. Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git branch -a | grep -i "2216\|nhr-date" | head -10 Tools used: - Bash: ls /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/ 2>/dev/null Tool results: → result (ok): + fhir-2216_fix-nhr-date-columns-and-document-type remotes/origin/TT-22161-give-ownership-of-db-tables-cie-to-domak remotes/origin/TT-22167 remotes/origin/fhir-2216_fix-nhr-date-columns-and-document-type remotes/origin/fix-fox-2216-graceful-cvc-degradation remotes/origin/revert-182216-NTC-2600-autopilot Tool results: → result (ok): business hooks index.ts locales mocks variants Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git log --oneline fhir-2216_fix-nhr-date-columns-and-document-type -10 Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git merge-base origin/master fhir-2216_fix-nhr-date-columns-and-document-type Tool results: → result (ok): 7202a79098b2 feat(FHIR-2216): fix NHR date columns and document type rendering with real DMP data e9e5b85518d1 refactor(PASTA-4418): Move Profile events into ProfileManagement engine (#240444) 0757fd288b2a refactor(PASTA-2575): deprecate speciality/agendas associations in Calendar and Speciality [3/n] (#240379) 361db04def8a feat(CAI-2444): remove feature switch improved_preference_handling (#240324) d716bf6fc76b feat(BOSS-4230): add profession search debug page (#240217) f63dd30ecdd4 fix(PAX-426 …(truncated, 330 more chars) Tool results: → result (ok): e9e5b85518d15b64f50487f258bdc7c0645ca415 Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff --stat e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type Tool results: → result (ok): .../src/business/adapters/DmpNhrAdapter.test.ts | 51 ++++- .../src/business/adapters/DmpNhrAdapter.ts | 37 +++- .../src/mocks/nhrMockedDocuments.ts | 205 ++++++++++++--------- .../dmp/mappers/dmpDocumentHelpers.test.ts | 116 +++++++++++- .../src/variants/dmp/mappers/dmpDocumentHelpers.ts | 17 +- 5 files changed, 310 insertions(+), 116 deletions(-) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type -- packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAda …(truncated, 7 more chars) Tool results: → result (ok): diff --git a/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts b/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts index caf8a204d53d..ad72b89d2fd3 100644 --- a/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts +++ b/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts @@ -85,25 +85,48 @@ function toAuthor(author: DmpAuthor): NhrDocumentAuthor { } } +// DMP API retur …(truncated, 1813 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type -- packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDoc …(truncated, 15 more chars) Tool results: → result (ok): diff --git a/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts b/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts index 8113341906bc..b762eceeac75 100644 --- a/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts +++ b/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts @@ -2,24 +2,29 @@ import type { NhrDocument } from '@doctolib/tpf-nationa …(truncated, 2182 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type -- packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAda …(truncated, 12 more chars) Tool results: → result (ok): diff --git a/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts b/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts index c053604527bf..e90706214ee0 100644 --- a/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts +++ b/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts @@ -49,6 +49,7 @@ const dmpSearchResult: DmpSearchResult = { classCode: '11488 …(truncated, 3307 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type -- packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDoc …(truncated, 20 more chars) Tool results: → result (ok): diff --git a/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.test.ts b/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.test.ts index 56ba887f3b58..ce159fc56e12 100644 --- a/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.test.ts +++ b/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.test.ts @@ -1,44 +1,142 @@ import type { NhrDocument } from …(truncated, 5755 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git diff e9e5b85518d1..fhir-2216_fix-nhr-date-columns-and-document-type -- packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts Tool results: → result (ok): diff --git a/packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts b/packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts index 909afcaa3827..42f8763a3dc1 100644 --- a/packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts +++ b/packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts @@ -523,37 +523,37 @@ export const nhrMockedDocuments: NhrDocument[] = [ ], }, }, - // ── Batch 9: Pathology reports …(truncated, 17432 more chars) Now let me examine the surrounding types and callers to assess edge cases and invariants. Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git show fhir-2216_fix-nhr-date-columns-and-document-type:packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts Tool results: → result (ok): import type { DmpApi, DmpAuthor, DmpDocument, DmpDocumentContent, SearchProps, SearchResult as DmpSearchResult, } from '@doctolib/dmp' import { DOCUMENT_STATUS, DOCUMENT_VISIBILITY, getPatientInsForDMP } from '@doctolib/dmp' import { isUnstructured } from '@doctolib/cda/types/UnstructuredBody' import { isStructured } from '@doctolib/cda/types/StructuredBody' import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient' import type { NhrAdapter, NhrDocumentAuthor, …(truncated, 6632 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git show fhir-2216_fix-nhr-date-columns-and-document-type:packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts Tool results: → result (ok): import type { NhrDocument } from '@doctolib/tpf-national-health-records' import type { NhrVisibilityEntry } from '@doctolib/tpf-national-health-records-ui' import { DOCUMENT_STATUS, DOCUMENT_VISIBILITY } from '@doctolib/dmp' const CLASS_CODE_SYSTEM = 'dmp:classCode' const TYPE_CODE_SYSTEM = 'dmp:typeCode' const PATIENT_CODE = '90' // EX_3.1-1040: class code for patient-authored documents // Prefer the LOINC/JDV_J07 typeCode when present; fall back to the JDV_J06 classCode. // Both are stored i …(truncated, 2601 more chars) Now let me check the NhrDocument type contract and who consumes getProcedureDate/getShareDate (since their return type changed from string to string | undefined). Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "getProcedureDate\|getShareDate" --include=".ts" --include=".tsx" packages/@doctolib/ 2>/dev/null | head -30 Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "serviceInformation\|submissionDate\|creationDate" --include=".ts" --include=".tsx" packages/@doctolib/national-health-records packages/@d …(truncated, 90 more chars) Tool results: → result (ok): packages/@doctolib/national-health-records/src/variants/types.ts:19: submissionDateFrom?: string packages/@doctolib/national-health-records/src/variants/types.ts:20: submissionDateTo?: string packages/@doctolib/national-health-records/src/variants/dmp/mappers/mapFiltersToSearchDocumentsParams.ts:27:function mapDateFilters(filters: ServerFilters): Pick { packages/@doctolib/national-health-records/src/variants/dmp/mappers/mapFilters …(truncated, 2188 more chars) Tool results: → result (ok): packages/@doctolib/national-health-records/src/variants/dmp/factories/columnsFactory.test.ts:15: getProcedureDate: jest.fn(), packages/@doctolib/national-health-records/src/variants/dmp/factories/columnsFactory.test.ts:16: getShareDate: jest.fn(), packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts:19:export const getProcedureDate = (doc: NhrDocument): string => packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts:22:ex …(truncated, 577 more chars) Let me check columnsFactory.tsx to see how getDate is consumed — the return type change from string to string | undefined could break callers. Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git show fhir-2216_fix-nhr-date-columns-and-document-type:packages/@doctolib/national-health-records/src/variants/dmp/factories/columnsFactory.tsx 2> …(truncated, 20 more chars) Tool results: → result (ok): import type { ColumnConfig } from '@doctolib/tpf-national-health-records-ui' import { createNhrDocumentCategoryColumn, createNhrDocumentNameColumn, createNhrProcedureDateColumn, createNhrShareDateColumn, createNhrSharedByColumn, createNhrStatusColumn, createNhrVisibilityColumn, } from '@doctolib/tpf-national-health-records-ui' import { DOCUMENT_STATUS } from '@doctolib/dmp' import type { DesignSystemIconComponent } from '@doctolib/design-system-icons' import { FileLinesRegularIcon …(truncated, 2216 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "createNhrProcedureDateColumn\|createNhrShareDateColumn\|getDate" --include=".ts" --include=".tsx" packages/@doctolib/tpf-national-health- …(truncated, 63 more chars) Tool results: → result (ok): (Bash completed with no output) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -path 'tpf-national-health-records-ui' -name '.ts' -not -path '/node_modules/' -not -path '/dist/' -not -path '/.yalc/' 2>/dev/null | xargs g …(truncated, 95 more chars) Tool results: → result (ok): (Bash completed with no output) Tools used: - Bash: find /Users/USER/workspace/doctolib -path 'tpf-national-health-records-ui' -name '.ts' -o -name '.tsx' 2>/dev/null | grep -v node_modules | grep -v dist | grep -v storybook-static | xargs gre …(truncated, 67 more chars) Tool results: → result (ok): Command running in background with ID: bb92vta80. Output is being written to: /private/tmp/claude-501/-Users-clertonra-workspace-doctolib-treatment-plan/4a60c61a-52a8-4582-9de5-258d84f5e6ef/tasks/bb92vta80.output Tools used: - Bash: sleep 3 && cat /private/tmp/claude-501/-Users-clertonra-workspace-doctolib-treatment-plan/4a60c61a-52a8-4582-9de5-258d84f5e6ef/tasks/bb92vta80.output 2>/dev/null; echo "---done---" Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/index.ts /Users/USER/workspace/doctolib/doctolib/.yalc/@doctolib/tpf-national-health-records-ui/src/index.ts /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/organization_traceability_sdk/src/useFilterParams.test.tsx /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx /Users/USER/workspace/doctolib/doctoli …(truncated, 778 more chars) Tools used: - Bash: grep -rn "createNhrProcedureDateColumn\|createNhrShareDateColumn" /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/ 2>/dev/null | head -10 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/index.ts:31: createNhrProcedureDateColumn, /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/index.ts:33:} from './business/factories/columns/createNhrProcedureDateColumn' /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/index.ts:42: createNhrShareDateColumn, /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national …(truncated, 1452 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/columns/createNhrProcedureDateColumn.tsx Tool results: → result (ok): 1 import type { NhrDocument } from '@doctolib/tpf-national-health-records' 2 3 import { NhrProcedureDateCell } from '../../../components/NhrDocumentList/NhrProcedureDateCell' 4 import type { ColumnConfig } from '../../../types' 5 6 export type NhrProcedureDateColumnOptions = { 7 / Translated column header / 8 header: string 9 / 10 Extracts the ISO date string for the procedure date from the document. 11 Returns undefined when the procedure date is absent. 12 / 13 get …(truncated, 690 more chars) Good — the UI consumer createNhrProcedureDateColumn/createNhrShareDateColumn already accepts string | null | undefined, so the return type change from string to string | undefined is safe. Let me check a few more critical items: timezone behavior of the new ISO strings and whether NhrDocument.creationDate/submissionDate allow undefined. Tools used: - Bash: grep -rn "NhrProcedureDateCell\|NhrShareDateCell" /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/ 2>/dev/null | grep -v test | head -10 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/columns/createNhrProcedureDateColumn.tsx:3:import { NhrProcedureDateCell } from '../../../components/NhrDocumentList/NhrProcedureDateCell' /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/columns/createNhrProcedureDateColumn.tsx:18: Renders a locale-aware formatted date via NhrProcedureDateCell. EX_3.1-1070. /Users/USER/workspa …(truncated, 1816 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src -name "NhrProcedureDateCell" -o -name "NhrShareDateCell" | head -10 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrProcedureDateCell /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrShareDateCell /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrProcedureDateCell/NhrProcedureDateCell.test.tsx /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-n …(truncated, 751 more chars) Tools used: - Bash: grep -rn "formatNhrDate" /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/ 2>/dev/null | grep -v test | head -5 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/filters/createNhrDateSelectionFilterConfig.tsx:1:import { formatNhrDateTime } from '#utils/nhrDateHelpers' /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/filters/createNhrDateSelectionFilterConfig.tsx:43: lastAccessDate={formatNhrDateTime(lastAccessDate)} /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-nationa …(truncated, 546 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/utils/nhrDateHelpers.ts Tool results: → result (ok): 1 const FALLBACK = '–' 2 3 export const formatNhrDate = (isoDate: string | null | undefined): string => { 4 if (!isoDate) return FALLBACK 5 const date = new Date(isoDate) 6 return Number.isNaN(date.getTime()) ? FALLBACK : date.toLocaleDateString() 7 } 8 9 export const formatNhrDateTime = (isoDate: string | null | undefined): string => { 10 if (!isoDate) return FALLBACK 11 const date = new Date(isoDate) 12 return Number.isNaN(date.getTime()) 13 ? FALLBACK 14 : date.toLocaleS …(truncated, 207 more chars) Let me verify how new Date("2024-03-15") (date-only ISO) is parsed in JS: this is UTC-midnight, and toLocaleDateString() converts to local TZ. For France (UTC+1/+2), this is harmless — same calendar day. But let me double-check behavior of the new YYYY-MM-DDTHH:MM:SS format (no timezone) — JS treats that as local time per ES2016+, which is what the user wants for HL7 DTM without a timezone suffix. Good. Now let me verify the HL7 edge cases — DTM can have 4, 6, 10, 12, or 14 digits per HL7v2, or YYYYMMDDHHMMSS.SSSS with fractional seconds, or with +ZZZZ timezone suffix. The adapter only handles 8 and 14. Let me check what DMP's spec actually emits. Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "creationDate\|submissionDate\|serviceStartDate" packages/@doctolib/dmp/src --include=".ts" 2>/dev/null | grep -v test | grep -v dist | hea …(truncated, 5 more chars) Tool results: → result (ok): packages/@doctolib/dmp/src/types/DmpApi.ts:73: creationDate: string packages/@doctolib/dmp/src/types/DmpApi.ts:74: serviceStartDate: string packages/@doctolib/dmp/src/types/DmpApi.ts:78: submissionDate?: string packages/@doctolib/dmp/src/types/DmpApi.ts:153: creationDateBottom?: string packages/@doctolib/dmp/src/types/DmpApi.ts:154: creationDateTop?: string packages/@doctolib/dmp/src/types/DmpApi.ts:155: serviceStartDateBottom?: string packages/@doctolib/dmp/src/types/DmpApi.ts:156: servi …(truncated, 1994 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && sed -n '60,90p' packages/@doctolib/dmp/src/types/DmpApi.ts Tool results: → result (ok): export interface DmpEventCode { code?: string description?: string classification?: string } export interface DmpDocument { uniqueId: string title: string description: string classCode: string typeCode: string creationDate: string serviceStartDate: string serviceStopDate: string healthCareFacilityTypeCode: string practiceSettingCode: string submissionDate?: string submissionSetId?: string uuid: string previousUuid?: string nextUuid?: string documentStatus: …(truncated, 165 more chars) DmpDocument.typeCode: string is declared as required (non-optional). The adapter check if (doc.typeCode) truthy-guards against ''. That matches the test case { ...baseDoc, typeCode: '' }. Now let me check if there could be typeCodes with a falsy-but-meaningful value like '0' — extremely unlikely since DMP codes aren't "0". Let me also check how NhrDocument is typed for classification: Tools used: - Bash: grep -rn "NhrDocument\b" /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src 2>/dev/null | grep -v test | head -10 Tool results: → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src/index.ts:23: NhrDocument, /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src/index.ts:42: DmpNhrDocument, /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src/business/types/document.ts:24:export type NhrDocument = { /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src/business/types/index.ts:2: NhrDocume …(truncated, 642 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records/src/business/types/document.ts Tool results: → result (ok): 1 import type { NhrDocumentAuthor } from '#business/types/participant' 2 3 // General types --- 4 / The services/procedures this document is associated with / 5 export type NhrServiceInformation = { 6 startDate?: string 7 endDate?: string 8 } 9 10 export type NhrDocumentClassification = { 11 codes: Code[] 12 } 13 14 export type Code = { 15 system: string 16 code: string 17 } 18 19 export type DateRange = { 20 upperLimit?: string 21 lowerLimit?: string 22 } 23 24 export type …(truncated, 474 more chars) Good — creationDate?: string, submissionDate?: string, and serviceInformation.startDate?/endDate? all accept undefined, so the change is type-safe. Now let me see if there's a mock documents file test or consumers we should worry about — the mock documents' ISO dates (e.g., '2025-02-28') get rendered by new Date(...).toLocaleDateString(), which works correctly. Also let me verify one subtle edge case: the 14-char parser omits the Z / timezone suffix. DMP HL7 DTM (per ISO 8601 w/out TZ) is treated as local time. This is correct for procedure/share dates but worth noting. Let me check callers that might interpret parse as UTC (e.g. sorting): Tools used: - Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/columns/createNhrShareDateColumn.tsx Tool results: → result (ok): 1 import type { NhrDocument } from '@doctolib/tpf-national-health-records' 2 3 import { NhrShareDateCell } from '../../../components/NhrDocumentList/NhrShareDateCell' 4 import type { ColumnConfig } from '../../../types' 5 6 export type NhrShareDateColumnOptions = { 7 / Translated column header / 8 header: string 9 / 10 Extracts the ISO date string for the share date from the document. 11 Returns undefined when the share date is absent. 12 / 13 getDate: (doc: NhrDocum …(truncated, 642 more chars) Sort is string-based (lexicographic) on ISO strings, which sorts correctly for ISO dates. Good. One more check — look at the adapter test mock factory to make sure typeCode change didn't drop coverage elsewhere: Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git show fhir-2216_fix-nhr-date-columns-and-document-type:packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts | he …(truncated, 7 more chars) Tool results: → result (ok): import { getPatientInsForDMP } from '@doctolib/dmp' import type { DmpApi, DmpDocumentContent, SearchResult as DmpSearchResult } from '@doctolib/dmp' import type { NhrDocumentSearchProps } from '@doctolib/tpf-national-health-records' import { DmpNhrAdapter } from './DmpNhrAdapter' jest.mock('@doctolib/dmp', () => ({ getPatientInsForDMP: jest.fn(), DOCUMENT_STATUS: { validated: 1, obsolete: 2, archived: 4 }, DOCUMENT_VISIBILITY: { sharedWithAll: 1, notSharedWithPatient: 2, notSh …(truncated, 3404 more chars) Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && git show fhir-2216_fix-nhr-date-columns-and-document-type:packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts | se …(truncated, 15 more chars) Tool results: → result (ok): }, }, ], }) }) }) describe('HL7 date conversion in toNhrDocument', () => { const baseDoc = dmpSearchResult.documents[0] as (typeof dmpSearchResult.documents)[0] it('converts HL7-8 creationDate (YYYYMMDD) to ISO date string', async () => { const result = await new DmpNhrAdapter( createMockDmpApi({ documents: [{ ...baseDoc, creationDate: '20230907' }] }) ).searchDocuments(searchProps) expect(result.documents[0]?.creationDate).toBe …(truncated, 1811 more chars) Now I have a complete picture. Let me check if HL7 6/12 is realistic and if there's any remaining concern about parseInt-like validation (the parser does not validate digit content — "ABCDEFGH" of length 8 would become "ABCD-EF-GH"). Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "HL7\|DTM\|YYYYMMDD" packages/@doctolib/dmp/src 2>/dev/null | head -10 Tool results: → result (ok): packages/@doctolib/dmp/src/types/FrDmpTypes.ts:161: / Lower bound for document creation date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:163: / Upper bound for document creation date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:165: / Upper bound for service start date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:167: / Lower bound for service start date (format: YYYYMMDDHH …(truncated, 769 more chars) Critical finding: the DMP types' JSDoc says dates are YYYYMMDDHHmmSS in UTC. The adapter's new parseHl7DateToIso produces a local-time ISO string (no Z suffix), so when downstream calls new Date(iso).toLocaleDateString(), the date will be interpreted as the browser's local time rather than UTC. For a European user (UTC+1 or UTC+2) this is harmless for date-only (the calendar day doesn't shift because UTC+X is ahead of UTC, so a UTC midnight rendered as local time stays same-day or falls to prior day — actually, UTC 00:00:00 in Paris winter is 01:00 local — same day; but in summer with DST it's 02:00 local — same day). However, times near midnight UTC could shift the displayed day when rendering YYYYMMDDHHMMSS values close to midnight UTC (e.g. 20240320230000 UTC becomes 20240320T23:00:00 treated as local = stays Mar 20; but if a doc is 20240320013000 UTC = 01:30 UTC = 02:30 Paris, and we render it as "2024-03-20T01:30:00" local = interpreted as Paris 01:30 = shown as Mar 20 — but the real UTC day was still Mar 20, but the real Paris day was Mar 20 too). Let me think again. Actual issue: DMP says UTC. The conversion strips the UTC identity. A date 20240320230000 = 2024-03-20 23:00 UTC = 2024-03-21 00:00 Paris winter, but rendered here as "2024-03-20T23:00:00" interpreted as local → 2024-03-20 23:00 Paris, which wrongly displays Mar 20 instead of Mar 21. This is an off-by-a-day risk near midnight UTC. Whether it's material depends on product expectations (Doctolib generally displays in user's local tz). Let me verify the creationDate from the mock is pure YYYYMMDD in test (20240315), not 14-digit with UTC semantics, so the existing 8-digit branch is fine. The 14-digit branch has the potential for display drift. Let me check if there's a TZ offset suffix convention from DMP: Tools used: - Bash: cd /Users/USER/workspace/doctolib/doctolib && grep -rn "in UTC\|UTC)" packages/@doctolib/dmp/src 2>/dev/null | head -10 Tool results: → result (ok): packages/@doctolib/dmp/src/types/FrDmpTypes.ts:161: / Lower bound for document creation date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:163: / Upper bound for document creation date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:165: / Upper bound for service start date (format: YYYYMMDDHHmmSS in UTC) / packages/@doctolib/dmp/src/types/FrDmpTypes.ts:167: / Lower bound for service start date (format: YYYYMMDDHH …(truncated, 769 more chars) Confirmed: DMP docs say UTC but the adapter produces a local-time ISO string. This is a real correctness issue for rendering near midnight UTC. Now let me finalize the review. I've reviewed the PR. Here is my findings report. --- Files reviewed - /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts - /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts - /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts - /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.test.ts - /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/mocks/nhrMockedDocuments.ts Cross-referenced downstream consumers: columnsFactory.tsx, createNhrProcedureDateColumn.tsx, createNhrShareDateColumn.tsx, NhrProcedureDateCell.tsx, formatNhrDate in nhrDateHelpers.ts, and DmpDocument/NhrDocument types. --- Critical issues (90-100) 1. HL7 DTM timezone semantics silently dropped — potential off-by-a-day display near midnight UTC (confidence 88) File: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts lines 88-104 (parseHl7DateToIso). @doctolib/dmp explicitly documents these wire values as UTC: > / Document creation date (format: YYYYMMDDHHmmSS in UTC) */ (see FrDmpTypes.ts:371/373/382) The parser produces YYYY-MM-DDTHH:MM:SS with no Z suffix. Per ES2016+, an ISO 8601 string without a timezone designator is interpreted as local time by new Date(), which is the code path hit downstream in formatNhrDate (/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/utils/nhrDateHelpers.ts:5) and NhrShareDateCell.toLocaleDateString(). Concrete bug: a DMP submissionDate of 20250320230000 (2025-03-20 23:00 UTC) now becomes "2025-03-20T23:00:00" → interpreted as local 23:00 → displayed as 20/03/2025 for a French user. The true local time is 2025-03-21 00:00+ (winter) / 01:00+ (summer), so the share date should display as 21/03/2025. Rows with times near midnight UTC will show the previous day in France. Fix: append Z to mark it UTC so downstream new Date() / toLocaleDateString() converts to the user's locale correctly: return ${yyyy}-${mm}-${dd}T${hh}:${mi}:${ss}Z For the 8-char form there is no time/TZ ambiguity, so YYYY-MM-DD can stay (JS will treat it as UTC midnight, and toLocaleDateString in Europe will correctly show that day). Add a test with a near-midnight UTC DTM to lock this in. --- Important issues (80-89) 2. Parser silently accepts non-numeric length-8/14 strings (confidence 82) File: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts lines 90-103. parseHl7DateToIso only checks length. An accidental string like "Lundi-15" (8 chars) returns "Lund-i-15" and a downstream new Date(...) produces Invalid Date — but only formatNhrDate catches that via Number.isNaN(date.getTime()). Other potential consumers (sorting uses raw string comparison) will show garbled values. Also, other valid HL7 DTM lengths (4 YYYY, 6 YYYYMM, 10 YYYYMMDDHH, 12 YYYYMMDDHHMM, and fractional .SSSS / ±ZZZZ offset suffixes) silently return undefined, which hides legitimate data from the API rather than failing loudly. Fix: validate with a regex (e.g. /^\d{8}$/ / /^\d{14}$/) and log/no-op on unknown formats. Optionally extend to handle 12-char YYYYMMDDHHMM — this is common for procedure dates without seconds. 3. parseHl7DateToIso accepts .length === 14 but ignores fractional seconds and TZ offset (confidence 80) File: same as #2. HL7 v2 DTM explicitly allows YYYYMMDDHHMMSS.SSSS and YYYYMMDDHHMMSS[+/-ZZZZ]. Any DMP document that embeds those forms will have its date dropped (undefined) by the current parser and render as – in the UI — the same bug the PR is trying to fix, just shifted to a less common input. Consider either stripping .SSSS and parsing any trailing +/-ZZZZ into the emitted ISO string, or at minimum documenting the supported subset and adding a test that the unsupported forms return undefined deterministically (rather than by accident). --- Observations (informational, below reporting threshold but worth flagging) - isPatientAuthored invariant is preserved correctly. Splitting DMP_SYSTEM into CLASS_CODE_SYSTEM / TYPE_CODE_SYSTEM keeps the classCode '90' check tight to the class code dimension, and the test returns false when only typeCode "90" is present locks that in. Good. - Return-type change string → string | undefined on getProcedureDate / getShareDate is safe — the downstream getDate prop on createNhrProcedureDateColumn / createNhrShareDateColumn is already typed string | null | undefined and sortAccessor uses ?? '' fallback. - Test typeCode: '' case — note this relies on DmpDocument.typeCode: string being required in the type but the adapter's if (doc.typeCode) falsy-guard treating '' as absent. That's fine today, but if a real DMP record ever ships typeCode: '0' (unlikely for LOINC), it would be skipped; acceptable. - Mock cleanup is well executed — statuses now use the numeric strings ('1', '2', '4') consistent with DOCUMENT_STATUS and class codes are real LOINC/JDV values (34874-8, REMB, 90, 11488-4, etc.). Batch 13 exercises the new dual-code path for getTypeCode. - Missing test coverage: no adapter test asserts submissionDate: undefined stays undefined (the original pre-fix behavior), and no test exercises serviceStopDate (only serviceStartDate). Low-value additions but would round out the matrix. --- Summary Ship-blocker candidate: Issue #1 (UTC → local drift). The PR fixes the three user-visible bugs the ticket targets, but in replacing the raw HL7 pass-through with a partial ISO conversion it loses the UTC timezone information that the DMP API guarantees. For 8-char YYYYMMDD values this is cosmetic; for 14-char YYYYMMDDHHMMSS values it will mis-display share / procedure dates near midnight UTC for French users. Appending Z when emitting the 14-char form is a one-line change and the existing test can be extended to cover it. Everything else — the classCode/typeCode split, isPatientAuthored guard, mock realignment, and expanded test coverage — is solid.