AdvancedRx Salesforce · Project Plan · 2026-06-23
Apex builds the Rx bottle label as native ZPL, queues it as a
Print_Job__c routed to the filler's workstation, and a
company-owned local agent (the Advanced Rx Helper) polls
Salesforce and prints to the station's existing Zebra over USB.
No print cloud, no browser, no third-party vendor. Every California ship-to
gets a 16 CCR 1707.5-compliant format on
one universal 4×3 stock; the current label's PHI leaks are fixed for real.
Make Rx bottle-label printing California 16 CCR 1707.5 compliant for every order shipping to California, clean of the PHI leaks in today's path, and delivered with no print cloud, no browser, and no third-party vendor, on one universal label stock for every patient.
ZPL is a text command language, so the label is just a string built in Apex — the renderer is
Salesforce-native. The genuinely hard part was never drawing the
label; it is getting bytes to a USB printer on a filler's PC, which no cloud
(Salesforce, Azure, PrintNode, Bringg) can reach behind the pharmacy firewall without
something running on that PC. So we run our own: the
Advanced Rx Helper, a small local agent (its own repo) that
polls Salesforce for print jobs routed to its workstation and prints to the
station's Zebra over USB. The path is
SF → Print_Job__c queue → the station's agent (on your LAN)
→ the USB printer. PHI never leaves Salesforce + your own network. This label is
v1 of the agent; it grows into a platform one narrow, audited job type at a time (§12).
| Format | Applies to | Layout |
|---|---|---|
| Standard | Every non-CA ship-to (default) | To-be-redesigned (nicer than today), rebuilt as ZPL with the PHI leaks removed. |
| CA-compliant | Every CA ship-to (enforced) | 1707.5 cluster (4 items, order A→B→C→D, ≥12pt sans, ≥50% area, emphasis), directions on the container, full BPC 4076 lower zone, native ^BQ QR. |
One universal 4×3 stock for ALL patients. No stock swapping, no
dedicated CA printer, no media-enforcement problem — the same blank goes in every printer and
the server picks which ZPL format to render onto it (container-fit is being
bench-tested this week, in progress). Two independent routings, both server-side:
the format is chosen by ship-to state (CA → compliant);
the printer is chosen by workstation (the filler's current
station). Apex sets both; the agent never chooses. The native ^BQ QR removes the
external bwipjs-api.metafloor.com dependency, and the separate refill-QR sticker
is consolidated onto the main label.
Today's bottle label is a server-rendered Visualforce PDF iframed by an LWC, printed manually from the PDF viewer. The prior plan and earlier audit overstated both the print automation and the compliance posture. The corrected facts:
c:printBottleLabel iframes /apex/PrescriptionLabel (a
renderAs="pdf", @page 4in 2in page). window.print() is
commented out (printBottleLabel.js:114-116); the pink "Print this
page" button and the 5-second setTimeout both invoke that no-op. The operator
prints manually from the PDF viewer (cross-checked CORRECTIONS.md row 35).
| Defect | Evidence (file:line) | Rule broken |
|---|---|---|
| Patient name at 10pt | PrescriptionLabel.page:24 | 1707.5(a)(1) ≥12pt |
| Drug name 12pt → 11pt, height-clipped | PrescriptionLabelController.cls:91-95; page:92-93 | 1707.5(a)(1) ≥12pt |
| Sig (directions) at 9.5 / 9pt | PrescriptionLabelController.cls:97-101; page:95-96 | 1707.5(a)(1)(C); directions-on-container |
| Drug strength NEVER queried or rendered | SOQL cls:35-50 has no strength field | 1707.5(a)(1)(B); BPC 4076(a)(7) |
| Condition/purpose NEVER rendered | absent from controller + page | 1707.5(a)(1)(D); BPC 4076(a)(10) |
| Four items not clustered / not in required order | name header, drug+sig body, no purpose/strength | 1707.5(a)(1) cluster ≥50% in order A→D |
| No emphasis treatment | no bold/color/blank-space set-off | 1707.5(a)(2) emphasis |
printBottleLabel.js:30-44 concatenates &patientName= + &pharmacistName= (plus rx#/qty/lot/fillId) into the iframe src with no encodeURIComponent → browser history + any proxy/server URL log.
printBottleLabel.js:118-120 logs patient, pharmacist, and prescriber names to the browser console.
Patient_Fill_Id__c to an external QR hostPrescriptionLabelController.cls:52 sends the fill id to bwipjs-api.metafloor.com on every render (page:42). Also a callout without a Named Credential.
BarQR getters (js:47-56) are unreferenced — the template (html:4) binds only src={prescriptionFrame}. And fillId is overloaded: an Rx record Id in the controller, but the business Patient_Fill_Id__c in a sibling flow variable. New code uses rxId and patientFillId as distinct values.
Bottle-label printing is not wired to any print-automation rail today. The
new design is a company-owned local agent (§3, §4-D1), not the
shipping rail and not a third-party print cloud. The shipping rail's only AdvancedRx call
(ShipmentPrintLabelInvocable.cls) is shipment-scoped, reads its prefId
off a zkmulti__MCShipment__c, and returns void (no status) — bending
it to non-shipment bottle labels meant an unproven contract + a cloud hop.
The constraint that drove the whole design: a cloud cannot reach a USB printer
behind the pharmacy firewall — something must run on the filler's PC. Every option
(Browser Print, QZ Tray, PrintNode, our agent) is just a different "thing on the PC"; we choose
to own it (D1).
Print_Job__c queue + the agent
The label never leaves Salesforce + your own network:
SF → Print_Job__c → the station's agent (on your LAN) → the
USB printer. No print cloud, no browser, no third-party SaaS. Printing is
asynchronous: the fill flow creates the job and moves on; the agent polls
every few seconds, prints within seconds, and reports status back onto the job.
SALESFORCE (advancedrx-salesforce) FILLER PC (Station 3)
────────────────────────────────────────────────────────── ──────────────────────────────
Filler picks station once/shift (2h expiry):
Choose_Your_Workstation → User.Current_Workstation__c = Station 3
Fill flow (Loop_in_an_order_Execute_Event / Generate_Rx_Label)
print step = Apex action that CREATES a record
│
▼
BuildBottleLabel (Apex, with sharing, WITH USER_MODE)
1. SOQL Rx by rxId: name, drug+STRENGTH, sig, purpose, qty,
BUD, lot, prescriber, dates, ship-to State, patientFillId
2. format = (state=='CA') ? CA : STANDARD ── server-enforced (D4)
3. zpl = ZplBottleLabelBuilder.build(format, fields) (native ^BQ QR)
4. INSERT Print_Job__c{ ZPL__c, Workstation__c, Status__c='Queued',
Rx__c, Patient_Fill_Id__c } (D8)
│ (fault connector on the INSERT → Error_Log__c)
▼
┌────────────────────┐ poll: "Queued jobs for Station 3?" ┌─────────────────────────┐
│ Print_Job__c queue │◀────────────────────────────────────────│ Advanced Rx Helper agent │
│ (Workstation-keyed │────────── job (ZPL) ───────────────────▶│ • polls SF (its station)│
│ claim / lease) │ writeback: Status__c='Printed'|'Error' │ • raw ZPL → USB printer │
└────────────────────┘ │ • writes status back │
▲ └───────────┬─────────────┘
│ Error / stuck Queued → alert + manual browser-PDF interim │ USB
│ ▼
┌────────────────────────┐ ╔═══════════════════════╗
│ INTERIM / EMERGENCY: │ ║ Zebra (existing GX430t)║
│ remediated browser-PDF │ (PHI-clean; Rx Id only) — manual ║ 4×3 stock, STD or CA ║
│ c:printBottleLabel │ ║ ZPL format ║
└────────────────────────┘ ╚═══════════════════════╝
ZplBottleLabelBuilderPure Apex string builder; STANDARD + CA formats; native ^BQ QR. No SOQL/DML/callout — deterministic string in / ZPL out, trivially unit-testable.
BuildBottleLabelwith sharing. SOQL the Rx by rxId under WITH USER_MODE; pick format by ship-to state (D4); build ZPL; INSERT a Print_Job__c routed to the filler's Current_Workstation__c (D8). Invoked from the fill flow; fault connector on the insert → Error_Log__c (D5).
Print_Job__c (the queue)ZPL__c (Long Text — PHI; purge/redact after print), Workstation__c (frozen at create), Status__c, Claimed_By__c / Claimed_At__c / Attempt__c (claim/lease — D5), Rx__c, Patient_Fill_Id__c, Error__c, Printed_At__c. The agent's inbox + an audit trail.
Agent_Registration__cOne row per installed agent → its Workstation__c. SF derives a job's eligible station from the authenticated agent, never from a station Id the agent supplies (D8).
advancedrx-helper — a small local service per filler PC. Polls SF for Queued jobs for its station, sends raw ZPL to the local printer over USB, writes Status__c back. v1 = exactly one job type, print_zpl. A narrow job-runner, not a remote shell (D9).
Reuse Workstation__c + the 2h-expiry pick-your-station UX. Build a clean picker that writes only our binding — do not reuse Choose_Your_Printer_Screen_Flow as-is (it writes/deletes zkmulti__MCUser_Printer__c + validates via Bringg_Printer_ID__c). Current_Workstation__c is non-unique Text(150) — resolve-and-freeze a real Workstation__c Id (D8).
c:printBottleLabel + VFThe three PHI leaks fixed as real work; kept as the PHI-clean browser-PDF path used pre-agent and if the agent is down.
The agent sends raw ZPL over USB; the GX430t prints it fine regardless of Zebra's end-of-sale status (the EOL concern only ever mattered for Browser Print). No fleet purchase. Replace with the ZD621t only as units age out.
zkmulti/Bringg/PrintNode/Browser Print/QZ Tray/AzureEvaluated; each kept as an "alternative" only. The company-owned agent replaces them all — see §4-D1. The label content (Apex ZPL) is identical regardless of delivery.
There is no external callout in the print path and no print
cloud. The native ^BQ QR removes the only outbound HTTP the current label
makes. If a future archival need arises, write a ContentVersion directly in Apex —
no Named Credential, no external service.
advancedrx-helper, its own repo) polls Salesforce for Print_Job__c records routed to its workstation and prints the ZPL to the local Zebra over USB. No print cloud, no browser, no third-party vendor.zkmulti/Bringg: shipment-scoped, void return, unproven contract. PrintNode: a third-party cloud → a HIPAA BAA gate. Azure: a cloud that also can't reach the USB printer — strictly more work.The unavoidable constraint: a cloud cannot reach a USB printer behind the pharmacy firewall, so something must run on the filler's PC. Our agent keeps PHI on SF + the LAN (no print-vendor BAA), removes the browser/CSP surface entirely (server-to-agent poll, not browser-to-localhost), works with the existing GX430t's, and gives us a platform (D9). The durable queue is Print_Job__c; the agent polls on backoff + jitter (≈30s floor → 120s cap, dropping to a 5-min heartbeat once the nudge is active) under a /limits budget that hard-stops polling at 95% of the org's daily API allocation, optionally woken by a Platform Event "nudge" — the nudge is the wake signal, never the durable store. QZ Tray / PrintNode remain drop-in delivery swaps if owning fleet software ever proves untenable.
ZplBottleLabelBuilder builds the ZPL for both formats. The agent never builds labels — it only relays a finished ZPL string to the printer.Label content + compliance live in one versioned, testable place where the data is. Font sizing is auditable in dots: at 300 dpi, font height in dots = pt × (300/72), so 12pt = 50 dots (^A0N,50,50) — the ≥12pt floor is a reviewable number. ZPL injection must be neutralized: ^FD excludes the command prefixes ^ and ~, so the builder hex-encodes every field value with ^FH (or strips/escapes) before insertion — unit-tested with a sig containing ^ and ~.
One blank dissolves the stock-mismatch problem — there is no wrong media to load. The law specifies ≥50% area + ≥12pt, not a physical size; 4×3 holds the CA cluster at ≥50% plus the full BPC 4076 lower zone. Container-fit is being bench-tested this week (in progress). Fixed-stock overflow rule: the label can't grow, so a long sig wraps within a fixed max-line budget; a sig that still overflows prints a continuation/auxiliary 4×3 label rather than shrinking below 12pt or dropping a required element. Counsel must confirm a split cluster still satisfies 1707.5 (OQ-1).
BuildBottleLabel selects the format from Order__r.Shipping_Address__r.State, with a hard CA guard as the last statement touching format — a CA ship-to can never be downgraded. The choice is stamped onto the Print_Job__c before the ZPL is built; nothing downstream can change it.1707.5 is mandatory for CA dispensing; a silent downgrade is a compliance failure with patient-safety stakes. Encoding the choice in Apex makes "CA always gets the compliant format" a property of the system, and because both formats print on the same universal stock, no media-mismatch path can undo it.
Print_Job__cPrint_Job__c (Queued) and continues. The agent processes it through a claim/lease lifecycle: an atomic locked Queued→Printing transition (FOR UPDATE, stamps Claimed_By__c / Claimed_At__c / Attempt__c); print → writeback Printed/Error; a scheduled sweeper re-queues lease-timed-out jobs once; Attempt__c caps retries. At-least-once with an explicit reprint control — duplicates are caught by the pharmacist verification (D7).Error contract: failure is signaled by the Apex action throwing (incl. internal DML failure); the flow's fault connector on the action routes to Error_Log__c. There is no LWC→Apex print call to mis-wire. The agent's print outcome lives on Print_Job__c (better than the dropped rail's void return); stuck/aged jobs raise an alert; the remediated browser-PDF path is the manual fallback. Because pharmacist verification backstops the physical label, at-least-once + reprint is the right, simple target.
Owning the agent means we drive the printer directly; we don't depend on a vendor's printer-support matrix. Keeping the GX430t's removes the ~$1.2k-per-station cost. Media: wax-resin ribbon on coated 4×3 (move to resin + synthetic for max durability); thermal transfer keeps labels legible for the medication's life — qualify by test (Phase 0).
A post-print scan would duplicate a control the pharmacist already performs — the human verification already compares the physical label to the Rx, which is the meaningful compliance check (and the backstop that makes async printing safe, D5). Consolidating the refill QR removes a second sticker and a second print step. The exact refill-QR encoding is an open input (OQ-3).
Print_Job__c carries a target Workstation__c Lookup, resolved and frozen at job creation. The agent only ever receives jobs for the station Salesforce binds to its authenticated identity — it never passes a station Id the server trusts. 5 stations = 5 registered agents, each served only its own jobs.Current_Workstation__c text, a shared filter, or reusing Choose_Your_Printer_Screen_Flow as-is (its zkmulti side effects contradict "no zkmulti").User.Current_Workstation__c is Text(150) holding a non-unique workstation Name, so BuildBottleLabel must resolve it to a specific Workstation__c Id (with an "ambiguous → error" rule) — or add a real User → Workstation__c lookup. Per-agent identity means each agent authenticates as its own principal (a JWT/cert integration identity — the credential); Agent_Registration__c is the station binding, not the credential. So a compromised agent cannot name another station's jobs — SF derives the lane from the auth context. The printer is a property of the physical station, not the person.
print_zpl. The reusable platform is the framework (poll, auth, job lifecycle, status writeback, deploy, auto-update). Future capabilities are new, individually security-reviewed job types.A company-owned, SF-connected workstation agent is a genuine platform — each new capability gets cheaper once it's trusted. Two guardrails keep it safe: (1) the platform emerges feature-by-feature, and compliance stays decoupled (the CA label is content in Apex; it ships via the manual PDF path even before the agent, so the platform build never blocks the deadline); (2) no arbitrary local execution — a cloud-driven agent on a PHI workstation that could take arbitrary actions is an RCE surface, so it only ever runs explicitly-coded, reviewed job types.
Every requirement is quoted verbatim from a primary or authoritative source. The citations are load-bearing — paraphrasing the law loosely is exactly what the review caught.
“Each of the following items, and only these four items, shall be clustered into one area of the label that comprises at least 50 percent of the label. Each item shall be printed in at least a 12-point sans serif typeface, and listed in the following order: (A) Name of the patient (B) Name of the drug and strength of the drug … (C) The directions for the use of the drug. (D) The condition or purpose for which the drug was prescribed if the condition or purpose is indicated on the prescription.” — Cornell LII / CA Board Order of Adoption
“For added emphasis, the label shall also highlight in bold typeface or color, or use blank space to set off the items listed in subdivision (a)(1).” — Cornell LII. On a monochrome printer we use the permitted bold typeface + blank space (color is unavailable).
“The remaining required elements for the label specified in section 4076 of the Business and Professions Code … shall be printed so as not to interfere with the legibility or emphasis of the primary elements … These additional elements may appear in any style, font, and size typeface.” — Cornell LII.
BPC 4076(a)(1)–(11) (FindLaw): (1) manufacturer trade name OR generic + manufacturer; (2) directions for use; (3) patient name; (4) prescriber name; (5) date of issue; (6) pharmacy name + address + Rx number; (7) strength of the drug; (8) quantity dispensed; (9) expiration date; (10) condition/purpose if indicated; (11) physical description (outpatient only) — with an exemption for medications lacking a description in a commercially available database (the citable basis to omit it for compounded preparations; confirm with PIC/counsel).
16 CCR 1707.5(b): “…translation of the directions for use … into at least five languages other than English.” The regulatory floor is five, but the Board currently publishes SIX standardized-direction language sets — Chinese, Farsi, Korean, Russian, Spanish, Vietnamese — covering 15 standardized directions. The prior plan's "five … not six" was stale. Drive the language set from data/config, never a literal. Translated directions are on patient request and may go on a supplemental document; when on the container/label, the English version must also appear (BPC 4076.6 — re-verify against leginfo before build; a 2024 amendment, AB 1902, is in the lineage).
^BQN,2,5 QR (Patient_Fill_Id__c) + consolidated refill QR ·
USP-795 BUD/lot + "compounded by the pharmacy" (16 CCR 1735.4)
Compounding overlay: 16 CCR 1735.4(b) requires the 4076 + 1707.5 info on top of the compound elements — flag to PIC/counsel for the CA cohort (OQ-1).
Cluster ≥50% of label AREA: the four ^FO/^FB
blocks occupy ≥50% of the printable area — the builder asserts cluster
width × height, not dot-height alone (height-only is wrong if the
cluster isn't full-width). Native QR: ^BQN,2,5 with
^FDHA,<patientFillId>^FS — H error-correction, automatic mode,
magnification 5 (reliable at 300 dpi), no external service. The
size-independent defects (sub-12pt name/drug/sig, missing strength, missing purpose, no
emphasis, no cluster) are fixed in the renderer for the CA format. Compliance sign-off
(PIC + counsel) is a Phase 0 gate, not an engineering deliverable (OQ-1).
Each phase is a shippable increment. Compliance is decoupled from the agent (D9): the CA label content can ship via the manual browser-PDF path before the agent exists, so the platform build never blocks the deadline. The agent is the automation on top.
ZplBottleLabelBuilder + a CA 4×3 renderrenderAs=pdf @page 4in 3in CA layout in the remediated VF pageWITH USER_MODEconsole.log (js:118-120)cls:52, page:42) with in-org BarQR/inline; delete dead BarQR getters (js:47-56)console.log, or external calloutPrint_Job__c queue (POC: one station)Print_Job__c object; BuildBottleLabel action (build ZPL + insert the job routed to Current_Workstation__c)advancedrx-helper repo (net-new)Queued jobs, send raw ZPL to the local GX430t over USB, write Status__c backprint_zpl job type (D9); decide + document the deploy/auto-update mechanismWorkstation__c, run a real fill^BQ CA label within seconds with no click, and Status__c flips to Printed; a forced failure leaves the job Queued/Error and the manual fallback still works.BuildBottleLabel into Loop_in_an_order_Execute_Event + Generate_Rx_Label — replace the manual screen with the action + a "sent to <station>" confirmation; fault connector → Error_Log__cWorkstation__c on all 5 fill stationsError jobsprint_bottle_label_flow (Draft) stays as-is
The bottle label is platform phase 1 — it stands up the agent + the
Print_Job__c/claim framework with a single job type (print_zpl).
Platform phase 2 is the backlog below: each item is a
new, individually security-reviewed job type on the same framework (D9 —
never a generic "run a command"). Build one at a time, compliance-decoupled, after the label ships.
print_zpl framework)| Job type | Grounds in | Notes |
|---|---|---|
PRINT_PACKING_LIST | printPackingListv2 (browser print today) | Top quick win — same shape as the label; kills browser-print fragility on the pack line |
PRINT_RECEIPT | printReceipt* + ControllerOrderSummary | Natural second print type |
PRINT_CLAIM_FORM | printClaimFormListTestFlow | PHI-heavy; a narrow print job fits |
PRINT_SHIPPING_LABEL_LOCAL | ShipmentPrintLabelInvocable | Closes the shipping loop locally (respect Zenkraft behavior) |
PRINT_AUX_WARNING_LABELS | bottle-label warning fields | Cheap once the ZPL path exists |
LOCAL_BARCODE_RENDER | the bwip-js/metafloor external QR | Security hardening — render barcodes locally, killing external-identifier egress across all labels |
| Job type | Grounds in | Notes |
|---|---|---|
CAPTURE_VERIFICATION_SCAN | barcodeInputValidator / final-verification scans | First capture primitive; only while an expected scan job is open — no keyboard injection |
VERIFY_SHIPPING_TRACKING_SCAN + PACKAGE_TYPE_SCAN | Prepare_Order_for_Shipping scan screens | Safety/status loop after local print |
WORKSTATION_PRINTER_HEALTHCHECK | Workstation__c + 2h printer-assignment expiry | Ops value; no PHI |
ORDER_READY_DESKTOP_ALERT | shippingView / filler queue controllers | OS notification; PHI-minimal (order id, not patient name) |
| Job type | Grounds in | Notes |
|---|---|---|
SCALE_CAPTURE_COMPOUND_WEIGHT | Compound__c / Lot__c (BUD, ingredient qty) | High patient-safety value; needs a real USB scale + SOP tolerances |
SCAN_TO_RX_IMAGE | Rx_Image__c doc fields; Azure intake | Rescan paper/fax to SF; whitelist file types — never arbitrary upload |
LABEL_BARCODE_QA | fill-id QR + final-verification scans | Decode-and-verify the printed QR (pass/fail), not photo retention |
PAYMENT_TERMINAL_JOB | Capture_Payment / PaymentCaptureAction | PCI-sensitive — token/status only, never raw PAN in the agent or SF |
|
No generic "copy data into another app," clipboard automation, or "run this command" — that is the unreviewable remote-control surface D9 forbids. Softphone/fax bridges need real workflow confirmation first. SFMC/marketing tasks aren't workstation-local — they stay server/SF-side.
Top 3 after the label: PRINT_PACKING_LIST (quick win, same shape) → CAPTURE_VERIFICATION_SCAN (first capture primitive) → PRINT_SHIPPING_LABEL_LOCAL + VERIFY_SHIPPING_TRACKING_SCAN (closes the shipping loop). Pair LOCAL_BARCODE_RENDER with the label work as security hardening.
|
| Risk | Sev | Mitigation |
|---|---|---|
| We now own fleet software forever — the agent must be deployed, code-signed, auto-updated, monitored, secured, supported on every filler PC; bus-factor | HIGH — the real cost | Keep v1 tiny + boring (one job type, a poll loop); document a deploy/auto-update/runbook in advancedrx-helper; treat it as a maintained product. The narrow job-runner (D9) keeps the surface small. |
| Agent down / offline / printer jam → label doesn't print | MED | Async status on Print_Job__c (stuck Queued / Error alerts); the pharmacist verification step catches a missing label (D7); the manual browser-PDF fallback is always available. |
| Agent security — a cloud-driven workstation agent could become an RCE surface | HIGH | No arbitrary execution — only explicitly-coded, reviewed job types (D9); least-privilege SF integration user; signed builds; locked-down service account. |
| CA patient silently downgraded to the non-compliant format | HIGH | Server-enforced routing with a hard CA guard as the last statement touching format (D4); stamped on the job before the agent sees it; unit test asserts CA can't produce STANDARD. |
| Compliance miss (cluster <50%, sub-12pt, wrong order, no emphasis, off-container directions, wrong language list) | HIGH | §5 verbatim rules; the builder asserts dot-height/cluster-area; PIC + counsel sign-off is a hard Phase 0/3 gate; language set is data-driven (6 languages, not a literal). |
| Existing PHI leaks persist on the fallback | HIGH | Phase 1 remediates all three as real work and ships first; exit criterion verified against the rendered URL + network panel. |
| Long sig overflow on the fixed 4×3 | MED | Fixed max-line budget + a continuation/auxiliary 4×3 label (never sub-12pt, never drop an element — D3); longest production sigs tested in Phase 3. |
| ZPL geometry / unscannable QR | MED | Labelary preview; native ^BQ at mag 5; scannable QR is a Phase 2 exit criterion; ISO Grade-B verification in Phase 3. |
| Duplicate / lost-status prints (no claim/lease) | HIGH | Atomic claim + lease + Attempt__c cap + sweeper for stuck Printing (D5); at-least-once with explicit reprint; pharmacist verification (D7). |
Print_Job__c.ZPL__c = a new plaintext PHI store (no Shield) | HIGH | Purge/redact ZPL__c after Printed; FLS-lock the field; explicit retention window (OQ-5); the agent doesn't persist bodies. |
| ZPL command injection via patient/sig text | HIGH | ^FH hex-encode / escape all field data (^FD excludes ^/~); unit-test a sig with ^/~ (D2). |
| Polling burns the org-aggregate API budget | MED | Backoff + jitter, /limits monitoring, an explicit budget; a Platform Event "nudge" wakes the agent so idle polling is rare (D1). |
| Agent spoofs another station | MED | Per-agent credential + Agent_Registration__c; SF derives the station server-side; the agent never names a station (D8). |
| Platform scope-creep delays the label | MED | Compliance is decoupled (ships via the manual path, Phase 1); the agent stays one job type until the label is done (D9). |
| # | Question | Owner | Blocks |
|---|---|---|---|
| OQ-1 | PIC + counsel sign-off on the CA label: 1707.5 layout, USP-795 / 16 CCR 1735.4 compound elements, BPC 4076(a)(11) exemption, translated-directions workflow (6 languages, supplemental document), USP <17> + the state board's adopted rules. | Counsel + PIC | Phases 0/1/3, go-live |
| OQ-2 | Live FieldDefinition SOQL: exact API names of the drug strength + condition/purpose fields on HealthCloudGA__EhrMedicationPrescription__c (managed; EhrMedicationPrescription.md is past TTL). | SF schema / Kyle | Phases 1, 3 |
| OQ-3 | What does the refill QR encode? The separate refill-QR sticker is being consolidated onto the main label — confirm the exact payload / URL. | Kyle / pharmacy ops | Phase 3 |
| OQ-4 | Agent build decisions (advancedrx-helper): language/runtime, deploy + auto-update across PCs, per-agent SF auth (JWT/cert) + the Agent_Registration__c binding, the claim/lease endpoint + lease window, wake-vs-poll-budget tuning. | Kyle / eng | Phase 2 |
| OQ-5 | Print_Job__c.ZPL__c retention/redaction policy — purge-after-print timing, retained audit metadata, FLS, retention window (Shield not licensed, so the ZPL is plaintext PHI at rest). | Kyle / PIC | Phase 2 |
A prior round of this plan was reviewed; all 11 findings are folded into the current design. The headline dispositions:
| # | Finding | Disposition |
|---|---|---|
| 1 | Fallback preserves PHI leaks | FIXED §2 documents all three with file:line; Phase 1 remediates them as real work; §7 of the plan states it fixes existing exposure. |
| 2 | Compliance fails 1707.5 (directions on container, emphasis, BPC 4076, non-interference) | FIXED §5 quotes (a)(1)/(a)(2)/(a)(3) + full BPC 4076 verbatim; directions are an in-cluster container item (D3). |
| 3 | Current-label audit undercounts noncompliance | FIXED §2 table: name 10pt, drug 11pt, sig 9/9.5pt, no strength, no purpose, not clustered, no emphasis — each with file:line. |
| 4 | zkmulti reuse not proven (shipment-scoped only) | MOOTED The zkmulti/Bringg/PrintNode rail is dropped (D1). Delivery is the company-owned agent to a USB printer. |
| 5 | Automatic fallback overpromised; void-return signal | MOOTED The void rail is dropped. Failure is observable on Print_Job__c.Status__c; stuck/Error jobs alert; pharmacist verification + manual fallback backstop it (D5/D7). |
| 6 | Error contract inconsistent (fault AND boolean) | FIXED D5 is one model: the flow inserts a Print_Job__c with a fault connector → Error_Log__c; the agent reports status. No LWC→Apex print call to mis-wire. |
| 7 | fillId overloaded (Rx Id vs Patient_Fill_Id__c) | FIXED New code uses rxId (record Id) and patientFillId (QR payload) as distinct values. |
| 8 | Azure claims unverifiable in this repo | MOOTED Azure is dropped (D1). |
| 9 | "2-click pink button" wrong (window.print() commented) | FIXED §2 states it (js:114-116) + cross-checks CORRECTIONS.md row 35. |
| 10 | BarQR claim unsupported (getters unreferenced) | FIXED §2 notes the dead getters; Phase 1 deletes them. |
| 11 | AGENTS.md path / stale Rx doc | ACCEPTED Flagged for cheap cleanup; OQ-2 verifies field names via live FieldDefinition SOQL rather than the stale doc. |
Subsequent rounds: the @InvocableMethod/Flow-fault conflation and the
fixed-stock-vs-"grow-the-label" contradiction are resolved by the async
Print_Job__c model (D5, no LWC print path) and the fixed-stock overflow rule
(D3). The ZD621t-vs-ZD421t correction and the Browser-Print fragility findings are moot now
that the agent — not Browser Print — is the delivery path; the GX430t's are
reused (D6).