Commit Graph
343 Commits
Author SHA1 Message Date
GiteadandClaude Sonnet 5 df5d2267cd feat: map upper/lower partial denture phrases to D5211/D5212 in CDT lookup
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 11:41:11 -04:00
GiteadandClaude Sonnet 5 c719b20dd0 feat: United Ucard claim searches by name+DOB and fills tooth number/surface when provided
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 23:40:50 -04:00
GiteadandClaude Sonnet 5 7ec82902d9 feat: United Ucard name+DOB eligibility search via chat, duplicate-record handling, Product ID as member ID
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 22:30:01 -04:00
GiteadandClaude Sonnet 5 ce25cdd2a2 fix: DDMA claim checkbox, eligibility patient name, and ID+DOB patient lookup
- Claim step2: robust member checkbox selection with page-wide fallback
- Eligibility: take patient name from 'Benefits for' heading, not subscriber name
- Processor: update the patient just created/matched by ID+DOB, not first ID match

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 15:56:03 -04:00
Gitead dcf2ff536a fix: close browser window after Deltains claim completes
Session still persists via the Chrome profile/saved cookies, so
closing the window doesn't force a re-login or OTP next time.
2026-09-18 14:51:56 -04:00
GiteadandClaude Sonnet 5 7b8a7af5d7 fix: update DDMA claim worker for new provider portal
DDMA redesigned their claims-submission flow, so the worker now navigates
via the dashboard's "Submit Claims" quick link, the "Member Search" and
"Claim Detail" sidebar sections, checkbox-based member selection, indexed
treatment-row fields, a multi-file upload input, and the new confirmation
page layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 14:36:14 -04:00
Gitead d91e74c959 fix: Deltains claim selectors and dedicated fee schedule
Fixes the transaction-type radio button (was matching nothing; now
targets the real data-testid), and adds a Deltains fee schedule
(seeded from DDMA's prices) so Deltains claims stop falling back to
MassHealth pricing.
2026-09-17 21:00:07 -04:00
Gitead 37695130d3 feat: add Deltains claim submission flow
Adds a full "Deltains Claim" button next to Delta MA Claim, mirroring
the DDMA claim flow across frontend, backend queue/routes, and a new
Selenium worker. Reuses the existing Deltains eligibility login/OTP
code and was iteratively wired against the live portal (patient roster
search, per-service-line fields, tooth number/surface selects, review
and submit). Also fixes chatbot/insurance-alias carrier recognition so
"deltains" resolves correctly instead of falling back to MassHealth.
2026-09-17 13:11:58 -04:00
GiteadandClaude Sonnet 5 8cbdba092d fix: handle no-history single-match case in United Ucard claim search
Only two paths now: click the radio in the last history row when a
table is shown, or click the Member Details link directly when no
history/radio appears at all (single unambiguous match, as seen for
patient Nassim). Removes the first-row retry fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 23:23:48 -04:00
GiteadandClaude Sonnet 5 865b754ae1 fix: complete United Ucard claim flow and remember OTP device
- Click the first visible 'Next' button on the Patient Information step
  instead of a stale hidden one, so the wizard advances after member select
- Read procedure fee from totalBilled/billedAmount (matching every other
  claim worker) instead of a fee key the frontend never sends
- Implement claim confirmation PDF capture + claim number extraction
- Check "Remember this device" on the OTP page so future logins skip OTP

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 22:45:05 -04:00
GiteadandClaude Sonnet 5 d7015270a8 fix: auto-refresh patient table after eligibility checks
Remaining benefit amount didn't show until a manual page reload
because invalidateQueries was placed after an early return (chatbot
claim flow) for MH checks, and was missing entirely from the 7
other-provider eligibility buttons.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 13:37:56 -04:00
GiteadandClaude Sonnet 5 765368216f fix: route United Ucard claims correctly and add fee schedule
- AI-column auto-submit and manual "Claim All" dispatchers in claim-form.tsx
  had no United Ucard branch, so United Ucard claims silently fell through
  to the MassHealth (MH) submit handler instead of opening the United Ucard
  site.
- Added a United Ucard fee schedule (copied from United SCO as a starting
  point) and wired it into the frontend price-mapping/mismatch-check code
  and the backend fee-schedule update route, which previously had no
  schedule for United Ucard and fell back to MassHealth's prices.
- Selenium claim worker: when the member search returns multiple coverage
  records, it now tries the last row first (existing default) and falls
  back to the first row only if the "Member Details" link never appears
  (i.e. the last row was an inactive record), instead of only ever trying
  one or the other.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 13:21:53 -04:00
GiteadandClaude Sonnet 5 af62bf151e fix: poll longer for Status & History table to load in preauth worker
Status & History page loads results asynchronously; a single 20s wait
was giving up before the row appeared, so the pre-auth number was
never captured. Now polls up to 75s for a populated row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:38:06 -04:00
GiteadandClaude Sonnet 5 e570a0aa13 feat: add United Ucard claim worker and fix batch-column site-key routing
Adds a "United Ucard Claim" button (claims/preauth insurance form) that
submits through a full Selenium pipeline mirroring the Tufts SCO claim
worker: frontend handler -> backend route/queue processor -> Python
agent, reusing the persistent login/OTP session from the existing
United Ucard eligibility check. Implements the UHC Dental claim wizard
end-to-end (Provider Information, Patient Information search/select,
Claim Information procedures + questions, Upload Documents, Review and
Sign, Submit); the final confirmation-page PDF/claim-number capture is
still a TODO stub pending that page's DOM.

Also wires United Ucard into the AI chatbot's eligibility flow
(insuranceAliases.json, siteKeyToAutoCheck, clarification options), and
fixes a bug where the AI-column batch claim feature silently defaulted
United Ucard patients to MassHealth because batchColumnDeriveSiteKey
had no matching branch and no job-dispatch case for UNITED_UCARD.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:27:39 -04:00
GiteadandClaude Sonnet 5 f30016e674 feat: add United Ucard eligibility check with OTP + persistent session
Adds a full login/OTP/search/capture flow for United Ucard (OneHealthcareID
-> UHC Dental provider portal), mirroring the United SCO/DDMA pattern:
persistent Chrome profile, OTP polling, member eligibility search, and PDF
capture saved to the patient's Eligibility folder.

Also fixes a validation bug in the browser-safe patient schema where
email/address/city/zipCode/gender/phone were optional but not nullable,
rejecting patient records with null values on those fields during edits
(e.g. "Expected string, received null").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 22:44:43 -04:00
GiteadandClaude Sonnet 5 e8889c0ff8 fix: auto-price CDT codes and fix crown/recement code mismatches
- Auto-fill service line price when a recognized CDT code is typed
  (e.g. D2740), instead of requiring a separate "Map Price" click
- Fix chatbot preauth prefill using an empty DOB for price lookup,
  causing age-tiered codes (D2740) to price as $0
- Re-apply fee-schedule pricing with the loaded patient DOB before
  MassHealth preauth auto-submit
- Add a "Recement Crown" (D2920) combo button distinct from "Crown"
  (D2740) to avoid picking the wrong code/price
- Fix AI note parsing to prioritize "recement" over "crown" regardless
  of word order or tooth-number format (e.g. "#7 crown recement")

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 23:29:43 -04:00
GiteadandClaude Sonnet 5 00a81b3fda fix: correctly suppress PDF popup for last claim in AI-column batch
closeClaim() was clearing chatbotAutoSubmitSiteKey synchronously right
after the selenium job kicked off, before the job's async completion
handler could check it. This was masked for all but the last claim in
the batch because closeClaim() also navigated away (unmounting the
page) whenever more claims were queued. On the last claim the page
stayed mounted, so the completion handler read a stale cleared value
and let the PDF preview popup through. Track the site key in a ref
that survives closeClaim() and is cleared only after the job's own
completion handler consumes it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 08:56:52 -04:00
GiteadandClaude Sonnet 5 fd2d1e6aba fix: default tooth # for 2PA and skip PDF popup for AI chat claims
- 2PA with no explicit tooth numbers now defaults to D0220 #8 / D0230 #24
- Claims submitted via the AI chat column no longer auto-open the PDF preview modal

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 15:52:31 -04:00
GiteadandClaude Sonnet 5 d35efe7366 fix: reliability fixes for UHC SCO and CMSP eligibility checks
- unitedSCOEligibilityProcessor: overwrite patient's stored insuranceId when
  the eligibility page reports a different (updated) Member ID than the one
  searched with.
- CMSP worker: add AngularJS late-binding retry to results-table extraction
  (ported from the MH worker's a0417653 fix), since every patient now routes
  through this worker for the accumulator check.
- cmspEligibilityHistoryRemainingProcessor: stop forcing patient status to
  UNKNOWN when extraction fails; a failed run landing after a successful one
  was clobbering a correct ACTIVE/INACTIVE status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 13:11:58 -04:00
GiteadandClaude Sonnet 5 74d5c7c7ff feat: wire up mic/speaker and Google Translate backend for live translation
Frontend uses the Web Speech API for speech-to-text and text-to-speech
(no key needed). Adds POST /api/translate backed by Google Cloud
Translation API v2, gated on GOOGLE_TRANSLATE_API_KEY (placeholder
added to .env/.env.example, unset by default).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 21:28:57 -04:00
GiteadandClaude Sonnet 5 616ca5f259 feat: add live translation UI section above dial pad
Google Translate-style side-by-side layout with per-side language
pickers on the patient connection page. UI shell only for now, no
translation provider wired up yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 16:05:30 -04:00
GiteadandClaude Sonnet 5 8f9fd13208 fix: update hardcoded folder name from DentalManagementMH07 to DentalManagement09
Scripts still referenced the old project folder name after the rename,
which broke the desktop shortcuts and start/stop scripts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:51:17 -04:00
GiteadandClaude Sonnet 5 79ac6aaa31 feat: migrate SMS/voice to Telnyx (TeXML), keep browser dial pad on Twilio
Twilio now handles only the in-browser dial pad (Access Token + browser-Device
outbound TwiML); Telnyx takes over SMS, inbound voicemail, the AI voice
conversation loop, and staff-triggered outbound calls via TeXML. Adds
TelnyxSettings model, Communication.provider discriminator, new comms/routes
modules, and a real Telnyx Settings page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:39:43 -04:00
Gitead b899659e13 docs: add ngrok vs Cloudflare Tunnel comparison for Twilio tunneling 2026-09-02 22:59:25 -04:00
GiteadandClaude Sonnet 5 52ddfd9f57 feat: add Remaining/Third Party columns, toggle PDF viewer, retire CMSP as separate insurance type
- Add remainingBenefit and thirdPartyInsurance columns to Patient; extract both
  from the MassHealth accumulator/member-detail pages during the eligibility
  check and surface them in the eligibility table
- Add an updated-date display and a toggle to suppress the post-check PDF
  viewer popup (default off) on the insurance eligibility page
- Rename CMSP-prefixed PDF filenames and UI copy to MH, since CMSP and MH now
  share the same worker
- Fold CMSP into MassHealth/MH across patient/claim insurance-type dropdowns
  and the chatbot's eligibility routing, since they're the same insurance
- Remove auto-download of saved eligibility PDFs; downloading is now manual

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:32:43 -04:00
GiteadandClaude Sonnet 5 f8235787db fix: handle DDMA site redesign in eligibility check flow
DDMA now often skips the family-members results table and navigates
straight to the single-patient detail page, and labels the patient's
name "Subscriber name:" instead of "Name:". Update step1/step2 to
detect the detail-page URL correctly (it's nested under the search
path, so a plain substring check couldn't tell them apart), extract
the name from the new label, and fall back to parsing "Coverage is:"
for eligibility status when there's no results row to read it from.
Also fix a status-text substring bug ("active" matching inside
"inactive") and stop the backend from collapsing an unknown
eligibility result into INACTIVE. Skip name extraction entirely when
the caller already knows the patient (existing-patient recheck).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 21:20:38 -04:00
GiteadandClaude Sonnet 5 b860fd213f fix: allow chatbot auto-scheduling when eligibility status is UNKNOWN
Only block appointment creation on explicit INACTIVE status, since
scrapes for some plan types (e.g. MassHealth Child Medicaid) can land
on UNKNOWN without actually finding an ineligible record.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 20:39:57 -04:00
Gitead 116889dd4e perf: reduce fixed sleeps in MassHealth click_plus_button
Cuts unconditional delay when adding a service line from ~7s to ~3s
as a first pass at speeding up MassHealth claim submission.
2026-08-20 00:37:14 -04:00
GiteadandClaude Sonnet 5 ad9d311a99 fix: tolerate single-letter typos in CDT code text matching
Adds Levenshtein-based fuzzy word matching to lookupCdtCodes so
misspellings like "comprehensiv exam" resolve the same as
"comprehensive exam". Both the AI chat bot and the AI claim column
share this matcher, so the fix applies to both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 00:01:41 -04:00
GiteadandClaude Sonnet 5 374f96399e docs: add fallback keyring-disable steps for when apt purge isn't enough
D-Bus service activation can respawn gnome-keyring-daemon even after
the package is removed and PAM/autostart hooks are disabled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 23:45:06 -04:00
GiteadandClaude Sonnet 5 e934d6bce5 chore: gitignore GCP service account key in PaymentOCRService
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 23:43:15 -04:00
GiteadandClaude Sonnet 5 304441d95a fix: nginx proxy_pass uses 127.0.0.1 instead of localhost
localhost resolves to ::1 first; backend/Vite only bind IPv4, causing
intermittent 502s when nginx tried the IPv6 loopback address.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 23:41:10 -04:00
GiteadandClaude Fable 5 5044fecb07 fix: UnitedDH selenium duplicated first attachment (multi-file input appends on send_keys)
DentalHub's upload input is a multi-file input; chromedriver send_keys
appends to the existing selection instead of replacing it, so the second
iteration re-uploaded the first file (2 attachments became 3). Clear the
input value before each send_keys and skip duplicate filePaths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 00:08:30 -04:00
GiteadandClaude Fable 5 efb85d0b92 feat: auto-confirm option for AI column claims (manual toggle + implied by Auto Claim)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 00:07:30 -04:00
ff 41bed21302 feat: send appointment confirmation SMS after AI-booked appointments
Voice-call bookings previously only spoke the confirmation during the
live call, leaving nothing for the patient afterward. Now every
successful booking (recall, reschedule, and new-patient) also sends a
standalone confirmation text, regardless of which channel the
conversation happened on.
2026-08-07 00:28:56 -04:00
ff 67e71a02e4 fix: AI recall follow-up message repeats "Great" and buries office hours
When the AI rejects a requested time in the recall booking flow, it reused
the same "Great, what time..." template used for a fresh ask, producing an
awkward double-greeting right after a rejection, and appended office hours
as a bare fragment instead of framing them as a sentence.
2026-08-07 00:07:10 -04:00
GiteadandClaude Fable 5 ff79cd1643 fix: earliest patient record wins when duplicates share a phone (inbound SMS/voice)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 23:11:55 -04:00
ffandClaude Sonnet 5 0cd095330a fix: AI recall-call flow, speech-to-text time parsing, and stale conversation state
- Reset conversation stage to a fresh start on every new voice call
  (recall and reminder alike), and on every hangup/timeout/goodbye,
  so an abandoned or completed call never leaves a patient stuck
  mid-flow for their next call or text.
- Add a staleness check to the SMS flow: after a long idle gap,
  check whether the patient's reply still reads as a continuation
  before resuming the stored stage, falling back to a friendly
  "it's been a while" re-greeting when unsure.
- Fix parseTime() to handle Twilio's speech-to-text output, which
  renders "pm"/"am" with periods and often drops the colon in a
  spoken time (e.g. "100 p.m." -> 1:00 PM) — this was silently
  failing and causing the AI to loop asking for a time it had
  already been given.
- Extend the voice Gather timeout so the AI doesn't hang up on a
  patient who just needs a few seconds to respond.
- Reword the recall-call opening line and rework the post-"yes"
  prompt to ask for day and time together.
- Fix rclone WebDAV server to serve only the backups folder instead
  of the entire backend app directory (was exposing .env and source).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 09:35:48 -04:00
ff 55ce52f276 fix: patient language field silently dropped by stale browser-side validation schema
packages/db/usedSchemas/browser.ts (the browser-resolved copy of the Patient
zod schema, kept separate from the Node copy since it can't import
Prisma-generated code) was missing several fields added to the real schema
over time — preferredLanguage, gender, insuranceProvider, insuranceId,
groupNumber, policyHolder, and the PLAN_NOT_ACCEPTED status. Since the schema
isn't strict, those fields were silently stripped from every patient
create/update in the browser with no validation error, so edits to them
never reached the server.

Also fixes the AI call greeting always playing in English regardless of the
patient's preferred language — the greeting text was a single hardcoded
string, unlike every later turn in the conversation which already branched
by language.
2026-08-05 21:40:53 -04:00
ffandClaude Sonnet 5 cef928be97 feat: add AI recall calling — books existing patients for routine cleanings
Adds a new recall conversation flow (recall-graph.ts) triggered from the
Patient Connection "AI Call" button: offers an existing patient a routine
exam & cleaning, classifies their yes/no reply, then books directly onto
the schedule (Column A, 30-minute slots, real conflict checking against
office hours and existing appointments) instead of only capturing a
preference for staff to follow up on.

Also adds a "Voice call" label in the message thread to distinguish call
transcripts from SMS, and updates the Call Templates settings UI with an
editable recall greeting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 23:13:09 -04:00
ffandClaude Sonnet 5 06dc63c53e feat: unify AI voice calls with SMS conversation rules, add Call Templates
AI phone calls now route through the same routePatientTurn() rule engine
as SMS (office-hours checks, slot-conflict checks, MassHealth eligibility,
staff escalation) instead of a freeform LLM chat, and speak in the
patient's preferred language (English/Spanish). Adds a separate "Call
Templates" settings section so spoken wording can be customized
independently from SMS wording.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 23:39:31 -04:00
ffandClaude Sonnet 5 089e94ba88 feat: add AI-driven phone calls to patient connection
Adds an "AI Call" option alongside Call/SMS/Chat that places an outbound
call where Lisa converses live with the patient via Twilio speech
gather + TTS, using the same conversational AI as chat. Includes a
separate, user-editable Call Template (Settings > AI Chat/Call Settings)
so the call greeting can be customized independently of SMS templates.

Also fixes the outbound-call webhook URL to always use the fixed public
Twilio hostname (CLOUDFLARE_HOST) instead of deriving it from the
triggering request, since staff-browser requests arrive over the
LAN-only hostname, which Twilio can never reach.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 20:14:09 -04:00
ff ed5a8af835 Merge branch 'main' of https://gitea.mydentalofficemanagement.com/Gitead/DentalManagementMH07 2026-07-31 10:49:52 -04:00
ffandClaude Sonnet 5 9885a3d35b fix: decouple Python venv setup from npm install postinstall
The three Python services (PatientDataExtractorService, PaymentOCRService,
SeleniumService) provisioned their venvs via postinstall, chained into
root's own postinstall. A failure in any one of them aborted the whole
npm install, which could leave unrelated Node deps (e.g. Backend's sharp)
uninstalled — silently breaking the app with no indication why.

Renamed each service's postinstall to an explicit "setup" script, added a
root "npm run setup:python" to run all three, and documented it as its
own step in the README instead of an automatic install-time side effect.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:49:06 -04:00
Gitead 75538126f2 docs: note server_names_hash_bucket_size fix for long local-<office> hostnames
Community Dentists of Lowell hit this during LAN HTTPS setup; documenting
it in Step 6 saves the next office from rediscovering it.
2026-07-31 10:11:36 -04:00
Gitead 55d798b45f docs: add Google Cloud Vision setup section to root README
Fresh-machine setup guide didn't cover the Payment OCR Service's Google
Vision credentials — add it as its own section (enable API, create
service-account key, install as google_credentials.json, verify).
2026-07-30 23:52:37 -04:00
Gitead 9efa8f6e0a docs+perf: document Google Vision key setup, consolidate OCR calls per screenshot
- README: step-by-step Google Cloud Vision API key creation and setup
  (enable API, create service-account key, place as google_credentials.json)
- ocrLocate: split into getOcrWords()/matchWordsForText() so a screenshot is
  OCR'd once and matched locally against multiple text targets, instead of a
  separate billed Vision API call per target (patient-row and Exam steps each
  cut from 2-3 calls down to 1)
2026-07-30 23:27:33 -04:00
Gitead 5cdd3452f2 fix: use Google Vision OCR instead of AI-vision estimates for Windows Type Agent clicks
Claude vision's self-reported text coordinates had a small but consistent bias,
causing the patient-row double-click to land above the name and the Exam-column
divider count to occasionally miscount and hard-fail. Swap patient-row, Exam,
and Save button targeting to exact OCR bounding boxes (Google Vision via the
existing PaymentOCRService) instead of AI-estimated ratios.
2026-07-30 23:14:02 -04:00
GiteadandClaude Sonnet 5 3f83794ac5 fix: add missing migration for auto-MH-check fields and drop dead lab_rx_template column
schema.prisma had autoMhCheckEnabled/DayOfWeek/Hour on User (added in
fc3e8c0e) with no corresponding migration, so migrate deploy on a fresh
DB left those columns missing and broke seeding. Also drops
lab_rx_template.doctorName, a column that existed only in the DB (added
by an old migration) but was never in schema.prisma or referenced by
any app code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 18:38:11 -04:00
Gitead 76bd99f7ff fix: Tufts SCO claim file attach — send_keys directly, skip button click
Clicking "Add a file" triggers input.click() which opens the OS-native
file picker that WebDriver can't control, causing send_keys on the
underlying input to fail with a message-less exception. The input is
already present in the DOM (display:none) so send_keys can target it
directly without the click.
2026-07-29 23:57:39 -04:00