Source-grounded check of which services need an ORIGINAL ink signature (plotter target) vs e-sign/typed. Verified firsthand against the official forms: - Confirmed wet-ink: the 5 CMS Medicare/NPI paper filings only (855I/B/O + 10114), which are exactly the no-login Standard-path filings the plotter serves. - CLIA CMS-116 does NOT require original ink — the form explicitly permits 'SIGN IN INK OR USE A SECURE ELECTRONIC SIGNATURE', so our digital stamp suffices; plotter optional for CLIA. - DEA registration/renewal is online-only (Form 224 unavailable in PDF), e-certified, no wet ink. - State CSR / state Medicaid are the only open items: paper in many states but original-ink-vs-e-sign is state-specific; verify per state. - All FCC/telecom/DOT/BOC-3/CRTC/PUC filings are electronic (e-sign fine). Added the verified matrix to state-healthcare-compliance-opportunities.md, saved docs/CMS-116 Form.pdf, and the plotter plan.
8.4 KiB
Plotter Plan — ink-signature station for no-login CMS filings
Goal: turn the (already-built) ink-signature pipeline into a reliable physical station that draws an original wet-ink signature on each printed CMS form so the Standard (no-login) filing path can be mailed and accepted. The CR-10 V2 is the motion system; this plan covers the retrofit, calibration, the software/hardware integration that remains, validation, and the operational runbook.
Status legend: ✅ done · 🔲 to do · ⏳ blocked on hardware
0. What already exists (software, hardware-independent)
- ✅
signature_vectorcapture end-to-end (migration 090, signing page, API). - ✅
ink_signature_plotter.py— fit-to-box, PDF-pt → bed-mm, G-code (Z pen or M280 servo/BLTouch), SVG preview,render_signature_on_pdfdigital twin, gated serial sender. - ✅
ink_signature_cli.py— load record → gcode + preview,--test-box,--plot. - ✅
test_ink_signature.py30/30; signature anchor verified inside the CMS-10114 Section 4A cell. - ✅
docs/ink-signature-plotter.md— retrofit + interpretive-risk writeup.
The remaining work is hardware + a few integration/safety pieces.
1. Hardware retrofit (CR-10 V2)
- 🔲 Pen holder. Print a spring-loaded CR-10/Ender X-carriage pen holder
(Printables/Thingiverse). Spring = even contact pressure. Print it before
converting (you still have the hotend).
- BOM: printed bracket, 1 compression spring (~8–12mm), 2–3× M3 screws, a smooth gel/rollerball pen (wet ink, hand-written look).
- 🔲 Mount + cable management. Attach beside the hotend; make sure the pen tip is the lowest point and the bed can still home.
- 🔲 Pen-up/down method — pick one:
- Z mode (default, simplest): pen fixed; G-code lifts/drops Z. Spring forgives over-press. No firmware change.
- Servo/BLTouch mode (optional): actuate pen with a servo or repurpose the
BLTouch;
--servo-penemitsM280. Faster, no Z lash, more build effort. - Decision: start Z mode; revisit servo only if Z lift is too slow.
- 🔲 Paper jig. Tape an L-shaped corner stop to the bed (front-left) so a
US-Letter sheet always sits at the same
(jig_x_mm, jig_y_mm). This is the single most important accuracy factor. - 🔲 Pen-touch Z reference. Either set
pen_down_mmby hand, or use the BLTouch to probe a fixed point on the jig for a repeatable touch height.
Reversibility: nothing here is permanent; swap the hotend back to print anytime.
2. First-light calibration (uses --test-box)
- 🔲 Connect: CR-10 enumerates as CH340
/dev/ttyUSB0@ 115200. Confirm withls -l /dev/ttyUSB*and a manualG28via pronterface/printrun. - 🔲 Dry-run inspect:
ink_signature_cli.py --order <X> --doc cms10114 --test-box→ review the_testbox.gcode+_preview.svg. - 🔲 Plot the box on a blank sheet in the jig:
--test-box --plot --home --port /dev/ttyUSB0. - 🔲 Print a real (unsigned) CMS-10114 cert page, lay it in the jig, plot the test box again, and confirm the rectangle frames the Section 4A signing cell.
- 🔲 Tune
--jig-x/--jig-y(position) and--pen-down(ink without digging in) until the box lands on the line. Record the final values as the station defaults. - 🔲 Bake the calibrated defaults into
PlotterConfig(or a smallplotter_config.jsonthe CLI/worker reads), so operators don't pass flags.
Acceptance: the plotted rectangle sits within ~1mm of the cell, repeatably, across 3 reloads of the sheet.
3. Software/integration still to build
- 🔲 Persisted station config.
scripts/workers/services/plotter_config.json(jig offset, pen heights, feeds, port) loaded byPlotterConfig.from_file(). Keeps calibration out of code + flags. - 🔲 Anchor scaling parity test. A test that plots/previews against a page
whose
page_w/page_hdiffer from the authored size, asserting the strokes still land in the cell (the stamper already scales; add the matching ink test). - 🔲 Signature-quality guard. Reject/flag vectors that are too few points,
near-empty bbox, or a single dot (someone tapped instead of signing) before
they reach the pen. Add to
ink_signature_plotter+ a unit test. - 🔲 855 anchors for ink.
cms855_pdf_filleronly has the 855I signature rect today; add 855B/O/A signature rects so org filings can also be plotted (currently human-placed). Mirror the CMS-10114 anchor approach. - 🔲 Batch integration. Teach
daily_paper_batch.pyto, for each signed filing in a batch: (a) print the filled form, (b) call the plotter to ink the signature, (c) include it in the per-agency envelope. Sequencing + a per-sheet "plotted ✓" status column so a crash doesn't double-sign or skip. - 🔲 Plot audit trail. Store the emitted G-code hash + a post-plot photo (if a camera is added) on the esign/batch record for traceability.
- 🔲 Operator safety.
--plotalready gated; add a hard env guard (INK_PLOTTER_ENABLED=1) so a stray--ploton a dev box can't move a machine, and a--confirmprompt for live runs.
4. Validation (build verifiable criteria)
- 🔲 Geometry (done, extend): keep
test_ink_signature.pygreen; add the page-scale parity + quality-guard tests above. - 🔲 Physical accuracy: a calibration card — plot a 10mm grid + the test box, measure with calipers, assert ≤1mm error. Document the measured numbers.
- 🔲 Legibility: plot 5 real captured signatures, scan, eyeball that each is
recognizably the signer's mark (not mangled by resampling). Tune
min_segment_mm/ feeds if jagged. - 🔲 Ink originality sanity: confirm under magnification the line is continuous wet ink (not dotty), since "deemed not original" is the failure mode we're guarding against.
- 🔲 End-to-end dry run: one fake order → form printed → signature plotted → batched → addressed envelope, with nothing actually mailed.
5. Go-live policy (interpretive risk)
CMS does not explicitly bless/ban autopen for the 855/10114. Therefore:
- 🔲 Two paths, choose per filing:
- Plotter (fast): default for low-stakes changes (e.g. address/contact NPPES updates) where a re-file is cheap.
- True wet-signature mail-out (safe): a printed packet to the provider (cover sheet with a signing arrow + return envelope) for high-stakes filings (enrollment, reactivation) until acceptance is proven.
- 🔲 Pilot: run a handful of real plotter-signed filings, track acceptance vs rejection at the MAC/Enumerator. If clean, widen the plotter default.
- 🔲 Kill switch: if any rejection cites the signature, fall back to wet-sig mail-out for that service and log it.
Note: never expose any of this (plotter, paper, ink, MAC, Enumerator) in client-facing copy — same rule as the rest of the no-login model.
6. Operational runbook (once calibrated)
# Daily, per signed Standard filing (or via daily_paper_batch once wired):
1. Print the filled, unsigned form (form printer, plain paper).
2. Lay the cert page in the jig on the CR-10.
3. Plot the signature:
INK_PLOTTER_ENABLED=1 python scripts/workers/ink_signature_cli.py \
--order CO-XXXX --doc cms10114 --plot --home --confirm
4. Verify the ink landed on the line; reassemble the form pages.
5. Hand to the daily batch -> per-agency Priority Mail envelope.
7. Sequence (what to do, in order)
- Print + mount the spring pen holder; tape the jig. (§1)
- Calibrate with
--test-box; record jig/pen values. (§2) - Add persisted
plotter_config.json+ load it. (§3.1) - Add quality guard + page-scale parity tests. (§3.2–3.3)
- Physical accuracy + legibility validation. (§4)
- Wire into
daily_paper_batchwith per-sheet plotted status. (§3.5) - Add env/confirm safety guards. (§3.7)
- Pilot live filings under the go-live policy; widen or fall back. (§5)
- (Later) 855B/O/A anchors so org filings can be plotted too. (§3.4)
Dependencies / risks
- ⏳ Everything in §1–2 is blocked on the pen holder + jig (cheap, fast).
- Risk: jig drift → signature off the line. Mitigate with a fixed, screwed-down
jig and a per-session
--test-boxcheck. - Risk: pen dry-out / skipping → illegible mark. Mitigate with gel/rollerball + legibility validation + a "prime the pen" pre-stroke.
- Risk: CMS deems plotted signature "not original." Mitigate with the two-path go-live policy + pilot.