# Multi-Province, Canadian Formation & Universal Compliance — Implementation Plan **Created:** 2026-04-05 **Status:** Planning — dev-only implementation, not yet in production **Triggers:** - Ontario removed Canadian resident director requirement (Bill 213, July 2021) - Formation page frontend already supports 10 Canadian provinces (backend does not) - Compliance calendar system built for CRTC but not used by other order types --- ## Goal Three interconnected features: 1. **Multi-province CRTC** — Extend the $3,899 CRTC Carrier Package from BC-only to multi-province. Ontario first; architecture supports any Canadian province. 2. **Standalone Canadian formation** — Offer Canadian province incorporation (C$449 + gov fees) on the existing formation page WITHOUT telecom registration. Separate flow from CRTC. 3. **Universal compliance calendar** — Create compliance entries for ALL orders (US formations, Canadian formations, CRTC carriers). Formation maintenance bundle at $199/yr. Service fee stays at $3,899 USD for CRTC regardless of province. US formation: $179 Basic / $399 Complete. Canadian formation: C$449 + gov fees (single tier). Government fees passed through at cost for all products. **Dev-only gate:** Ontario and Canadian formation options visible only in dev (`import.meta.env.DEV` / `NODE_ENV !== 'production'`). Production continues unchanged until everything is tested end-to-end. --- ## Research Findings ### Ontario Director Residency — Confirmed Removed Bill 213 (Better for People, Smarter for Business Act, 2020) removed OBCA s.118(3) requiring 25% of directors to be Canadian residents. Proclaimed in force July 5, 2021. Both BC and Ontario now have no Canadian residency requirement — the key enabler for our foreign (non-Canadian) clients. ### Ontario vs BC Comparison | Factor | BC | Ontario | |--------|----|----| | Director residency | None required | None required | | Incorporation fee | ~C$350 | ~C$360 | | Annual return/report | C$42.71/yr | C$25/yr | | Portal | BC Corporate Online (anonymous) | Ontario Business Registry (requires login) | | Entity format | "1234567 B.C. Ltd." | "1234567 Ontario Inc." | | Legal endings | Ltd., Inc., Corp., Limited, etc. | Inc., Corp., Ltd., Ltee (+ French) | | Sales tax | GST 5% + PST 7% = 12% | HST 13% (combined) | | Workers comp | WorkSafeBC | WSIB | | DID area codes | 604/778/236/250 | 416/647/437/905/289/365/519/613 | | AMB locations | 4 (Vancouver) | 30+ (Toronto, Mississauga, Ottawa, etc.) | | AMB pricing | ~C$13-20/mo | from C$7.99/mo | | Corporate tax (small biz) | 11% combined | 12.2% combined | | Language | English only | English or French | ### Province-Agnostic Components (Zero Changes Needed) These are federal or infrastructure-level and work identically for any province: - CRTC domestic carrier registration (letter to Secretary General) - BITS international registration (Form 503 + affidavit) - CCTS membership registration - GCKey provisioning (for CRTC filings) - .ca domain registration via Porkbun (CIRA CPR satisfied by any Canadian corp) - HestiaCP email/hosting provisioning - eSign portal flow - MinIO document storage - Corporate binder compilation (pikepdf + reportlab) - Payment processing (Stripe/PayPal/SHKeeper) ### Key Difference: OBR Requires Login BC Corporate Online is anonymous — no account needed. The Ontario Business Registry requires an Ontario Business Account (OBA) login. Plan: create a Performance West "house account" on the OBR and test whether it's suitable for filing multiple incorporations. If not, fall back to admin ToDo with manual incorporation. ### Formation Page — Existing Canada Support The formation order page (`site/src/pages/order/formation.astro`) already has: - Country selector (US / CA) - `CA_PROVINCES` array with all 10 provinces + fees + live FX conversion - Entity type swap: LLC->Ltd., Corporation->Inc., S-Corp->Corp. - Province dropdown with dual CAD/USD pricing - CRTC callout linking to the CRTC order page (separate flows) **What's missing:** The backend (`formations.ts` route) only validates US entity types and the `formation_orders` table has `entity_type CHECK (llc, corporation, s_corp)`. Canadian types (ltd, inc, corp) are rejected. No Canadian province adapter is dispatched. ### Codebase Coupling (CRTC Pipeline) ~100+ hardcoded "BC" references across: - Order form (`site/src/pages/order/canada-crtc.astro`) — ~40 references - Pipeline (`scripts/workers/services/canada_crtc.py`) — ~50 references - API route (`api/src/routes/canada-crtc.ts`) — ~10 references - AMB scraper, Flowroute DID, compliance calendar No `province` column in `canada_crtc_orders` table. Pipeline hardcodes `BCPortal` import. Good abstraction points exist: `StatePortal` base class, `amb_locations.province` column, `own_ca_province` DB column, `FormationOrder.state_code` parameter. --- ## Architecture ### Product Matrix | Product | Price | Pipeline | Compliance Entries | Maintenance | |---------|-------|----------|-------------------|-------------| | US Formation Basic | $179 + state fees | US state adapter | 1-3 (annual report, franchise tax) | $179/yr bundle | | US Formation Complete | $399 + state fees | US state adapter | 2-4 (+ RA renewal) | $179/yr bundle | | CA Formation | C$449 + gov fees + AMB | CanadianIncorporationHandler | 7-8 (annual return + tax + AMB) | $179/yr bundle | | CRTC Carrier Package | $3,899 + gov fees | CanadaCRTCHandler (composes CanadianIncorporationHandler) | 15-17 (+ telecom obligations) | $349/yr | ### Pipeline Decomposition The CRTC pipeline is currently monolithic. We decompose it into shared incorporation steps and telecom-only steps. **Shared steps** (used by BOTH formation-only AND CRTC): | Step | Action | Formation Basic | Formation Complete | CRTC | |------|--------|----|----|----| | AMB mailbox setup | Registered office | No | Yes | Yes | | Name reservation | Registry filing | If named | If named | If named | | Incorporation | COLIN / OBR | Yes | Yes | Yes | | Trade name registration | Registry filing | If requested | If requested | If requested | | CRA Business Number | BN from CRA | Add-on ($49) | Add-on ($49) | No (not needed) | | Organizational minutes | Document gen | No | Yes | Yes | | Corporate binder | PDF compilation | Digital only | Yes | Yes | | Delivery email | Send docs | Yes | Yes | Yes | | Compliance calendar | Create entries | Yes (corporate) | Yes (corporate + AMB) | Yes (corporate + telecom) | **CRTC-only steps** (NOT in formation pipeline): | Step | Action | |------|--------| | DID provisioning | Canadian phone number via Flowroute | | .ca domain + HestiaCP | Domain, email, 14 mailboxes, hosting | | CRTC letter generation | DOCX template -> MinIO -> DocServer PDF | | eSign | Client signs CRTC letter in portal | | CRTC submission | Mail letter to Secretary General | | BITS registration | GCKey provisioning + BITS filing | | CCTS membership | Registration + client obligations email | | GCKey provisioning | Government credential for CRTC filings | | Telecom compliance entries | CRTC, BITS, CCTS, ATS surveys, DID/domain/mailbox renewals | ### ProvinceConfig Protocol ```python class ProvinceConfig(TypedDict): # Identity code: str # "BC", "ON", "AB", "QC", ... name: str # "British Columbia", "Ontario" abbreviation: str # "B.C.", "Ont." # Corporate law act_name: str # "BC Business Corporations Act", "OBCA" legal_endings: list[str] # Province-specific corporate name suffixes numbered_entity_template: str # "{number} B.C. Ltd.", "{number} Ontario Inc." # Portal portal_name: str # "BC Corporate Online", "Ontario Business Registry" portal_url: str requires_login: bool # False (BC), True (ON) selectors: dict # Playwright CSS selectors for portal # Fees (CAD cents) incorporation_fee_cad: int # 35000 (BC), 36000 (ON) annual_return_fee_cad: int # 4271 (BC), 2500 (ON) annual_return_name: str # "Annual Report" (BC), "Annual Return" (ON) name_reservation_fee_cad: int # Tax sales_tax: dict # {type: "GST+PST", gst: 5, pst: 7} or {type: "HST", rate: 13} workers_comp_name: str # "WorkSafeBC", "WSIB" # Infrastructure area_codes: list[str] # DID area codes for Flowroute default_city: str # "Vancouver", "Toronto" timezone: str # "America/Vancouver", "America/Toronto" amb_scrape_slug: str # "british-columbia", "ontario" registered_office_addresses: list # Compliance corporate_obligations: list # Province-specific tax/filing requirements supports_formation_only: bool # Whether we offer standalone formation cra_bn_automatable: bool # Whether BN registration can be automated # Templates articles_template: str # Path to province-specific Articles template minutes_template: str # Path to organizational minutes template ``` ### Universal Compliance Calendar A shared module called by ALL pipelines: ```python # scripts/formation/compliance.py def create_compliance_entries( order_type: str, # "crtc" | "ca_formation" | "us_formation" jurisdiction: str, # "BC", "ON", "WY", "DE", etc. country: str, # "CA" | "US" order_reference: str, # Sales Order or order number entity_name: str, incorporation_date: date, add_ons: dict, # {ra: bool, amb: bool, domain: bool, did: bool, ein: bool} ) -> list[dict]: """Create compliance calendar entries based on order type and jurisdiction.""" ``` The function reads obligations from province/state config and filters by order_type. The `renewal_worker.py` already handles the lifecycle regardless of origin. ### File Structure ``` scripts/formation/ province_config.py # ProvinceConfig TypedDict + get_province(code) compliance.py # NEW: Universal create_compliance_entries() canadian_incorporation.py # NEW: CanadianIncorporationHandler (shared steps) base.py # StatePortal base class (existing) states/ __init__.py # State registry (add CA provinces) bc/config.py # BC ProvinceConfig (refactored) bc/adapter.py # BCPortal(StatePortal) (existing) on/__init__.py # NEW on/config.py # NEW: Ontario ProvinceConfig on/adapter.py # NEW: ONPortal(StatePortal) wy/config.py # WY config (add compliance obligations) ... (50 more US states) scripts/workers/ services/ canada_crtc.py # MODIFIED: Composes with CanadianIncorporationHandler cra_bn.py # NEW: CRA Business Number registration flowroute.py # MODIFIED: provision_canadian_did(province) renewal_worker.py # Unchanged (already handles any compliance entry) amb_location_scraper.py # MODIFIED: Multi-province scraping ``` --- ## Pricing ### CRTC Carrier Package (unchanged) | Item | Price | |------|-------| | CRTC Telecom Registration (one-time) | $3,899 USD | | Annual Maintenance & Compliance | $349/yr | | Consulting | $75/hr | | Government fees | Passed through at cost (province-specific) | ### Canadian Formation (new) | Item | Price | Notes | |------|-------|-------| | Canadian Formation | C$449 + gov fees | Incorporation + org minutes + binder + compliance calendar. AMB mailbox billed separately (annual, ~C$96-240/yr depending on location). | | Government fees | BC ~C$350, ON ~C$360 | Passed through (BoC rate + 10% buffer) | | Add-on: CRA BN | $49 | Business Number registration with CRA | | Add-on: Named company | +gov fee | Name reservation (BC: C$30, ON: varies) | | Free DID | Included | With formation + RA renewal (stub — not yet active) | ### Maintenance Bundles (new) | Bundle | Price | Includes | |--------|-------|---------| | US Formation Maintenance | $179/yr | Annual report filing ($99 value) + RA renewal ($99 value) | | CA Formation Maintenance | $179/yr | Annual return filing ($99 value) + AMB/RA renewal ($99 value) | | CRTC Maintenance (existing) | $349/yr | All of CA maintenance + CRTC + CCTS + domain/email + DID | ### ERPNext Items Needed | Item Code | Name | Rate (USD) | Used By | |-----------|------|-----------|---------| | `CRTC-MAINT-ANNUAL` | CRTC Annual Maintenance | $349/yr | CRTC orders | | `FORMATION-MAINT-US` | US Formation Maintenance Bundle | $179/yr | US formation (Complete) | | `FORMATION-MAINT-CA` | CA Formation Maintenance Bundle | $179/yr | CA formation | | `RA-RENEWAL` | Registered Agent Renewal | $99/yr ($49 WY) | All formations (if RA) | | `FREE-DID` | Free DID (with formation + RA) | $0 | Stub — not yet active | | `ANNUAL-REPORT` | Annual Report/Return Filing | $99/yr | All formations | | `CRA-BN` | CRA Business Number Registration | $49 | CA formation add-on | | `MAILBOX-RENEWAL` | Mailbox Renewal (AMB) | $199/yr | CRTC + CA Complete | | `DOMAIN-RENEWAL-CA` | .ca Domain + Hosting Renewal | $25/yr | CRTC only | --- ## Phases ### Phase 0: OBR + CRA Playwright Recon **Model: Opus 4.6** — Complex unknown-portal reconnaissance requiring judgment. **0a. Ontario Business Registry recon:** 1. Navigate to `business.ontario.ca`, map account creation flow 2. Walk through incorporation wizard — record form fields, selectors, inputs 3. Document: login method, MFA, CAPTCHA, bot detection 4. Record: payment step (credit card selectors) 5. Test if one house account can file multiple incorporations 6. Record: name search flow (part of wizard or separate?) 7. Output: selector map + screenshots saved to MinIO **0b. CRA Business Number recon:** 1. Navigate to CRA Business Registration Online 2. Map the BN registration form fields 3. Document: does it require an existing corp number? Identity verification? 4. Can we register using our house account or does the client need to do it? 5. Determine if automatable or admin ToDo **Files:** - `scripts/recon_obr.py` — NEW: OBR Playwright recon script - `scripts/recon_cra_bn.py` — NEW: CRA BN recon script **Effort:** 2-2.5 hours --- ### Phase 1: ProvinceConfig + Compliance Module Design **Model: Opus 4.6** — Architecture with future-proofing for any province and all order types. **Files:** - `scripts/formation/province_config.py` — NEW: ProvinceConfig TypedDict + `get_province(code)` registry - `scripts/formation/compliance.py` — NEW: `create_compliance_entries()` universal function - `scripts/formation/states/bc/config.py` — MODIFY: conform to ProvinceConfig - `scripts/formation/states/__init__.py` — MODIFY: register CA provinces, add compliance fields to US states The compliance module design must handle: - CRTC orders: 15-17 entries (telecom + corporate + renewals) - CA formation: 6-8 entries (corporate obligations only) - US formation: 1-4 entries (annual report + RA + franchise tax) - Filtering by order type and purchased add-ons - Province/state-specific deadlines, fees, and filing names **Effort:** 3-4 hours --- ### Phase 2: Database Migrations **Model: Sonnet 4.6** — Mechanical SQL. **Files:** - `api/src/migrations/036_multi_province.sql` — NEW ```sql -- === CRTC table changes === ALTER TABLE canada_crtc_orders ADD COLUMN province TEXT NOT NULL DEFAULT 'BC'; ALTER TABLE canada_crtc_orders RENAME COLUMN bc_incorporation_number TO incorporation_number; CREATE INDEX idx_crtc_orders_province ON canada_crtc_orders(province); -- === Formation table changes === ALTER TABLE formation_orders ADD COLUMN country CHAR(2) NOT NULL DEFAULT 'US'; ALTER TABLE formation_orders DROP CONSTRAINT formation_orders_entity_type_check; ALTER TABLE formation_orders ADD CONSTRAINT formation_orders_entity_type_check CHECK (entity_type IN ('llc', 'corporation', 's_corp', 'ltd', 'inc', 'corp')); CREATE INDEX idx_formation_orders_country ON formation_orders(country); ``` **Effort:** 45 minutes --- ### Phase 3: Ontario Adapter + Infrastructure + Shared Handlers **3a. Ontario config** — **Sonnet 4.6** `scripts/formation/states/on/config.py` — Full Ontario ProvinceConfig: - OBR URLs, fees (C$360 incorp, C$25 annual return) - Legal endings: Inc., Corp., Ltd., Ltee, Cie (+ French equivalents) - Area codes: 416/647/437/905/289/365/519/613/705 - HST 13%, WSIB, Toronto default - Selectors from Phase 0 recon - Corporate obligations (Ontario Annual Return, T2, GST/HST, WSIB — no PST) **3b. Ontario adapter** — **Sonnet 4.6** `scripts/formation/states/on/adapter.py` — `ONPortal(StatePortal)`: - `search_name()`: OBR free search - `file_incorporation()`: initially admin ToDo, OBR automation stubbed - `file_llc()` / `file_corporation()`: route to `file_incorporation()` (Canadian entity types) **3c. AMB scraper extension** — **Sonnet 4.6** `scripts/workers/amb_location_scraper.py`: - Parameterize province in scrape function - Add Ontario scraping (Toronto, Mississauga, Ottawa, Hamilton, etc.) - Run for both BC + ON in daily cron **3d. Flowroute DID generalization** — **Sonnet 4.6** `scripts/workers/services/flowroute.py`: - Rename `provision_bc_did()` -> `provision_canadian_did(province)` - Area code mapping: BC=[604,778,236,250], ON=[416,647,437,905,289,365] **3e. CanadianIncorporationHandler** — **Opus 4.6** `scripts/formation/canadian_incorporation.py` — NEW: - Shared incorporation pipeline used by BOTH formation-only AND CRTC - Steps: AMB setup (if Complete), name reservation (if named), incorporation, trade name (if requested), CRA BN (if add-on), binder compilation, delivery email, compliance calendar creation - `CanadaCRTCHandler` composes with this (calls it for incorporation, then continues with telecom steps) - Formation-only orders dispatch here directly from the job server **3f. CRA BN registration** — **Sonnet 4.6** `scripts/workers/services/cra_bn.py` — NEW: - Initially stubbed as admin ToDo - CRA Business Number registration automation added after Phase 0b recon **3g. Universal compliance creator** — **Opus 4.6** `scripts/formation/compliance.py` — NEW: - `create_compliance_entries()` function - Reads obligations from province/state config - Filters by order_type and purchased add-ons - Creates entries in ERPNext Compliance Calendar DocType - Called by: CanadianIncorporationHandler, CanadaCRTCHandler, US formation job handler **Effort:** 7-8 hours total (3a-d: 3-4 hrs, 3e: 2-3 hrs, 3f: 30 min, 3g: 1-2 hrs) --- ### Phase 4: Service Page Province Comparison Table + FAQ **Model: Sonnet 4.6** (table HTML) + **Opus 4.6** (FAQ) **4a. Province comparison table** (Sonnet) — Add to CRTC service page between the corporate tax table (line ~1205) and M&A section (line ~1262): New table: "Choose your province: incorporation comparison" | Factor | British Columbia | Ontario | Alberta* | Federal (CBCA)* | |--------|-----------------|---------|----------|----------------| | Resident director | No | No | No | 25% Canadian | | Incorporation fee | ~C$350 | ~C$360 | ~C$300 | ~C$200 | | Annual return/report | C$42.71/yr | C$25/yr | C$20/yr | C$12/yr | | Portal | Anonymous | Requires account | Requires account | Requires account | | Processing time | 1-2 days | Same day | 1-2 days | 1-5 days | | Numbered format | 1234567 B.C. Ltd. | 1234567 Ontario Inc. | 1234567 Alberta Ltd. | 1234567 Canada Inc. | | Sales tax | GST+PST 12% | HST 13% | GST 5% | Depends | | Small biz tax rate | 11% | 12.2% | 11% | Depends | | Language | English | English/French | English | English/French | | Best for | Pacific gateway | Largest market | Low cost | Multi-province | *Alberta and Federal shown as "Coming soon". **4b. FAQ rewrite** (Opus) — In `canada-crtc.json`: - Rewrite Q23: "Which province should I choose?" — BC vs ON pros/cons - New FAQ: "Can I switch provinces later?" — extra-provincial registration **Effort:** 1-2 hours --- ### Phase 5: Order Form Multi-Province **5a. CRTC order form** — **Opus 4.6** Modify `site/src/pages/order/canada-crtc.astro` (2,550 lines): - Province selector at Step 1 (radio: BC | Ontario, dev-only gate) - `PROVINCE_DATA` JS object + `setProvince(code)` function - Swaps: entity format, legal endings, fees, AMB locations, DID area codes, act references - `province` hidden field in form submission **5b. Formation page backend wiring** — **Sonnet 4.6** The frontend already works for Canada. Backend changes only: - Ensure the CRTC callout remains (separate flows) - Verify entity type mapping sends correct values (ltd/inc/corp) - Verify province fee display works with API **Effort:** 4-5 hours total (5a: 3-4 hrs, 5b: 1 hr) --- ### Phase 6: API Routes + Pipeline Refactors **6a. CRTC API route** — **Sonnet 4.6** `api/src/routes/canada-crtc.ts`: - Accept `province` parameter - Province-specific fee calculation via lookup - Dev gate: reject ON if `NODE_ENV=production` - Store province in `canada_crtc_orders` **6b. CRTC pipeline refactor** — **Opus 4.6** `scripts/workers/services/canada_crtc.py` (2,179 lines): - Constructor accepts `province` from Sales Order - Composes with `CanadianIncorporationHandler` for incorporation steps - Dynamic province adapter: `get_province(code)` replaces hardcoded `BCPortal` - All messages use `province_config["name"]` instead of "BC" - Compliance entries dispatched to universal `create_compliance_entries()` **6c. Formation API route** — **Sonnet 4.6** `api/src/routes/formations.ts`: - Accept `country` parameter ("US" default, "CA") - Validate Canadian entity types (ltd, inc, corp) when country=CA - Province-specific fee calculation (CAD->USD via FX) - Dev gate: reject country=CA if `NODE_ENV=production` - Dispatch to `CanadianIncorporationHandler` job for CA orders - ERPNext Formation Order: add Ltd./Inc./Corp. to entity_type Select **Effort:** 5.5-6.5 hours total (6a: 1 hr, 6b: 3-4 hrs, 6c: 1.5-2 hrs) --- ### Phase 7: Compliance Configs — All Jurisdictions **Model: Sonnet 4.6** — Data entry into established config structure. **7a. Canadian province compliance configs:** BC corporation (non-telecom): | Entry | Fee | Deadline | Billable | |-------|-----|----------|----------| | BC Annual Report | C$42.71 | 2 months after anniversary | Yes ($99) | | T2 Corporate Income Tax | $0 (accountant) | June 30 | No | | Corporate Tax Payment | $0 (accountant) | March 31 | No | | GST/HST Return | $0 (accountant) | March 31 (if registered) | No | | T4/T4A Slips | $0 (accountant) | February 28 (if employees) | No | | BC PST | $0 (accountant) | Volume-based (if applicable) | No | | WorkSafeBC | $0 | March 1 (if BC employees) | No | | AMB Renewal | ~C$199/yr | Anniversary | Yes ($99) | Ontario corporation (non-telecom): | Entry | Fee | Deadline | Billable | |-------|-----|----------|----------| | Ontario Annual Return | C$25 | 6 months after anniversary | Yes ($99) | | T2 Corporate Income Tax | $0 (accountant) | June 30 | No | | Corporate Tax Payment | $0 (accountant) | March 31 | No | | HST Return | $0 (accountant) | March 31 (HST 13% combined) | No | | T4/T4A Slips | $0 (accountant) | February 28 (if employees) | No | | WSIB | $0 | Quarterly (if ON employees) | No | | AMB Renewal | ~C$96/yr | Anniversary | Yes ($99) | Note: Ontario has fewer entries (no separate PST — HST is combined). **7b. US state compliance configs — all 51 jurisdictions:** Add `compliance_obligations` to each state config in `scripts/formation/states/`. Data sourced from `docs/state-annual-fees-complete.md`. **States with annual report fees ($7-$810):** | State | Code | Annual Fee | Deadline | Filing Name | |-------|------|-----------|----------|-------------| | California | CA | $810 | Apr 15 (1st year: 90 days) | Statement of Information + Franchise Tax | | Massachusetts | MA | $500 | Anniversary | Annual Report | | Nevada | NV | $350 | Anniversary | Annual List + Business License | | Delaware | DE | $300 | Jun 1 | Franchise Tax | | Maryland | MD | $300 | Apr 15 | Annual Report + PPT Return | | Tennessee | TN | $300 | Anniversary (1st quarter) | Annual Report | | North Carolina | NC | $200 | Apr 15 | Annual Report | | DC | DC | $150/yr | Anniversary (biennial $300) | Biennial Report | | Arkansas | AR | $150 | May 1 | Franchise Tax Report | | Florida | FL | $138.75 | May 1 | Annual Report | | New Hampshire | NH | $100 | Apr 1 | Annual Report | | Oregon | OR | $100 | Anniversary | Annual Report | | Alaska | AK | $50/yr | Jan 2 (biennial $100) | Biennial Report | | Maine | ME | $85 | Jun 1 | Annual Report | | Connecticut | CT | $80 | Anniversary | Annual Report | | Illinois | IL | $75 | Anniversary month | Annual Report | | New Jersey | NJ | $75 | Anniversary month | Annual Report | | Georgia | GA | $60 | Apr 1 | Annual Registration | | Washington | WA | $60 | Anniversary | Annual Report | | Wyoming | WY | $60 min | Anniversary month | Annual Report | | South Dakota | SD | $55 | Anniversary month | Annual Report | | Alabama | AL | $50 min | Apr 15 | Business Privilege Tax | | Kansas | KS | $50 | Apr 15 | Annual Report | | North Dakota | ND | $50 | Nov 15 | Annual Report | | Rhode Island | RI | $50 | Anniversary | Annual Report | | Virginia | VA | $50 | Anniversary month (last day) | Annual Registration | | Vermont | VT | $45 | Anniversary quarter | Annual Report | | Hawaii | HI | $35 | Anniversary | Annual Report + GET License | | Louisiana | LA | $35 | Anniversary | Annual Report | | Colorado | CO | $25 | Anniversary month | Periodic Report | | Michigan | MI | $25 | Feb 15 | Annual Statement | | Oklahoma | OK | $25 | Anniversary | Annual Certificate | | West Virginia | WV | $25 | Jul 1 | Annual Report | | Wisconsin | WI | $25 | Anniversary quarter | Annual Report | | Montana | MT | $20 | Apr 15 | Annual Report | | Utah | UT | $18 | Anniversary | Annual Renewal | | Indiana | IN | $15/yr | Anniversary month (biennial $30) | Business Entity Report | | Iowa | IA | $15/yr | Apr 1 odd years (biennial $30) | Biennial Report | | Kentucky | KY | $15 | Jun 30 | Annual Report | | Pennsylvania | PA | $7 | Anniversary (new as of 2025) | Annual Report | | New York | NY | $4.50/yr | Anniversary (biennial $9) | Biennial Statement | | Nebraska | NE | $6.50/yr | Apr 1 odd years (biennial $13) | Biennial Report | **States with $0 annual fees (9 states):** | State | Code | Notes | |-------|------|-------| | Arizona | AZ | No annual report required, no fee | | Idaho | ID | Annual report required but $0 fee | | Minnesota | MN | Annual renewal required but $0 fee | | Mississippi | MS | No annual report ($0); privilege tax only for S-Corps | | Missouri | MO | No annual report required, no fee | | New Mexico | NM | No annual report required, no fee | | Ohio | OH | No annual report; Commercial Activity Tax only if revenue >$150K | | South Carolina | SC | No annual report unless LLC elects S-Corp treatment | | Texas | TX | Public Information Report ($0); franchise tax only if revenue >$2.47M | **Note:** Even $0-fee states get a compliance calendar entry as a REMINDER — the client may still need to file a $0 report to maintain good standing (ID, MN, TX). **Franchise tax states (additional entry beyond annual report):** | State | Franchise Tax | Threshold | Deadline | |-------|--------------|-----------|----------| | California | $800/yr minimum | All LLCs | Apr 15 | | Delaware | $300/yr minimum | All LLCs | Jun 1 | | Texas | 0.375%/0.75% of revenue | >$2.47M revenue | May 15 | | Tennessee | $300/member min | All LLCs | Anniversary | | Alabama | $0.25 per $1K net worth | Min $50, max $15K | Apr 15 | **Effort:** 3-4 hours total (7a: 1 hr, 7b: 2-3 hrs) --- ### Phase 8: Dev Stack E2E Tests **Model: Debugger agent** **8a. Multi-province CRTC test:** 1. Verify province selector shows BC + ON on dev 2. Create Ontario CRTC order, verify fees adjust 3. Verify DID search returns 416/647 numbers 4. Verify mailbox picker shows Toronto locations 5. Verify pipeline runs with ON adapter 6. Verify compliance calendar: 15-17 ON entries (WSIB not WorkSafeBC, no PST, HST) 7. Verify emails use "Ontario" language 8. Regression: verify BC orders still work **8b. Canadian formation-only test:** 1. Select Canada + Ontario on formation page 2. Verify entity types show Ltd./Inc./Corp. 3. Verify fees show CAD + USD 4. Submit formation-only order 5. Verify CanadianIncorporationHandler dispatched (no telecom steps) 6. Verify compliance calendar: 6-8 ON entries (corporate only, no telecom) 7. Verify binder compilation works without CRTC letter **8c. US formation compliance test:** 1. Create a WY formation order 2. Verify compliance calendar entry created: WY Annual Report ($60, anniversary month) 3. Create a DE formation order (with RA) 4. Verify entries: DE Franchise Tax ($300, Jun 1) + RA renewal ($99) 5. Verify renewal_worker processes these entries correctly **Effort:** 2-3 hours --- ## Model Assignment Summary | Model | Phases | Why | |-------|--------|-----| | **Opus 4.6** | 0, 1, 3e, 3g, 4b, 5a, 6b | Architecture, unknown portal recon, pipeline decomposition, complex refactoring, persuasive content | | **Sonnet 4.6** | 2, 3a-d, 3f, 4a, 5b, 6a, 6c, 7a, 7b | Mechanical edits, known patterns, SQL, HTML tables, data entry, config population | | **Debugger** | 8 | Build verification, regression testing, E2E validation | --- ## Effort Summary | Phase | Effort | Model | |-------|--------|-------| | Phase 0: OBR + CRA Recon | 2-2.5 hrs | Opus | | Phase 1: ProvinceConfig + compliance design | 3-4 hrs | Opus | | Phase 2: DB Migrations | 45 min | Sonnet | | Phase 3a-d: ON adapter + AMB + DID | 3-4 hrs | Sonnet | | Phase 3e: CanadianIncorporationHandler | 2-3 hrs | Opus | | Phase 3f: CRA BN stub | 30 min | Sonnet | | Phase 3g: Universal compliance creator | 1-2 hrs | Opus | | Phase 4: Service page table + FAQ | 1-2 hrs | Sonnet + Opus | | Phase 5a: CRTC order form | 3-4 hrs | Opus | | Phase 5b: Formation page wiring | 1 hr | Sonnet | | Phase 6a: CRTC API route | 1 hr | Sonnet | | Phase 6b: CRTC pipeline refactor | 3-4 hrs | Opus | | Phase 6c: Formation API route | 1.5-2 hrs | Sonnet | | Phase 7a: CA province compliance configs | 1 hr | Sonnet | | Phase 7b: US state compliance (51 jurisdictions) | 2-3 hrs | Sonnet | | Phase 8: Dev E2E tests | 2-3 hrs | Debugger | | **Total** | **28-36 hours** | **5-6 sessions** | Parallelizable: Phases 0, 1, 2, 4, and 7b have no dependencies on each other. Phase 4 (service page table) can ship to production immediately — no backend needed. --- ## Files Changed Summary ### New Files (10) | File | Phase | Purpose | |------|-------|---------| | `scripts/formation/province_config.py` | 1 | ProvinceConfig TypedDict + registry | | `scripts/formation/compliance.py` | 3g | Universal compliance entry creator | | `scripts/formation/canadian_incorporation.py` | 3e | Shared Canadian incorporation handler | | `scripts/formation/states/on/__init__.py` | 3a | Ontario package init | | `scripts/formation/states/on/config.py` | 3a | Ontario ProvinceConfig | | `scripts/formation/states/on/adapter.py` | 3b | ONPortal(StatePortal) | | `scripts/workers/services/cra_bn.py` | 3f | CRA Business Number registration | | `scripts/recon_obr.py` | 0 | OBR Playwright recon (disposable) | | `scripts/recon_cra_bn.py` | 0 | CRA BN recon (disposable) | | `api/src/migrations/036_multi_province.sql` | 2 | Province + country columns | ### Modified Files (16) | File | Phase | Change | |------|-------|--------| | `site/src/pages/services/telecom/canada-crtc.astro` | 4a | Province comparison table | | `site/src/pages/order/canada-crtc.astro` | 5a | Province selector + dynamic content | | `site/src/content/services/canada-crtc.json` | 4b | FAQ rewrite | | `api/src/routes/canada-crtc.ts` | 6a | Accept province parameter | | `api/src/routes/formations.ts` | 6c | Accept CA provinces + entity types | | `scripts/workers/services/canada_crtc.py` | 6b | Compose with CanadianIncorporationHandler | | `scripts/workers/services/flowroute.py` | 3d | `provision_canadian_did(province)` | | `scripts/workers/amb_location_scraper.py` | 3c | Multi-province scraping | | `scripts/workers/job_server.py` | 3e | Add CA formation job handlers | | `scripts/formation/states/bc/config.py` | 1 | Conform to ProvinceConfig | | `scripts/formation/states/__init__.py` | 1 | Register CA provinces | | `scripts/formation/states/*/config.py` (51 files) | 7b | Add compliance_obligations to each US state | | `erpnext/doctypes/formation_order/formation_order.json` | 6c | Add Canadian entity types | | `docs/go-live-todo.md` | — | Add multi-province + formation items | | `docs/product-facts.md` | — | Add CA formation product | | `docs/billing.md` | — | Add maintenance bundles | --- ## AMB Ontario Locations From Anytime Mailbox Ontario page (30+ locations): | City | Address | Starting Price | |------|---------|---------------| | Toronto - Dundas St | 2967 Dundas St. W., Toronto, ON M6P 1Z2 | C$7.99/mo | | Toronto - Davenport Rd | 1463 Davenport Rd, Toronto, ON M6H 2H6 | C$13.99/mo | | Mississauga | 1065 Canadian Pl, Mississauga, ON L4W 0C2 | C$8.99/mo | | + 25 more cities | Acton, Ajax, Bolton, Brampton, Cambridge, Cornwall, Etobicoke, Georgetown, Hamilton, Markham, North York, Oakville, Ottawa, etc. | Varies | **Recommendation:** Default to a downtown Toronto location for prestige. --- ## Open Questions | Question | Context | Decision Needed | |----------|---------|-----------------| | OBR house account viability? | Phase 0 will answer. If one account can't file multiple corps, fall back to admin ToDo. | After Phase 0 | | CRA BN automation viability? | Phase 0b will answer. If not automatable, admin ToDo with instructions. | After Phase 0 | | Alberta / Federal — when? | Architecture supports from day one. Add when demand warrants. | Post-launch | | Ontario AMB default location? | Toronto has 6+ locations. Downtown for prestige? | Phase 3 | | ON numbered entity suffix? | "Ontario Inc." or "Ontario Ltd."? Verify against OBR. | Phase 0 | | French-language support? | OBCA allows French endings (Ltee, Cie). Offer on form? | Phase 5 | | US state compliance — all at once or incremental? | 51 configs is a lot. Could do top 10 first. Decision: all 51 now. | Phase 7b | | Formation maintenance auto-enrollment? | Auto-enroll in $179/yr bundle? Or opt-in? | Phase 6c |