export const MASTER_ROUTER_CHOICES = [
'working_capital',
'ar_financing',
'po_financing',
'inventory_financing',
'real_estate_financing',
'equipment_financing',
'letter_of_credit',
'stretch_financing',
'other',
'exploring_options',
'unknown',
] as const;
export const MasterRouterSchema = z.object({
field77: MasterRouterChoiceSchema,
});Every field.
Every constraint.
The packages/csg-schema Zod definitions are the canonical source, and the TypeScript types are inferred from those same objects. A CI gate holds the Zod source to the Product Gating Spec field by field. Other language bindings are on the roadmap, not shipped — the table below says which is which.
One source. One definition.
Take field77 (the §3 Master Router). The enum is declared once in Zod; the type is inferred from it; the CI manifest pins it to the spec.
export type MasterRouterChoice =
z.infer<typeof MasterRouterChoiceSchema>;
routeFromMasterRouter('ar_financing');
// {
// branch: 'Factoring',
// sections: ['§6'],
// needs_consultation: false,
// }{
id: 77,
section: '§3',
name: 'master_router',
status: 'implemented',
}main-pipeline.yml runs the csg-schema suite as part of the Vitest workspace, and that suite includes a parity test asserting that every field in the spec manifest — 90 entries today, transcribed from the Product Gating Spec — has a matching key in an implemented FIELD_IDS_constant. Mark a manifest field implemented without shipping its Zod definition and the build fails.
What ships today.
Zod and TypeScript are the two forms that exist and stay in lockstep by construction. The OpenAPI components are real but hand-written. JSON Schema, Python, and Go are roadmap.
Zod validators
livepackages/csg-schema/src/sectionsThe canonical source. parse / safeParse plus superRefine cross-field rules — FEIN required only for US registration, state vs province lists swapped by country.
TypeScript types
live@capitalsource/csg-schemaEvery exported type is a z.infer of the object above it, so there is one definition rather than a type and a validator that can disagree. No `any` anywhere.
OpenAPI 3.1 components
hand-writtendocs/openapi/v1.yamlReal and linted by redocly in CI, but hand-maintained — not emitted from the Zod source. Treat mismatches as bugs and tell us.
JSON Schema (draft 2020-12)
plannednot generated yetThere is no JSON Schema emitter on the Zod source today, and no schemas/csg-1003.json to download. Language-agnostic consumers use the OpenAPI components for now.
Python dataclasses
plannedcapitalsource-csg-schema (unpublished)V2.1 target. Pydantic v2 + dataclass twin generation. Not on PyPI.
Go structs
plannedcsg-schema-go (unpublished)V2.1 target. Struct tags plus a branch-dispatch helper. No public module yet.
13 section modules. 90 field definitions.
Every field has a canonical slug and a spec field id that never changes. §2 core is required on every submission; §4 cross-cutting blocks are required when the product branch selected by Field 77 pulls them in; each branch adds its own fields.
§2 Core (22 keys, 18 spec rows)
- · consent
- · legal_business_name
- · trade_name
- · entity_type
- · industry_type
- · country_of_registration
- · state_or_province
- · inception_date
- · fein
- · business_address
- · owner_legal_name
- · owner_title
- · ownership_percentage
- · owner_mobile
- · owner_email
- · owner_dob
- · owner_ssn
- · primary_residence_address
- · certification_authorization
- · certification_esign_consent
- · certification_signature
- · certification_date
§3 Router (field77) + §4.1 Trade finance (7)
- · master_router
- · supplier_country
- · supplier_prepayment_pct
- · incoterms
- · product_inspected
- · inspector
- · shipping_destination
§4.2 Bank health + §4.3 Debt stack (10)
- · primary_depository_bank
- · avg_daily_bank_balance
- · nsf_count_last_3_months
- · negative_day_count_last_3_months
- · bank_statement_upload_last_3_months
- · has_existing_debt
- · open_position_count
- · total_outstanding_balance
- · combined_periodic_debit
- · debt_position_list
§5 RBF / Working capital (4)
- · rbf_product_fit
- · funding_urgency
- · preferred_term_length
- · personal_credit_score_range
§6 Factoring / A/R (10)
- · total_outstanding_ar
- · average_invoice_size
- · standard_invoice_terms
- · active_customer_count
- · top_customer_concentration
- · currently_using_factor
- · current_factor_name
- · recourse_preference
- · ar_aging_upload
- · sample_invoice_customer_list_upload
§9 Real estate (8)
- · loan_purpose
- · property_type
- · property_address
- · estimated_property_value
- · existing_mortgage_balance
- · annual_noi
- · owner_occupied
- · t12_rent_roll_upload
§7 PO Financing (7), §8 Inventory (6), §10 Equipment (7), §11 Letter of Credit (7), and §12 Stretch (2) round out the 90. Source of record: packages/csg-schema/src/sections/ and the Product Gating Spec. There is no generated per-field reference site yet.
Known gap: the spec's un-gated financial block — employee counts, sales model, average monthly revenue, amount needed, use of funds — is written in §2 but has no Zod definition yet, so it is not in the 90 and not in the parity manifest.
One package. Every surface.
@capitalsource/csg-schema ships the Zod validators and their inferred TypeScript types. The MCP server, REST API, and Recurser CLI all consume it — nobody redefines a field. It is workspace-internal at v0.0.1 and not published to npm, so today you consume it through the API, the CLI, or a copy of the spec we send you.