{
  "id": "treatment-plan/review-the-pr-https-github-com-doctolib-shiny-axolotl-subagent-a243328f",
  "slug": "review-the-pr-https-github-com-doctolib-shiny-axolotl-subagent-a243328f",
  "title": "Session: review-the-pr-https-github-com-doctolib-shiny-axolotl-subagent-a243328f — 2026-04-23",
  "type": "source",
  "project": "treatment-plan",
  "date": "2026-04-23",
  "started": "2026-04-23T14:19:26.511000+00:00",
  "ended": "2026-04-23T14:20:57.819000+00:00",
  "model": "claude-sonnet-4-6",
  "cwd": "/Users/USER/workspace/doctolib/treatment-plan",
  "git_branch": "main",
  "permission_mode": "",
  "user_messages": 1,
  "tool_calls": 15,
  "tools_used": [
    "Bash",
    "Read"
  ],
  "is_subagent": true,
  "wikilinks_out": [],
  "body_text": "Project: treatment-plan · Branch: main · Mode:  · Model: claude-sonnet-4-6\n\nStats: 1 user messages, 15 tool calls, tools used: Bash, Read.\n\nConversation\n\nTurn 1 — User\n\nReview PR #3019 in the doctolib/treatment-plan repository for test coverage quality and completeness. Do NOT post any comments on the PR — report your findings as text output only.\n\nPR context\n- Title: feat(FHIR-2194): pass document to dropdown action callbacks and add isAvailable filter\n- Package: @doctolib/tpf-national-health-records-ui\n- Change type: Frontend feature (TypeScript/React, Vitest + RTL)\n\nWhat changed (functional)\n1. DropdownActionOption.onClick now receives the NhrDocument as argument\n2. New isAvailable?: (doc: NhrDocument) => boolean predicate — when false, option is hidden from that row\n3. New 'link-primary' added to uiStyle union\n4. MoreActions, ActionButton, NhrDocumentListModal updated accordingly\n\nTest files updated\n- ActionButton.test.tsx — 3 new tests for isAvailable\n- MoreActions.test.tsx — 7 cases updated; link-primary style test added\n- NhrDocumentListModal.test.tsx — integration test verifying document passed to onClick\n- NhrDocumentListTableBody.test.tsx — assertions updated for document parameter\n\nHow to get the diff\ngh pr diff 3019 --repo doctolib/treatment-plan\n\nThe local repo is at /Users/USER/workspace/doctolib/treatment-plan — you can read test files directly.\n\nWhat to focus on\n- Are all paths through isAvailable tested? (undefined, returns true, returns false, mixed)\n- Is the onClick(doc) call verified with the correct document object?\n- Edge cases: empty option list, all options filtered out, async onClick handlers\n- Are the link-primary style tests complete?\n- Missing test scenarios for NhrDocumentListModal threading\n- Test quality: are assertions meaningful (not just \"doesn't crash\")?\n\nReport: (1) what's well-covered, (2) gaps and missing scenarios, (3) severity of each gap.\n\nTurn 1 — Assistant\n\nI'll start by fetching the PR diff and reading the relevant test files to do a thorough analysis.\n\nTools used:\n\n- Bash: gh pr diff 3019 --repo doctolib/treatment-plan 2>&1 | head -500\n\nTools used:\n\n- Bash: find /Users/USER/workspace/doctolib/treatment-plan/packages -type f -name \".tsx\" | xargs grep -l \"NhrDocumentList\\|MoreActions\\|ActionButton\\|DropdownActionOption\" 2>/dev/null | head -20\n\nTool results:\n\n  → result (ok): diff --git a/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx b/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx\nindex ee5f3198b1..d4e7919d7d 100644\n--- a/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx\n+++ b/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx\n@@ -157,7 +157,9 @@ const sharedBySampleR\n…(truncated, 20813 more chars)\n\nTool results:\n\n  → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.stories.tsx\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.test.tsx\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentList/NhrDocumentList.tsx\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-r\n…(truncated, 2525 more chars)\n\nTools used:\n\n- Bash: gh pr diff 3019 --repo doctolib/treatment-plan 2>&1 | tail -400\n\nTool results:\n\n  → result (ok): +  })\n+\n+  it('should pass the row to shouldBeVisible', () => {\n+    const shouldBeVisible = vi.fn().mockReturnValue(true)\n+    const action = createMoreActionsAction([\n+      { key: 'archive', label: 'Archive', isAvailable: shouldBeVisible, onClick: vi.fn() },\n+    ])\n+    const row = nhrDocumentFixtureBuilder()\n+\n+    setup(<ActionButton action={action} row={row} />)\n+\n+    expect(shouldBeVisible).toHaveBeenCalledWith(row)\n+  })\n })\ndiff --git a/packages/tpf-national-health-records-ui/src/comp\n…(truncated, 16710 more chars)\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/ActionButton.tsx\n\nTool results:\n\n  → result (ok): 1\timport type { NhrDocument } from '@doctolib/tpf-national-health-records'\n2\t\n3\timport type { ActionConfig } from '../../../../types'\n4\timport { MoreActions } from './MoreActions'\n5\timport { SimpleAction } from './SimpleAction'\n6\t\n7\ttype ActionButtonProps = {\n8\t  action: ActionConfig\n9\t  row: NhrDocument\n10\t}\n11\t\n12\texport const ActionButton = ({ action, row }: ActionButtonProps) => {\n13\t  if (action.kind === 'dropdown') {\n14\t    if (action.options.length === 0) return null\n15\t\n16\t    return <Mo\n…(truncated, 102 more chars)\n\nNow let me read the actual test files as they exist in the PR branch and the source files to understand the full picture:\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/ActionButton.test.tsx\n\nTool results:\n\n  → result (ok): 1\timport type { DesignSystemIconComponent } from '@doctolib/design-system-icons'\n2\timport { setup } from '@doctolib/test-helpers'\n3\timport { screen } from '@testing-library/react'\n4\timport { describe, expect, it, vi } from 'vitest'\n5\t\n6\timport { createMoreActionsAction } from '../../../../business/factories/actions/createMoreActionsAction'\n7\timport { nhrDocumentFixtureBuilder } from '../../../../test-helpers/fixtures/nhrDocumentFixtureBuilder'\n8\timport type { SimpleActionConfig } from '../../../\n…(truncated, 1421 more chars)\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/MoreActions.test.tsx\n\nTool results:\n\n  → result (ok): 1\timport type { DesignSystemIconComponent } from '@doctolib/design-system-icons'\n2\timport { setup } from '@doctolib/test-helpers'\n3\timport { screen, waitFor } from '@testing-library/react'\n4\timport { describe, expect, it, vi } from 'vitest'\n5\t\n6\timport { createMoreActionsAction } from '../../../../business/factories/actions/createMoreActionsAction'\n7\timport type { DropdownActionOption } from '../../../../types'\n8\timport { MoreActions } from './MoreActions'\n9\t\n10\tconst MockIcon = (() => <svg data\n…(truncated, 3243 more chars)\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListModal.test.tsx\n\nTool results:\n\n  → result (ok): 1\timport type { DesignSystemIconComponent } from '@doctolib/design-system-icons'\n2\timport { setup } from '@doctolib/test-helpers'\n3\timport { screen, waitFor } from '@testing-library/react'\n4\timport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'\n5\t\n6\timport { createMoreActionsAction } from '../../business/factories/actions/createMoreActionsAction'\n7\timport { mockColumns, mockPatientInfo } from '../../test-helpers'\n8\timport { nhrDocumentFixtureBuilder } from '../../test-helpers/\n…(truncated, 8225 more chars)\n\nI notice the local test files don't reflect the PR changes yet (the MoreActions.test.tsx still shows the old version without doc prop). Let me read the remaining test files and the source files to get the complete picture:\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/NhrDocumentListTableBody.test.tsx\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/types.ts\n\nTool results:\n\n  → result (ok): 1\timport type { DesignSystemIconComponent } from '@doctolib/design-system-icons'\n2\timport { setup } from '@doctolib/test-helpers'\n3\timport { screen, waitFor } from '@testing-library/react'\n4\timport { describe, expect, it, vi } from 'vitest'\n5\t\n6\timport { createMoreActionsAction } from '../../../../business/factories/actions/createMoreActionsAction'\n7\timport { mockColumns, mockRows } from '../../../../test-helpers'\n8\timport { nhrDocumentFixtureBuilder } from '../../../../test-helpers/fixtures/nhr\n…(truncated, 5906 more chars)\n\nTool results:\n\n  → result (ok): 1\timport type { DesignSystemIconComponent } from '@doctolib/design-system-icons'\n2\timport type { NhrDocument } from '@doctolib/tpf-national-health-records'\n3\timport type { ReactNode } from 'react'\n4\t\n5\texport type NhrPatientInfo = {\n6\t  fullName: string\n7\t  gender: 'male' | 'female' | 'other'\n8\t  birthDate: string\n9\t  age: number\n10\t}\n11\t\n12\texport type ColumnConfig = {\n13\t  key: string\n14\t  header: string\n15\t  sortable: boolean\n16\t  / Only required when sortable: true. Returns a string for lo\n…(truncated, 3393 more chars)\n\nNow I have a clear picture. The local main branch has the old code (without the PR changes), and I've been reading the PR diff to understand exactly what the PR proposes. The local types.ts also shows the old API. Let me verify one more important piece — the NhrDocumentListTableBody.test.tsx in the PR diff vs what's on disk to confirm my understanding:\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/MoreActions.tsx\n\nTool results:\n\n  → result (ok): 1\timport { Dropdown } from '@doctolib/design-system/Dropdown'\n2\timport { DropdownTrigger } from '@doctolib/design-system/DropdownTrigger'\n3\timport type { IconName } from '@doctolib/design-system/Icon'\n4\timport { IconButton } from '@doctolib/design-system/IconButton/v2'\n5\t\n6\timport type { DropdownActionConfig, DropdownActionOption } from '../../../../types'\n7\t\n8\ttype DropdownOptionProps = {\n9\t  option: DropdownActionOption\n10\t}\n11\t\n12\tconst DropdownOption = ({ option }: DropdownOptionProps) => {\n\n…(truncated, 1356 more chars)\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListModal.tsx\n\nTool results:\n\n  → result (ok): 1\timport { Modal } from '@doctolib/design-system/Modal'\n2\timport { ModalBody } from '@doctolib/design-system/ModalBody'\n3\timport type { NhrDocument } from '@doctolib/tpf-national-health-records'\n4\timport { useEffect, useMemo, useState } from 'react'\n5\t\n6\timport type { ActionConfig, ColumnConfig, FilterConfig, NhrPatientInfo, SearchDocumentsFn } from '../../types'\n7\timport { NhrDocumentList } from '../NhrDocumentList/NhrDocumentList'\n8\t\n9\texport type NhrDocumentListModalProps = {\n10\t  isOpen: boo\n…(truncated, 2809 more chars)\n\nI now have a complete picture. The local main branch is the pre-PR state. I've read both the old code and the full PR diff. Let me do a final check on the NhrDocumentListTableBody.test.tsx — specifically the PR diff version of it shows expect(onDownload).toHaveBeenCalledWith(doc) as the change, but the file on disk still has the old version. Let me also check the fixture builder to understand what nhrDocumentFixtureBuilder() produces:\n\nTools used:\n\n- Bash: find /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui -name \"nhrDocumentFixtureBuilder\" 2>/dev/null\n\nTool results:\n\n  → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/dist/test-helpers/fixtures/nhrDocumentFixtureBuilder.d.ts\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/dist/test-helpers/fixtures/nhrDocumentFixtureBuilder.js.map\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/dist/test-helpers/fixtures/nhrDocumentFixtureBuilder.js\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-\n…(truncated, 552 more chars)\n\nTools used:\n\n- Bash: find /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui -name \"createMoreActionsAction*\" 2>/dev/null\n\nTool results:\n\n  → result (ok): /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/actions/createMoreActionsAction.test.ts\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/actions/createMoreActionsAction.ts\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/dist/business/factories/actions/createMoreActionsAction.js.map\n/Users/USER/workspace/doctolib/treatment-plan/packages/tpf\n…(truncated, 384 more chars)\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/actions/createMoreActionsAction.ts\n\nTool results:\n\n  → result (ok): 1\timport { EllipsisVerticalRegularIcon } from '@doctolib/design-system-icons/EllipsisVerticalRegularIcon'\n2\t\n3\timport type { DropdownActionConfig, DropdownActionOption } from '../../../types'\n4\t\n5\texport const createMoreActionsAction = (options: DropdownActionOption[]): DropdownActionConfig => ({\n6\t  kind: 'dropdown',\n7\t  key: 'more',\n8\t  tooltip: 'More actions',\n9\t  iconComponent: EllipsisVerticalRegularIcon,\n10\t  variant: 'transparent',\n11\t  options,\n12\t})\n13\n\nTools used:\n\n- Read: /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/business/factories/actions/createMoreActionsAction.test.ts\n\nTool results:\n\n  → result (ok): 1\timport { EllipsisVerticalRegularIcon } from '@doctolib/design-system-icons/EllipsisVerticalRegularIcon'\n2\timport { describe, expect, it, vi } from 'vitest'\n3\t\n4\timport type { DropdownActionOption } from '../../../types'\n5\timport { createMoreActionsAction } from './createMoreActionsAction'\n6\t\n7\tconst mockOption: DropdownActionOption = {\n8\t  key: 'download',\n9\t  label: 'Download',\n10\t  onClick: vi.fn(),\n11\t}\n12\t\n13\tdescribe('createMoreActionsAction', () => {\n14\t  it('returns ActionConfig with ke\n…(truncated, 1200 more chars)\n\nI now have a thorough understanding of the PR. Let me compile my findings.\n\n---\n\nSummary\n\nThe PR introduces three related behavioral changes to @doctolib/tpf-national-health-records-ui: passing the NhrDocument row to onClick callbacks, filtering options per-row via isAvailable, and adding 'link-primary' to the uiStyle union. The test coverage is generally solid and the approach is behavior-first. However, the analysis below reveals several concrete gaps — some of which are important enough to merit action before merge.\n\n---\n\nWhat's Well Covered\n\nMoreActions.test.tsx (PR version): Every uiStyle branch is covered end-to-end for the onClick(doc) contract. The neutral (Dropdown.Item), link-danger (Dropdown.Button), and newly added link-primary branches each have their own click-through test verifying expect(onClick).toHaveBeenCalledWith(row). This is good because MoreActions.tsx has two distinct render paths inside DropdownOption (the if (option.uiStyle) branch vs. the fallthrough), and all three style variants exercise both paths.\n\nActionButton.test.tsx (PR version): The isAvailable filter logic is tested cleanly at three points — isAvailable returning true, returning false for all options (empty result), and the argument passed to it being the correct row object. These directly target the filter expression !opt.isAvailable || opt.isAvailable(row) in ActionButton.tsx.\n\nNhrDocumentListModal.test.tsx (PR version): The new integration test verifies the full threading chain: searchDocuments returns a document, the dropdown is opened, an option is clicked, and onClick receives the exact same document object. This is the most important regression scenario for the feature and it's covered.\n\nNhrDocumentListTableBody.test.tsx (PR version): The onClick(doc) assertion is updated from toHaveBeenCalledOnce() to toHaveBeenCalledWith(doc) — a meaningful improvement that would catch the regression of passing the wrong document or no document.\n\n---\n\nCritical Gaps\n\nGap 1 — Mixed isAvailable scenario not tested (ActionButton layer)\nCriticality: 8/10\n\nThe ActionButton filtering logic action.options.filter((opt) => !opt.isAvailable || opt.isAvailable(row)) is only tested with a uniform result: all options visible (one test), or the single option invisible (one test). The practical use case is a list where some options have isAvailable returning false and others return true (or have no isAvailable predicate at all). There is no test for: given three options where option A has isAvailable returning false, option B has isAvailable returning true, and option C has no isAvailable, the rendered dropdown shows exactly options B and C.\n\nWithout this test, a future change that accidentally applies the filter to the wrong subset or inverts the logic for the mixed case would pass all existing tests.\n\nThe relevant source is the filter expression in /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/ActionButton.tsx (post-PR line: const visibleOptions = action.options.filter((opt) => !opt.isAvailable || opt.isAvailable(row))).\n\nGap 2 — isAvailable filtering is tested at ActionButton but not confirmed to flow through to the rendered dropdown options (MoreActions layer)\nCriticality: 7/10\n\nActionButton passes { ...action, options: visibleOptions } down to MoreActions. The ActionButton tests confirm visibleOptions.length === 0 → nothing rendered, and that shouldBeVisible is called with the row. But no test opens the dropdown and asserts which option labels are visible vs. absent after filtering. The existing ActionButton tests checking isAvailable: false only assert container.toBeEmptyDOMElement() (which is for the all-filtered case); the partial filter case described in Gap 1 means we can't tell if hidden options are actually absent from the DOM.\n\nThis failure mode: a regression that passes all filtered options to MoreActions regardless of the filter result would not be caught.\n\nGap 3 — NhrDocumentListModal loading overlay with dropdown action and isAvailable predicate\nCriticality: 6/10\n\nNhrDocumentListModal.tsx wraps each DropdownActionOption.onClick to set isActionLoading. It also passes isAvailable through unchanged (the PR spreads ...option before overriding onClick). There is no test confirming that isAvailable still functions correctly after the wrapping — specifically that a hidden option (one whose isAvailable returns false) is not shown in the modal's rendered table. The existing modal test for isAvailable behavior is entirely absent; only the onClick(doc) threading is verified at the modal level.\n\nGap 4 — NhrDocumentListTableBody does not test row-specific option filtering (per-row isAvailable across multiple rows)\nCriticality: 6/10\n\nThe NhrDocumentListTableBody tests cover \"dropdown trigger per row\" and \"option onClick per row,\" but the per-row nature of isAvailable is not exercised at this level. With two rows where isAvailable returns true for row 1 and false for row 2, the expectation is that row 1 shows the dropdown trigger and row 2 does not. This is the scenario most likely to reveal a regression where the row argument is captured incorrectly (closure over the wrong variable during filter). The filtering logic lives in ActionButton.tsx which is called once per row, so an integration test at the NhrDocumentListTableBody level would provide the highest confidence for this scenario.\n\n---\n\nImportant Improvements\n\nGap 5 — link-primary style rendering is not separately verified in MoreActions\nCriticality: 5/10\n\nThe new link-primary test in MoreActions.test.tsx confirms onClick(row) is called but does not assert the visual rendering — specifically that a Dropdown.Button (rather than Dropdown.Item) is used for link-primary, and that it is accessible. For link-danger, the equivalent test asserts the button is in the document by role before clicking. The link-primary test does the same (it clicks the button, which implicitly confirms it renders), so this is a minor gap — but there is no assertion that the uiStyle prop is forwarded to the design system component. If link-primary accidentally falls through to the Dropdown.Item branch (because the if (option.uiStyle) check is true for any truthy uiStyle value), the visual treatment would be wrong but all tests would still pass.\n\nGap 6 — NhrDocumentListTableBody onClick(doc) assertion uses toHaveBeenCalledOnce() without confirming the argument\nCriticality: 5/10 (already noted as partially addressed by the PR)\n\nLooking at the diff again carefully: the PR changes line 166 from expect(onDownload).toHaveBeenCalledOnce() to expect(onDownload).toHaveBeenCalledWith(doc). However, the local file on disk at /Users/USER/workspace/doctolib/treatment-plan/packages/tpf-national-health-records-ui/src/components/NhrDocumentListModal/NhrDocumentListTable/NhrDocumentListTableBody/NhrDocumentListTableBody.test.tsx line 166 still reads expect(onDownload).toHaveBeenCalledOnce(). This means the PR diff correctly proposes the fix but the local branch doesn't have it applied yet. Assuming the PR branch does contain the change, this is addressed.\n\n---\n\nTest Quality Issues\n\nIssue 1 — NhrDocumentListModal test for onClick(doc) uses vi.useRealTimers() inconsistently\n\nIn NhrDocumentListModal.test.tsx, the beforeEach sets vi.useFakeTimers() but the new test (line 181 in the PR diff) calls vi.useRealTimers() at the top of the test body. This pattern is consistent with the other tests in that file that need async behavior (searchDocuments resolves), so it is intentional. However, there is no corresponding call to restore fake timers in afterEach for this specific test \n…(truncated, 1904 more chars)",
  "sha256": "ed40e01f2803d478",
  "source_url": "sessions/treatment-plan/2026-04-23T14-19-treatment-plan-review-the-pr-https-github-com-doctolib-shiny-axolotl-subagent-a243328f.html"
}