new-site/docs/plans/plotter-plan.md
justin 0b06043437 healthcare: verify wet-signature requirements across all services
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.
2026-06-07 02:40:47 -05:00

8.4 KiB
Raw Blame History

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_vector capture 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_pdf digital twin, gated serial sender.
  • ink_signature_cli.py — load record → gcode + preview, --test-box, --plot.
  • test_ink_signature.py 30/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)

  1. 🔲 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 (~812mm), 23× M3 screws, a smooth gel/rollerball pen (wet ink, hand-written look).
  2. 🔲 Mount + cable management. Attach beside the hotend; make sure the pen tip is the lowest point and the bed can still home.
  3. 🔲 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-pen emits M280. Faster, no Z lash, more build effort.
    • Decision: start Z mode; revisit servo only if Z lift is too slow.
  4. 🔲 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.
  5. 🔲 Pen-touch Z reference. Either set pen_down_mm by 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)

  1. 🔲 Connect: CR-10 enumerates as CH340 /dev/ttyUSB0 @ 115200. Confirm with ls -l /dev/ttyUSB* and a manual G28 via pronterface/printrun.
  2. 🔲 Dry-run inspect: ink_signature_cli.py --order <X> --doc cms10114 --test-box → review the _testbox.gcode + _preview.svg.
  3. 🔲 Plot the box on a blank sheet in the jig: --test-box --plot --home --port /dev/ttyUSB0.
  4. 🔲 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.
  5. 🔲 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.
  6. 🔲 Bake the calibrated defaults into PlotterConfig (or a small plotter_config.json the 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

  1. 🔲 Persisted station config. scripts/workers/services/plotter_config.json (jig offset, pen heights, feeds, port) loaded by PlotterConfig.from_file(). Keeps calibration out of code + flags.
  2. 🔲 Anchor scaling parity test. A test that plots/previews against a page whose page_w/page_h differ from the authored size, asserting the strokes still land in the cell (the stamper already scales; add the matching ink test).
  3. 🔲 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.
  4. 🔲 855 anchors for ink. cms855_pdf_filler only 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.
  5. 🔲 Batch integration. Teach daily_paper_batch.py to, 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.
  6. 🔲 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.
  7. 🔲 Operator safety. --plot already gated; add a hard env guard (INK_PLOTTER_ENABLED=1) so a stray --plot on a dev box can't move a machine, and a --confirm prompt for live runs.

4. Validation (build verifiable criteria)

  • 🔲 Geometry (done, extend): keep test_ink_signature.py green; 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:

  1. 🔲 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.
  2. 🔲 Pilot: run a handful of real plotter-signed filings, track acceptance vs rejection at the MAC/Enumerator. If clean, widen the plotter default.
  3. 🔲 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)

  1. Print + mount the spring pen holder; tape the jig. (§1)
  2. Calibrate with --test-box; record jig/pen values. (§2)
  3. Add persisted plotter_config.json + load it. (§3.1)
  4. Add quality guard + page-scale parity tests. (§3.23.3)
  5. Physical accuracy + legibility validation. (§4)
  6. Wire into daily_paper_batch with per-sheet plotted status. (§3.5)
  7. Add env/confirm safety guards. (§3.7)
  8. Pilot live filings under the go-live policy; widen or fall back. (§5)
  9. (Later) 855B/O/A anchors so org filings can be plotted too. (§3.4)

Dependencies / risks

  • Everything in §12 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-box check.
  • 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.