Includes: API (Express/TypeScript), Astro site, Python workers, document generators, FCC compliance tools, Canada CRTC formation, Ansible infrastructure, and deployment scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
34 KiB
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:
- Multi-province CRTC — Extend the $3,899 CRTC Carrier Package from BC-only to multi-province. Ontario first; architecture supports any Canadian province.
- Standalone Canadian formation — Offer Canadian province incorporation (C$449
- gov fees) on the existing formation page WITHOUT telecom registration. Separate flow from CRTC.
- 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_PROVINCESarray 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
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:
# 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:
- Navigate to
business.ontario.ca, map account creation flow - Walk through incorporation wizard — record form fields, selectors, inputs
- Document: login method, MFA, CAPTCHA, bot detection
- Record: payment step (credit card selectors)
- Test if one house account can file multiple incorporations
- Record: name search flow (part of wizard or separate?)
- Output: selector map + screenshots saved to MinIO
0b. CRA Business Number recon:
- Navigate to CRA Business Registration Online
- Map the BN registration form fields
- Document: does it require an existing corp number? Identity verification?
- Can we register using our house account or does the client need to do it?
- Determine if automatable or admin ToDo
Files:
scripts/recon_obr.py— NEW: OBR Playwright recon scriptscripts/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)registryscripts/formation/compliance.py— NEW:create_compliance_entries()universal functionscripts/formation/states/bc/config.py— MODIFY: conform to ProvinceConfigscripts/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
-- === 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 searchfile_incorporation(): initially admin ToDo, OBR automation stubbedfile_llc()/file_corporation(): route tofile_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
CanadaCRTCHandlercomposes 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_DATAJS object +setProvince(code)function- Swaps: entity format, legal endings, fees, AMB locations, DID area codes, act references
provincehidden 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
provinceparameter - 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
provincefrom Sales Order - Composes with
CanadianIncorporationHandlerfor incorporation steps - Dynamic province adapter:
get_province(code)replaces hardcodedBCPortal - 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
countryparameter ("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
CanadianIncorporationHandlerjob 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:
- Verify province selector shows BC + ON on dev
- Create Ontario CRTC order, verify fees adjust
- Verify DID search returns 416/647 numbers
- Verify mailbox picker shows Toronto locations
- Verify pipeline runs with ON adapter
- Verify compliance calendar: 15-17 ON entries (WSIB not WorkSafeBC, no PST, HST)
- Verify emails use "Ontario" language
- Regression: verify BC orders still work
8b. Canadian formation-only test:
- Select Canada + Ontario on formation page
- Verify entity types show Ltd./Inc./Corp.
- Verify fees show CAD + USD
- Submit formation-only order
- Verify CanadianIncorporationHandler dispatched (no telecom steps)
- Verify compliance calendar: 6-8 ON entries (corporate only, no telecom)
- Verify binder compilation works without CRTC letter
8c. US formation compliance test:
- Create a WY formation order
- Verify compliance calendar entry created: WY Annual Report ($60, anniversary month)
- Create a DE formation order (with RA)
- Verify entries: DE Franchise Tax ($300, Jun 1) + RA renewal ($99)
- 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 |