app/lib/approved-drafts.ts provides three pure functions used by the browser client to manage approval state and produce the downloadable work packet. No server round-trips are involved — approval lives entirely in React session state (useState<Set<string>>), and the formatted download is assembled client-side from the TriageResponse already held in memory. Closing or refreshing the tab clears all approvals.
ApprovedDraft interface
Before the functions, the module defines the shape of a resolved approved item:
artifact is always defined on an ApprovedDraft — the approvedDrafts() filter guarantees this by excluding any item whose artifact is undefined.
queueItemIdentity(item: QueueItem): string
Returns a stable, human-readable string key that uniquely identifies a queue item within a triage session.
Returns
string — a key in the format "{claim_id}-{line_number}", e.g. "CLM-00123-2".
Usage This key is used as the value stored in the Set<string> that tracks which items have been approved in the UI. Passing it to approved.has() checks approval status; passing it to approved.add() marks an item approved.
approvedDrafts(items, approved): ApprovedDraft[]
Filters a queue to the items that are eligible for download: in an actionable lane, have a generated artifact, and have been explicitly approved by the user.
Returns
ApprovedDraft[] — a filtered, artifact-guaranteed array. Order mirrors the input items order (priority-ranked).
Inclusion criteria — all three conditions must hold for an item to be included:
item.prioritized.triage.laneis"appeal"or"corrected_claim".item.artifactis notundefined.queueItemIdentity(item)is present inapproved.
"human_review", "patient_bill", and "write_off" lanes are never included in the downloadable packet, regardless of approval state. Human review briefs are surfaced in the queue UI but are not exported through this path.
formatApprovedDrafts(drafts): string
Produces a plain-text download bundle from a list of approved drafts. The output is a single string intended to be written to a .txt file.
Returns
string — a newline-joined plain-text document.
Format The document opens with a fixed header block, then repeats a structured section for each draft:
=== {artifact.title} ===as the section heading- A claim context line:
Claim: {claim_id}; Patient: {patient_name}; Line: {line_number} - A service line context line:
Service date: {service_date}; Procedure: {procedure_code} - A blank line
artifact.content— the full draft body- A blank line
Citations:followed by each citation as- {source}: {field_path} = {value}- A trailing blank line before the next section
Download flow in the UI
TheTriageWorkspace component in app/components/triage-workspace.tsx wires these three functions into the download flow:
-
Approval state is held in
const [approvedLines, setApprovedLines] = useState<Set<string>>(() => new Set()). TheTriageQueuecomponent callsonApprove(item)when the user approves a line, which runssetApprovedLines((current) => new Set(current).add(queueItemIdentity(item))). -
Downloadable count is derived on every render:
const downloadableDrafts = approvedDrafts(result.items, approvedLines). The download button label shows the current count and isdisabledwhendownloadableDrafts.length === 0. -
downloadApprovedDrafts()is called when the button is clicked:
Blob from the formatted string, generates a temporary object URL, programmatically clicks a synthetic <a> element to trigger the browser’s save dialog, then immediately revokes the URL to release memory. The filename is always claimjumper-approved-drafts.txt.
- Session reset — when the user clicks “Choose another EOB”,
setApprovedLines(new Set())clears all approvals alongside the triage result. Approvals are never persisted tolocalStorageor any server.