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.
Two reported bugs, plus two related ones found while tracing:
1. WRONG PRODUCT (Stripe showed 'FCC setup package' for a trucking order): the
trucking new-carrier form reused the slug 'new-carrier-bundle', which is the
TELECOM VoIP onboarding bundle (FRN+499+RMD+CPNI+CALEA, $1799). So trucking
customers were charged the telecom product/price and saw FCC on their receipt.
Added a distinct 'dot-new-carrier-bundle' (USDOT+MC+BOC-3+MCS-150+Drug&Alcohol,
$599 + FMCSA gov fees) and pointed the trucking page at it.
2. ACH 500 error: the Stripe session requested the Financial Connections
'balances' permission, which isn't activated on the account -> Stripe rejected
the whole session (invalid_request_error). Removed 'balances' (+prefetch); we
only need 'payment_method' to collect+charge the bank account.
Also fixed (found while tracing):
3. The telecom new-carrier-bundle's BUNDLE_COMPONENTS listed TRUCKING slugs by
mistake (copy/paste) -- corrected to its real FCC components.
4. The trucking page offered llc-formation / corp-formation / foreign-qual which
did not exist in the catalog (batch would 400). Added llc-formation +
corp-formation; remapped foreign-qual -> foreign-qualification-single.
Catalog regenerated (66 -> 69 services), drift-check + tsc clean.
Previously two hand-maintained price lists (API COMPLIANCE_SERVICES + site
SERVICE_META) drifted apart -- that is how the healthcare +$200 raise charged
$399 while displaying $599. Eliminate the drift class entirely:
- Move the catalog to api/src/service-catalog.ts (the authority; checkout
charges from it). compliance-orders.ts imports it.
- scripts/gen-service-catalog.mjs generates site/src/lib/service-catalog.generated.ts
from the API source. intake_manifest.ts re-exports SERVICE_META from it, so all
~60 site pages keep working unchanged.
- deploy.sh regenerates + drift-checks before building (site build context is
./site only and cannot read ../api, so generation happens host-side).
- scripts/check-service-catalog-drift.mjs fails the build if the generated file
ever diverges from the API (verified: passes aligned, fails on mismatch).
To change a price now, edit ONE file: api/src/service-catalog.ts.