Two of our three real paid customers (Mark Adams / mark@adamslumber.com and
Paul Wilson / synthetic@pipeline.com) never completed intake. They each hit the
old hard cap of 10 daily reminders (last sent Jun 12 / Jun 13) and the worker
then went permanently silent -- the last two daily runs reminded 0 orders even
though both still owe us intake on paid work. (The third, mitchell allen /
mitchell@allenscrapmetal.com, did complete intake; his orders are dispatched.)
Replace the dead-stop cap with a two-phase cadence:
- daily for the first DAILY_PHASE (10) nudges -- the initial burst,
- then weekly (WEEKLY_INTERVAL_DAYS) up to an absolute MAX_REMINDERS (60),
so a paid order with missing intake keeps getting a gentle nudge instead of
being dropped. Tunable via INTAKE_REMINDER_DAILY_PHASE /
INTAKE_REMINDER_WEEKLY_INTERVAL_DAYS / INTAKE_REMINDER_MAX. Clearing
intake_reminder_last_at re-arms an order immediately (documented in the
module docstring).
David Sgro (PA OAG complaint BCP-26-05-025816) opted out 2026-04-13; response
emailed to the AG 2026-06-11. To make the suppression bulletproof and keep the
response's representations true:
- Added a legal do-not-contact list (DO_NOT_CONTACT_DOMAINS/_EMAILS) to
_email_exclusions.py with dataspindle.com / dave@dataspindle.com; folded into
BLOCKED_EMAIL_DOMAINS and is_blocked().
- listmonk_import.upsert_subscriber now refuses to import/re-confirm any
suppressed address. This closes the exact gap that re-added him on 2026-04-26:
the duplicate-import branch re-added an existing unsubscribed subscriber to
lists with status=confirmed, overriding the opt-out.
- MCS150UpdateHandler is the catch-all for many admin-assisted DOT services
(UCR, MC authority, audit prep, ETA, name reservation, registered agent,
annual report). It was filling an MCS-150 PDF for ALL of them -- e.g. a UCR
order produced a wrong MCS-150 PDF. Now only MCS150_FORM_SLUGS fill the form;
others get an admin-review todo (PDF 'not generated') for manual handling.
Signature flow was already correctly scoped (UCR is not in DOT_SIGNING).
- handle_process_compliance_service forced the Sales Order workflow_state to
'Review' via set_value, which bypasses ERPNext's allowed transitions and
threw WorkflowPermissionError (Received -> Review) on every run. The Postgres
fulfillment_status is the source of truth; the ERPNext workflow_state is a
cosmetic mirror. Now try the proper apply_workflow action and stay quiet
(debug, not warning) when no valid Review transition exists.
We no longer offer Canadian accountant/accounting setup. Removed all
service-offering content:
- Marketing page (services/telecom/canada-crtc): the 'Set Up Canadian
Accounting (we help)' next-steps card, the '3 hours of complimentary
accounting consultation' deliverable bullet, and the whole 'Accounting
Support' section (assigned accountant, portal chat, $75/hr, 3 complimentary
hours).
- Order page (order/canada-crtc): the '3 hrs Canadian accounting support'
included-feature bullet and the 'Preferred accounting software'
(Xero/QuickBooks) form field + its accounting-hours helper text.
- Fulfillment (canada_crtc.py): dropped the bank-setup email line offering
'3 hours of Canadian accounting consultation'.
Kept factual GST/HST tax advisories and the bank's QuickBooks/Xero
transaction-sync feature (third-party bank capability, not our service).
MCS150UpdateHandler is the catch-all for many admin-assisted DOT services
(UCR, MC authority, audit prep, ETA, name reservation, registered agent,
annual report). My new intake-completeness gate was firing the 'confirm your
MCS-150 details' email for ALL of them -- e.g. a UCR order wrongly emailed the
customer about MCS-150 details. Scope the gate to MCS150_FORM_SLUGS (the
services that actually file an MCS-150: mcs150-update, dot-registration,
usdot-reactivation, dot-full-compliance).
Paul Wilson (Compound Technologies) signed up with synthetic@pipeline.com,
which is a genuine, deliverable EarthLink address (pipeline.com MX ->
earthlink-vadesecure.net; he confirmed receipt by phone). Our code had
hardcoded pipeline.com + the synthetic@ prefix as a 'non-deliverable
FMCSA-census placeholder' and silently suppressed every automated email to
him (checkout provisioning, order-creation validation, intake reminders,
set-password invites). Nothing in the codebase actually generates that
address, so the placeholder rationale was wrong. Removed pipeline.com and the
synthetic@ rule from all four suppression sites; only RFC-reserved
example.com/test.com/invalid remain blocked.
Closes the data gap for orders that bypass the full intake (e.g. the DOT
compliance-remediation pipeline) and for all MCS-150 variants:
- Worker intake-completeness gate (mcs150_update): before filling, check the
customer-required operational fields the FMCSA census cannot supply
(operation classification, cargo, CURRENT annual mileage, email; plus
signer/address for new-registration/reactivation, and states-of-operation
for 150B hazmat). If missing, email the customer a census-pre-filled intake
link and hold the order at fulfillment_status='awaiting_intake' with an admin
todo, instead of fabricating a blank filing. The existing intake PUT endpoint
already re-dispatches the worker on submit, so filing auto-resumes.
- Intake wizard (Wizard.astro): when resuming ?order=CO-xxx for a DOT/MCS order,
seed still-empty fields from the FMCSA census (name/address/fleet/interstate)
so the customer only confirms the operational details.
- /api/v1/dot/census now also returns total_drivers + a normalized
carrier_operation_code for the prefill.
- MCS150Step.astro extended to collect every field the filler needs across all
variants: mailing address, cdl_drivers, primary_vehicle_type,
reason_for_filing, usdot_revoked, cell/fax, hazmat-safety-permit block
(needs_hmsp, operating states, security plan), and intermodal-equipment
provider counts; all prefill from intake_data.
verify_mcs150_variants.py covers 150/150B/150C end-to-end (ALL PASS).
Fixes a batch of missing fields the FMCSA census does not provide and the
filler was mis-mapping:
- Corrected the question->field mapping to match the actual form: Q22 =
COMPANY OPERATIONS (interstate/intrastate, 22xBox), Q23 = OPERATION
CLASSIFICATIONS (for-hire/private/govt, 23xBox). These were swapped, and
the bogus entity-type->23xBox map (no entity-type question exists on this
form revision) was removed.
- Added proper radio-group handling for Reason for Filing (Biennial Update),
Mailing-address (Same as principal vs below), and Q28 USDOT-revoked, with
correct option indices (these are /0../n radios, not /Yes checkboxes; the
old code set them to /Yes and never selected the right option).
- Map interstate/intrastate from the FMCSA census carrierOperationCode, and
populate email/phone/mileage/cargo from intake.
- AcroForm checkbox/radio appearances use a ZapfDingbats glyph that
poppler/Preview fail to render (value set but box looks empty). Now stamp
an explicit X overlay into the page content for every 'on' box so it shows
in every viewer and in the faxed output.
handle_process_compliance_service assumed handlers return local temp
paths and re-uploaded each to MinIO. The MCS-150 handler uploads itself
and returns the MinIO key, so the re-upload tried to read a nonexistent
local file and logged a 'File not found' error after the order was
already correctly held at the admin gate. Now we skip files that don't
exist locally and keep the returned key as-is.
- When intake lacks signer_name, backfill it from the name the client
typed when signing the perjury certification (that name is exactly what
belongs in the form's print/type-name field, certifyName).
- After a client-approved re-dispatch, re-point the signed esign record at
the freshly filled form and re-stamp the signature, so the signed PDF an
admin reviews reflects the current complete form (not a stale earlier
fill). Field layout (and thus signature anchors) is unchanged across
fills, so the recorded anchor coordinates stay valid.
The MCS-150 biennial update re-confirms the carrier's existing FMCSA
record. Previously the PDF filler only had whatever the intake form
collected; rescued/sparse orders (or orders where the carrier's data
lives in FMCSA, not the intake) produced near-empty forms. Now we pull
the carrier census (legal name, address, EIN, fleet counts) from the
FMCSA carrier API and merge it under any customer-provided intake values
(customer edits win), so the form is pre-filled with the carrier's
current registered data. Refactored the FMCSA fetch into a shared
_fetch_fmcsa_carrier helper used by both enrichment and status check.
When an MCS-150/USDOT order hits the pre-submission admin-verification gate, the
Telegram FULFILLMENT NEEDED alert now appends a presigned link to the prepared
PDF (via the public minio.performancewest.net endpoint, IP-allowlisted to admin)
so you can review the document straight from the alert before approving. Added
notify_fulfillment_todo(view_url=...) + a _presigned_view_url helper (public
endpoint + explicit region to avoid the region-probe that 403s from the worker).
The MCS-150/USDOT PDF was generated fine but the MinIO upload threw 'Minio object
has no attribute fobj_put' (wrong method name + signature), so the prepared filing
PDF was never persisted -- nothing for an admin to review at the verification gate,
and the esign-completed re-dispatch failed with 'File not found'. Use the correct
minio fput_object(bucket, key, file_path). Affects every MCS-150/USDOT filing.
Per request: after the customer signs but BEFORE we submit to the government, hold
the order for a human to verify the prepared filing is correct.
- MCS-150 handler (mcs150-update + usdot-reactivation): new admin-verification gate
after the signature gate -- if not admin_approved, set fulfillment_status=
'ready_to_file', create a HIGH-priority 'VERIFY before filing' admin todo, and
STOP (no FMCSA submission). job_server injects admin_approved from the dispatch
payload (mirrors client_approved).
- New admin endpoint POST /api/v1/admin/compliance-orders/:id/approve-submit
(requireAdmin): verifies status=ready_to_file, re-dispatches the worker with
admin_approved=true to proceed to actual submission.
- Durable submission EVIDENCE: the web/fax submitters only wrote confirmation
screenshots to an ephemeral temp dir. Now _upload_submission_evidence copies the
FMCSA confirmation screenshot + attested PDF + fax_log_id to MinIO under
filings/<slug>/<order>/evidence/ and records the keys on the order, so we keep
proof of every government submission.
(state-trucking + the FCC handlers already gate via admin todos / auto_filing.py;
this brings MCS-150 to parity and adds evidence retention.)
Two bugs found tracing Mitchell Allen's batch CB-95BA6C90 (5 DOT services, card):
1) Worker authorization/signing-link/status emails were sent via
smtplib.SMTP('localhost', 25), which has no MTA in the workers container ->
every send failed '[Errno 111] Connection refused', so customers never got
their e-sign links and orders sat 'awaiting client signature' forever. Routed
all 9 hardcoded localhost:25 sites (state_trucking, mcs150_update, boc3_filing,
hazmat_phmsa, mailbox_setup, dot_esign, completion_emails) through the
authenticated SMTP relay (SMTP_HOST/PORT/STARTTLS/login) + added a shared
worker_email.send_worker_email helper.
2) The ERPNext Sales Order for compliance/compliance_batch was only created in
the /checkout/create-session endpoint, but CARD orders confirm via the Stripe
WEBHOOK -> handlePaymentComplete, which never created the SO. Result: every
webhook-confirmed order had erpnext_sales_order=NULL and workers logged
'Sales Order not found 404' then built from PG. Added idempotent
ensureComplianceSalesOrder() to handlePaymentComplete so ALL payment methods
(card-webhook, PayPal, crypto) create + link the SO.
Two latent bugs the e2e harness caught:
1. api entities.ts GET /states/:code/name-search calls WORKER_URL/name-search,
but job_server had NO such route -> 404 -> silently fell back to stale
entity_cache on every live name check. Added a synchronous /name-search route
returning {available,exact_match,similar_names,state}.
2. both the new route AND the existing async handle_name_search imported a
nonexistent search_name_sync(); fixed to drive the real async search_name()
via an event loop (same pattern as /entity-status).
scripts/e2e-formation-order.mjs: replays the real formation order flow (live
name search -> formation_orders insert -> ERPNext customer + Sales Order with
BUSINESS-FORMATION + STATE-FILING-FEE line items -> verify SO total + DB linkage
-> cleanup) without a real Stripe charge or state filing. Run in the api container.
Also created the missing ERPNext Items (BUSINESS-FORMATION, STATE-FILING-FEE,
FOREIGN-QUAL-SINGLE/MULTI) that the formation SO references.
Follow-on to the trucking new-carrier slug fix:
- success page: add dot-new-carrier-bundle to DOT_SLUGS + NEW_CARRIER_SLUGS so
the order-confirmation 'what to expect' messaging classifies it as trucking.
- pipeline_orchestrator: the trucking onboarding PIPELINE was keyed under the
bare 'new-carrier-bundle' slug, which is the TELECOM bundle's slug (also a
collision at the worker layer). Re-keyed to 'dot-new-carrier-bundle' so a
trucking bundle never runs the telecom pipeline (and vice versa).
Client-facing and website code now describes only a generic per-document signing
authorization; nothing visible to signers or recorded in the website/API code or
DB schema references ink, paper, reproduction, or any fulfillment mechanics.
- rename esign-ink-consent.ts -> esign-sign-consent.ts; INK_CONSENT_TEXT ->
SIGN_CONSENT_TEXT (generic: 'use my signature to complete and submit this
single filing', no ink/paper/reproduce language); helpers ink* -> sign*
- portal-esign-generic.ts: API field ink_reproduction -> require_sign_consent,
ink_consent_text -> sign_consent_text, request field ink_consent -> sign_consent
- signing page (site/public/portal/esign): all ids/vars/comments ink* -> sign*;
no 'ink' string remains
- npi_provider metadata flag ink_reproduction -> require_sign_consent
- migration 090/092 + live DB column comments rewritten to drop ink/plotter
wording (DB column names kept as ink_consent* for compat, internal only)
- order-timeline.ts buffer comments neutralized
- tests: 37 checks, consent text asserted to omit ink/plotter/paper/reproduce/etc
DB columns ink_consent* retained (internal, never sent to clients) to avoid a
risky rename of already-applied prod columns.
Consent gate (the legal linchpin from the wet-signature memo):
- migration 092 adds ink_consent/ink_consent_at/ink_consent_text to esign_records
- extract pure, unit-tested gate logic into esign-ink-consent.ts (DRY single
source for route + signing page): isInkReproduction / inkConsentRequired /
inkConsentSatisfied + verbatim client-safe INK_CONSENT_TEXT
- portal-esign-generic.ts: GET surfaces ink_reproduction + consent text; POST
gates DRAWN signatures on ink-path docs on explicit consent, stores it
- signing page locks the signature block until consent is checked (drawn only)
- npi_provider marks cms855/cms10114 esign metadata ink_reproduction=true
- 33 unit checks: gate truth table + consent text omits all internal mechanics
(plotter/machine/CMS/MAC/etc) and keeps required legal reassurances
Patent-risk memo (docs/legal/patent-risk-mechanical-wet-signature.md):
- prior-art-dated risk analysis (autopen 1803/1942, plotters, CNC = public domain
=> low risk on core concept; e-sign workflow space litigious)
- firsthand recent-grant sweep (1.58M USPTO grants 2021-2025, queried via DuckDB):
ZERO patents on machine-applies-signature-in-ink; e-sign players hold only
electronic-workflow patents. Not an FTO; flags where attorney search is needed
Adds a second machine class (small fan-shaped reach arm) alongside the
CR-10/AxiDraw rectangular-bed plotters, so wet signatures can be produced
while away from the home station.
ink_signature_plotter.py:
- PlotterConfig gains dialect (marlin|lineus) + name; new LineUsConfig
(native units, pen height = per-move Z, reach annulus from shoulder pivot).
- Named machine profiles (cr10 default, axidraw, lineus) via load_profile().
- bed_mm_to_lineus_units(), check_reach() (annulus for lineus, rectangle for
marlin), compute_jig_offset_for_box() (solves jig from the ACTUAL fitted ink
extent so a wide cell line doesn't over-constrain a small arm).
- emit_gcode() dispatches to emit_marlin_gcode()/emit_lineus_gcode().
- send_lineus(): WiFi TCP 1337 (NUL-terminated, ok-acked) or USB serial,
dry_run=True default (same gating as the CR-10 path).
ink_signature_cli.py: --profile, --solve-jig (auto-applies jig offset),
--lineus-host/--lineus-usb, reach-check that refuses to --plot out-of-reach
on Line-us.
Tests: 43 checks (was 30) covering profiles, reach check, jig solve, lineus
emitter, dry-run sender. Docs updated with profiles + portable workflow.
Telegram notifications:
- Add shared scripts/workers/telegram_notify.py (send_telegram, notify_fulfillment_todo,
create_admin_todo) so every worker alerts the operator the same way; fire-and-forget.
- Fire notify_fulfillment_todo after each admin_todos insert across all 8 service
handlers (9 sites) so no fulfillment task waits unseen.
(Orders + quotes + tickets already notified via checkout/quotes/tickets routes.)
Client portal order progress:
- order-timeline: derive real per-step status from live signals (payment paid,
e-signature signed, fulfillment_status) instead of a static template; add
current_step to the response.
- Extract pure applyLiveStatus into order-timeline-status.ts (DB-free) + unit test
(api/test/test_timeline_status.ts, 8 cases).
- portal /me now returns compliance_orders.fulfillment_status.
- Dashboard renders a client-safe Progress badge (In progress / Action needed /
Filed-awaiting-confirmation / Completed); batches show the most actionable status.
No back-office mechanics exposed.
ERPNext sync parity:
- Create a Sales Order for formation and fcc_carrier_registration orders (previously
only canada_crtc + compliance synced); write erpnext_sales_order back to each table.
Non-blocking, matches existing pattern.
Verified: API tsc clean, timeline unit tests 8/8, Astro build 58 pages,
cms10114/ink/paper_batch Python tests still green, no mechanics leaks.
The Standard no-login CMS path needs an ORIGINAL ink signature on paper
(CMS-10114: 'Stamped, faxed or copied signatures will not be accepted'). This
adds a pipeline to redraw the provider's own captured strokes in real ink with a
pen on a CR-10 V2 (or any Marlin/GRBL machine) — original, in ink, never copied.
- migration 090: esign_records.signature_vector (JSONB stroke paths, 0..1).
- signing page now captures normalized stroke paths alongside the PNG; API
stores a size-bounded vector for drawn signatures.
- ink_signature_plotter.py (hardware-independent): fit strokes to the signature
anchor box, PDF-pt -> bed-mm via jig offset, emit Marlin/GRBL G-code (Z pen or
M280 servo/BLTouch), SVG toolpath preview, and render_signature_on_pdf (a
digital twin that proves the toolpath lands on the cert line). Gated serial
sender (dry_run default).
- ink_signature_cli.py: end-to-end load-record -> gcode+preview, --test-box jig
calibration, --plot to stream over USB.
- Corrected CMS-10114 signature anchor to sit inside the Section 4A signing cell
(above the bottom rule, below the label).
- docs/ink-signature-plotter.md documents the CR-10 retrofit + interpretive risk.
Tests: test_ink_signature.py 30/30, test_cms10114.py 27/27, test_paper_batch.py
15/15, API tsc clean, Astro build 58 pages.
Verified firsthand against the live CMS-10114 (Rev. 02/25, OMB 0938-0931):
- Section 1A confirms paper is valid for Change of Information (#2) AND
Reactivation (#4), not just initial enumeration. Resolves the UNCERTAIN flag.
- Current mailing address is CMS NPI Enumerator Services, Mail Stop DO-01-51,
7500 Security Blvd, Baltimore MD 21244. The old Fargo PO Box 6059 is retired;
corrected in mac_routing.NPI_ENUMERATOR + all docs.
- No electronic no-login equivalent exists for CMS (NPI Registry API is
read-only; PECOS/NPPES-IA require login), unlike FMCSA's ask.fmcsa ticket form.
So tiers stay: Standard=paper CMS-10114 (no login), Expedited=NPPES surrogate.
New: cms10114_pdf_filler.py fills the flat official form via text overlay
(reason checkbox + NPI + Section 2A identity + Section 4A cert name + signature
anchor); wired into npi_provider._generate_10114_for_signing for nppes-update.
Signed forms route to the NPI Enumerator via the existing daily batch.
Tests: test_cms10114.py 27/27, test_paper_batch.py 15/15, Astro build 58 pages.
- NpiIntakeStep: add positively-framed 'can you grant electronic I&A Surrogate
access?' question for all filing slugs (reval/reactivation/nppes-update/
enrollment/bundle). Optional, never required, never mentions paper; captured
as intake_data.surrogate_access (yes/no/blank). Astro build green (58 pages).
- npi_provider.py: surface the surrogate answer in the admin todo so fulfillment
knows EXPEDITED (online via surrogate) vs STANDARD (e-sign + daily mail batch).
Standard (no-login) CMS filings are mailed in one Priority Mail envelope per
destination agency, batched each postal working-day morning to save postage.
- migration 089: paper_filing_batches table + esign_records.paper_batch_id /
filing_destination_key (idempotent: a filing is batched at most once).
- batch_cover_sheet.py: per-agency cover sheet (sender/dest/date/manifest) +
merged print-job PDF (cover + all enclosed signed filings).
- daily_paper_batch.py worker: gather signed+unbatched cms855/cms10114 filings,
group by destination (MAC by state via mac_routing; Fargo for CMS-10114),
build cover+merged PDF per agency, persist batch, mark filings batched.
Self-gates on postal working days (skips weekends + federal/USPS holidays).
Phase 1 = human prints+mails; phase 2 = wire print-mail API.
- worker-crons: pw-paper-batch systemd timer (Mon-Fri 13:30 UTC, self-gated).
- test_paper_batch.py: 15/15 pass (working-day gating, routing, cover+merge).
- Verified Standard(no-login)/Expedited(surrogate) matrix from official CMS-855
PDFs (docs/healthcare-filing-tiers-verified.md): reactivation+revalidation are
855I paper-to-MAC reasons, original-signature, routed by state; sig may not be
delegated; 855B needs PECOS app fee.
- Add scripts/workers/mac_routing.py: state->MAC routing (all 56 jurisdictions,
12 destinations) for envelope addressing + daily batch grouping. Addresses
marked VERIFY before live mail.
- npi_provider.py: fix access strings to two-tier framing; NPPES update/reactivation
no longer 'online-only'; note 855B fee.
- checkout.ts + service pages: strip client-facing mechanics & the paper-vs-tier
choice; surrogate is the only optional, positively-framed ask (faster, never
required, never share password).
The residential proxy password contains a '#', which urlparse() misreads as a
URL fragment and corrupts the port (ValueError: Port could not be cast...).
Parse scheme://creds@host:port manually and percent-decode user/pass so both
raw ('#') and encoded ('%23') passwords work. Verified against the live
credential.
CMS healthcare portals (NPPES, PECOS, I&A) block datacenter IPs, so the
healthcare browser automation needs to egress via the residential proxy on
hg409y7ez04.sn.mynetname.net (username 'performancewest').
- undetected_browser: use_proxy now accepts an env-var name, so callers can
select a domain-specific proxy. _proxy_config(proxy_env) reads it and falls
back to UNDETECTED_PROXY_URL. Healthcare uses 'HEALTHCARE_PROXY_URL'.
- probe_npi_undetected: launches with use_proxy='HEALTHCARE_PROXY_URL' when set.
- npi_provider: documents that the (future) automated NPPES/PECOS flows must
use the healthcare proxy.
- Plumb HEALTHCARE_PROXY_URL (+ UNDETECTED_PROXY_URL fallback) through the
ansible env template and docker-compose workers env.
The credential itself is NOT in the repo. Set the full URL in the ansible
vault as vault_healthcare_proxy_url:
socks5://performancewest:<password>@hg409y7ez04.sn.mynetname.net:<port>
Verified parsing + Playwright proxy-dict wiring with a unit test.
Copy: drop paper/electronic/fax framing across the revalidation + enrollment
marketing pages and the order-confirmation email; present two service tiers:
- Standard filing (no CMS account; we prepare CMS-855, you sign, we submit to MAC)
- Expedited filing (CMS I&A surrogate access; same-day PECOS filing + tracking)
Internal worker todos + the _STANDARD_FILING_SLUGS identifier updated to match.
New scripts/test_healthcare_e2e.py validates the whole order line (slug
consistency x6 places, price agreement, intake field collection+enforcement,
worker dispatch, handler execution producing CMS-855 PDF+anchor, free-tool
action_urls). 45 checks.
Bugs found + fixed by the test:
- medicare-enrollment requires practice_state server-side but the wizard never
enforced it -> orders could be paid then stall. Wizard now requires it.
- determine_form_type defaulted org NPIs to the individual 855I because
enumeration_type is never collected -> wrong form, CMS rejection. Now does a
live NPPES lookup (safe 855I fallback).
- cms855_pdf_filler.py: fills official CMS-855I/B/O/A AcroForms from intake
(name, NPI, DOB, cert-page printed name) and records the signature anchor at
the form's official /Sig box so the e-sign stamper lands on the cert line.
- npi_provider handlers (revalidation/reactivation/enrollment) now generate the
paper CMS-855, upload it to MinIO, request_esign with anchors, and email the
signing link. Human completes/verifies + USPS Priority Mails to the MAC.
- scripts/Dockerfile: copy the official CMS-855I/B/O/A forms into the image.
- order-confirmation email presents both filing methods: paper CMS-855 (no
account needed, client e-signs one page, we print+mail to their MAC) and
I&A surrogacy (faster, needs CMS account). NPPES-only services note that
surrogacy is required (web-only).
- npi_provider handlers record the access model per service in admin todos.
- marketing copy leads with the lowest-friction paper option.
Adds a systemd-timed worker that nudges customers who paid but never completed
their intake form (which stalls fulfillment).
- migration 087: intake_reminder_count + intake_reminder_last_at on
compliance_orders (makes the daily run idempotent and bounded), plus a
partial index for the paid-order eligibility scan.
- scripts/workers/intake_reminder.py: each run emails any paid order with
intake_data_validated != TRUE, capped at 10 reminders/order, at most one
consolidated email per customer per day (groups a customer's incomplete
services into one email). Reuses the post-payment intake URL format
(/order/{slug}?order={n}) and the API's email validation, skipping
placeholder/invalid addresses (synthetic@, pipeline.com, etc.). Sends via
smtplib with SMTP_PASS (verified working in the worker container).
- worker-crons: pw-intake-reminder timer, daily ~noon ET (16:00 UTC).
Root cause of customers being unable to log in: ERPNext (portal.performancewest.net)
is the intended single portal and already surfaces compliance/trucking orders
(performancewest_erpnext/www/orders.py reads compliance_orders by email). But
only the Stripe checkout path provisioned the ERPNext Website User up-front
(findOrCreateCustomer). PayPal / crypto / remediation-pipeline orders go straight
to handlePaymentComplete, which created NO portal user and never set
portal_user_created -> no login + no set-password invite (exactly what happened
to the Paul Wilson / Compound Technologies PayPal order).
- handlePaymentComplete: add ensureCompliancePortalUser() in the shared
post-payment path so EVERY paid compliance order (any payment method) gets an
ERPNext portal account + the set-password invite. Idempotent.
- Guard against placeholder emails (synthetic@/pipeline.com etc): skip portal
provisioning and the set-password invite for non-deliverable addresses.
- compliance-orders API: validate email format AND reject placeholder addresses
at order creation (was: presence-only, so synthetic@pipeline.com passed).
- delivery_worker: never email a set-password invite to a placeholder address.
Note: the legacy PG-customers login (api/routes/portal-auth.ts, /account/*) is
CRTC/formation-era and only backfills canada_crtc_orders/orders, never
compliance_orders. ERPNext is now the consistent portal for compliance.
Customers (the DER) had no concrete how-to for onboarding/enrolling drivers or
what information to collect. Add:
- Section 1 'Enrolling a driver (new-hire onboarding)' subsection: exact info to
collect, the onboarding sequence (collect info, sign Forms A/B, Clearinghouse
query, prior-employer inquiry, add to C-TPA pool, pre-employment test, wait for
MRO negative), and a driver-removal note.
- Form G — Driver Enrollment & Covered-Employee Roster: per-driver enrollment
block (name, DOB, SSN last4, CDL #/state, contact, hire date, test result,
Clearinghouse/prior-employer status) plus a roster table for the covered pool.
- TOC, email, and handler text updated A-F -> A-G.
The instant-delivery email told customers to 'just reply to this email' with no
way to view/manage their order. Add a portal line in the body and change the CTA
to 'View in Portal' pointing at PORTAL_URL (portal.performancewest.net), matching
delivery_worker/renewal_worker conventions. Add _site_url()/_portal_url() helpers.
- Rewrite dot_da_binder_generator.py to emit an editable .docx (was reportlab PDF)
so carriers/counsel can review and adapt the program. ~4000 words, 10 sections.
- Render all six required forms (A-F); previously only A, D, E existed. Each form
starts on its own page (page break) and fills a page.
- Mode-aware policy text for FMCSA/FRA/PHMSA/FTA/FAA/USCG with correct CFR parts
and random-testing rates; optional single-state Drug-Free Workplace addendum
(federal DOT program is nationwide; only the optional DFWP addendum is state-keyed).
- Handler now outputs .docx instead of .pdf.
- job_server instant-delivery: attach DOCX (correct MIME) as well as PDF, and use
DOT-specific email copy + CTA instead of the FCC/telecom boilerplate.
Turn the DOT Drug & Alcohol Compliance Program into an automated
instant-delivery deliverable: when a carrier orders, we generate a
complete, print-ready PDF binder and email it (no admin step).
The binder (dot_da_binder_generator.py) bundles everything a small
carrier needs under 49 CFR Part 382 + Part 40:
- How to manage the program (DER setup + annual operations)
- Written drug & alcohol testing policy for employees
- The six DOT test scenarios + triggers
- Random testing / consortium (C-TPA) instructions
- Supervisor reasonable-suspicion training + live/online access
- Violations, SAP access, return-to-duty / follow-up
- EAP / rehab / treatment resources (SAMHSA, 988, locator, ODAPC)
- Recordkeeping retention schedule
- Ready-to-use forms (acknowledgment, reasonable-suspicion,
post-accident decision worksheet)
- Regulation citations
- Optional state Drug-Free Workplace addendum
Policy-variant selection: FMCSA (Part 382) is the trucking default;
honors an explicit dot_da_mode override for FRA/PHMSA/FTA/FAA/USCG.
New DrugAlcoholProgramHandler returns the binder PDF; slug added to
INSTANT_DELIVERY_SLUGS so job_server emails it automatically. Slug
rerouted from MCS150UpdateHandler (was admin-assisted enrollment) and
re-priced as a discountable own-deliverable (no passthrough cost).
Tests: scripts/tests/test_dot_da_binder.py (FMCSA sections, PHMSA+state
addendum, all-modes render) — passing.
Item 2 of the trucking state-authorization plan.
- compliance-orders.ts: populate gov_fee_label for every state-trucking
service so the variable, billed-at-cost government charges (apportioned
IRP, IFTA decals, NY HUT, CT HUF, weight-distance, CA MCP+CARB, OS/OW
permits, bundle) are disclosed at checkout. price_cents stays the flat
service fee; gov fees pass through at cost.
- migration 086: compliance_orders.fulfillment_status state machine
(authorization_required -> authorization_signed -> awaiting_customer_
delegation -> awaiting_secure_credentials -> awaiting_government_fee_
approval -> awaiting_insurance_filing -> ready_to_file ->
filed_waiting_state -> completed) + fulfillment_status_at
- state_trucking.py: FULFILLMENT_* constants + _set_fulfillment_status();
gate sets authorization_required on pause, authorization_signed on
resume, ready_to_file once the filing todo is queued
- TruckingValueNotice.astro: 'What's included & what's billed at cost'
disclosure with the authorization/delegation explanation
Capture-to-form signature placement so the customer's drawn or typed
signature lands right on the signature rule of the actual form, not in a
sidecar page.
- migration 085: esign_records.signature_anchors (JSONB exact PDF coords,
lower-left origin, points) + signed_document_minio_key
- signature_stamper.py: signature_box() anchors; anchors_from_acroform()
pulls the signature field /Rect from a real AcroForm (e.g. MCS-150
certifySignature); stamp_signature() overlays PNG (auto-trimmed so ink
rests on the rule) or typed name, scaled to actual page size
- state_trucking_authorization.py: renders the Limited Authorization to
File PDF and returns (pdf_bytes, anchors)
- esign_stamp.py: stamp_esign_document() downloads unsigned PDF, stamps,
uploads _signed.pdf, sets signed_document_minio_key (idempotent)
- dot_esign.py: extract certifySignature anchor for MCS-150/closeout forms
so the federal perjury cert is signed on the line
- state_trucking.py: authorization gate — first run emails signing link
and PAUSES; resumes with client_approved after signing
- job_server handle_esign_completed: stamp then re-dispatch
- tests: test_signature_placement.py (custom form), and
test_mcs150_signature_placement.py (official AcroForm) both assert the
signature lands inside the recorded signature box (verified visually)
Dependency edges can now require the prerequisite be ACTIVE at FMCSA, not
just our handler completed. mc-authority/ucr/d&a now wait for an active
USDOT; BOC-3 stays parallel-OK (can file while authority pending). Adds
_prerequisite_active() polling FMCSA QC API, a waiting_on_activation hold
state with next-check timestamp, and a 21-day authority vetting estimate
for customer comms. Branch logic unit-tested.
_get_authority_state() returns structured FMCSA authority state; handle()
branches on active/pending/revoked/none:
- active: file/refresh BOC-3 (current behavior)
- pending: file BOC-3 + insurance/21-day-vetting reminder
- revoked: file + recommend reinstatement (mc-authority, never auto-charge)
- none (USDOT only): flag MC authority needed first, do not file blindly
recommended_followups + authority_state persisted in admin todo for
upsell-approve on the order timeline.
Forms that legally require the client's signature were not being captured
correctly:
- MCS-150 handler created a perjury e-sign record but then submitted to FMCSA
anyway, before the client signed. Now it gates submission: request the
signature, hold, and only file when handle_esign_completed re-dispatches with
client_approved=True.
- MCS-150 e-sign links were signed with JWT_SECRET/ADMIN_JWT_SECRET, but the
portal verifies with CUSTOMER_JWT_SECRET, so every link returned "Invalid
portal link." New shared dot_esign helper signs with CUSTOMER_JWT_SECRET.
- carrier-closeout (final MCS-150 Out of Business) and entity-dissolution
(Articles of Dissolution + no-lawsuits/liens/judgments attestation) captured
no signature at all. Both now request a signed attestation before the
workflow proceeds.
- mc-authority / emergency-temporary-authority now get a correctly labeled
OP-1 applicant certification instead of an "MCS-150" record.
Also fixes a latent dispatcher bug: order["service_slug"] was never set, so
handlers sharing a class fell back to their default SERVICE_SLUG. This made
entity-dissolution run the carrier-closeout branch and mc-authority/etc. look
like mcs150-update. Now the resolved slug is injected into order_data.
Portal e-sign page now renders the document-specific certification text from
metadata.perjury_text (so the dissolution no-liabilities attestation and OP-1
cert are actually shown to the signer), not just a generic perjury line.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- build_trucking_campaigns.py: nightly script that creates 8 Listmonk campaigns
per day (4 TZ x 2 types: MCS-150 overdue 2k/TZ, inactive USDOT 1k/TZ)
at 4AM ET / 5AM ET (CT) / 6AM ET (MT) / 7AM ET (PT). Deduplicates via
listmonk_sent_at column.
- migration 083: add listmonk_sent_at + listmonk_campaign_type to fmcsa_carriers
- email_verifier.py: bump max_workers from 5 to 20 for 4x faster throughput
- cron: daily pw-trucking-campaigns at 08:00 UTC (3 AM EST)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Checker closing mode now pitches a done-for-you 'Trucking Wrap-Up' ($199)
with a buy button to /order/dot-compliance?services=carrier-closeout, instead
of a lead form. DIY checklist replaced by what's-included list.
- Entity dissolution offered as a paid add-on with the lawsuits/liens/judgments
warning before dissolving.
- New catalog services: carrier-closeout ($199), entity-dissolution ($199).
- CarrierCloseoutHandler orchestrates the sequential shutdown workflow
(final MCS-150 out-of-business, MC revoke, UCR cancel, IFTA/IRP + state
closures; dissolution branch for the add-on) as admin-tracked tasks.
- Sell-your-trucks: single shared form with quick-cash / marketplace / both;
name field is now a real first+last name (no corp-name prefill).
- tickets categories: add truck_sale_both, drop business_closeout (now an order).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>