#!/usr/bin/env python3 """ Build the Canadian accountability graph for one bill, walked end to end. Schema is the full segment-12 vocabulary from followthemoney.felineunion.org: 18 node types, 14 edge types. Depth-one content: Bill C-44 (42-1). Every node and every edge carries `src` (a citation id). Nothing enters the graph without one. Node types with no records for this bill are emitted with count 0 rather than omitted, so the gaps are visible. """ import json, os, sys, datetime HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) RAW = os.path.join(HERE, "raw") NODE_TYPES = ["bill","statute","regulation","department","minister","official", "appropriation","program","contract","corporation","subsidiary", "director","shareholder","lobbyist","financial_institution", "pension_fund","crown_corporation","project"] EDGE_TYPES = ["amended","repealed","authorized","funded","contracted","subcontracted", "owned","financed","guaranteed","lobbied","employed","regulated", "transferred","invested"] # ---------------------------------------------------------------- citations SOURCES = { "legisinfo": { "title": "LEGISinfo — Bill C-44 (42-1), structured record", "publisher": "Parliament of Canada", "url": "https://www.parl.ca/legisinfo/en/bill/42-1/c-44", "data_url": "https://www.parl.ca/legisinfo/en/bill/42-1/c-44/json", "kind": "primary", "machine_read": True}, "sc2017c20": { "title": "Statutes of Canada 2017, c. 20 — table of provisions", "publisher": "Justice Laws Website", "url": "https://laws-lois.justice.gc.ca/eng/AnnualStatutes/2017_20/page-1.html", "kind": "primary", "machine_read": True}, "cibact": { "title": "Canada Infrastructure Bank Act (S.C. 2017, c. 20, s. 403)", "publisher": "Justice Laws Website", "url": "https://laws-lois.justice.gc.ca/eng/acts/C-6.18/FullText.html", "kind": "primary"}, "si201740": { "title": "Order Designating the Minister of Infrastructure, Communities and " "Intergovernmental Affairs for the purposes of the Act (SI-2017-40)", "publisher": "Justice Laws Website", "url": "https://laws-lois.justice.gc.ca/eng/regulations/SI-2017-40/FullText.html", "kind": "primary"}, "pbo2025": { "title": "Update on the Spending Outlook of the Canada Infrastructure Bank, 10 July 2025", "publisher": "Office of the Parliamentary Budget Officer", "url": "https://distribution-a617274656661637473.pbo-dpb.ca/b053bf2c36478fdeea90a43530335af142e709a6bd74ec2a3543562434d89f76", "kind": "primary", "machine_read": True}, "oag2021r9": { "title": "2021 Reports of the Auditor General — Report 9, Investing in Canada Plan", "publisher": "Office of the Auditor General of Canada", "url": "https://www.oag-bvg.gc.ca/internet/English/parl_oag_202103_04_e_43786.html", "kind": "primary"}, "tran44r3": { "title": "The Canada Infrastructure Bank — Report 3, Standing Committee on Transport, " "Infrastructure and Communities (44-1)", "publisher": "House of Commons", "url": "https://www.ourcommons.ca/Content/Committee/441/TRAN/Reports/RP11664128/tranrp03/tranrp03-e.pdf", "kind": "primary"}, "cibrem": { "title": "CIB invests $1.28B in a 15-year loan for the REM", "publisher": "Canada Infrastructure Bank", "url": "https://cib-bic.ca/en/medias/articles/cib-invests-in-reseau-express-metropolitain-project-with-1-28-billion-15-year-loan/", "kind": "primary"}, "caisserem": { "title": "Canada Infrastructure Bank invests in Réseau express métropolitain project " "with $1.28 billion, 15-year loan", "publisher": "CDPQ / La Caisse", "url": "https://www.lacaisse.com/en/news/pressreleases/canada-infrastructure-bank-invests-reseau-express-metropolitain-project-128", "kind": "primary"}, "cibchair2020": { "title": "Changes in leadership at the Canada Infrastructure Bank, 3 April 2020", "publisher": "Infrastructure Canada", "url": "https://www.canada.ca/en/office-infrastructure/news/2020/04/changes-in-leadership-at-the-canadian-infrastructure-bank.html", "kind": "primary"}, "pmsabia": { "title": "Michael Sabia — backgrounder, 7 December 2020", "publisher": "Office of the Prime Minister", "url": "https://www.pm.gc.ca/en/news/backgrounders/2020/12/07/michael-sabia", "kind": "primary"}, "acegrowth": { "title": "Morneau's economic growth council calls for national infrastructure bank, " "20 October 2016", "publisher": "The Globe and Mail", "url": "https://www.theglobeandmail.com/news/politics/morneaus-economic-growth-council-calls-for-national-infrastructure-bank/article32461740/", "kind": "secondary", "note": "Reports the Advisory Council on Economic Growth's first-wave recommendation " "and names council members with their employers."}, "sabiadm": { "title": "Veteran executive Michael Sabia named next deputy minister of Finance", "publisher": "CBC News", "url": "https://www.cbc.ca/news/politics/michael-sabia-finance-1.5831207", "kind": "secondary", "note": "Appointment announced 10 December 2020, effective 14 December 2020."}, "oclcomms": { "title": "Monthly Communication Reports (open data)", "publisher": "Office of the Commissioner of Lobbying of Canada", "url": "https://open.canada.ca/data/en/dataset/a34eb330-7136-4f5e-9f5f-3ba41df58b06", "kind": "primary", "note": "Dataset located and catalogued. Bulk CSV retrieval blocked — see blocked joins."}, "eccontrib": { "title": "Contributions to all political entities, as filed (open data)", "publisher": "Elections Canada", "url": "https://open.canada.ca/data/dataset/6495ea57-3824-48f0-a2b2-88477122a286", "kind": "primary", "note": "Not joined for this bill — no federal corporate or union donations exist to join."}, } nodes, edges = [], [] def N(nid, ntype, label, src, **kw): assert ntype in NODE_TYPES, ntype assert src in SOURCES or all(s in SOURCES for s in src), src n = {"id": nid, "type": ntype, "label": label, "src": [src] if isinstance(src, str) else list(src)} n.update(kw); nodes.append(n); return nid def E(a, rel, b, src, **kw): assert rel in EDGE_TYPES, rel e = {"from": a, "rel": rel, "to": b, "src": [src] if isinstance(src, str) else list(src)} e.update(kw); edges.append(e); return e # ---------------------------------------------------------------- 1. THE BILL li = json.load(open(os.path.join(RAW, "c44.json")))[0] N("bill:c-44-42-1", "bill", "Bill C-44 (42-1)", "legisinfo", long_title=li["LongTitleEn"], short_title=li["ShortTitleEn"], sponsor=li["SponsorPersonName"], sponsor_title=li["SponsorAffiliationTitleEn"], sponsor_riding=li["SponsorConstituencyNameEn"], parliament=li["ParliamentNumber"], session=li["SessionNumber"], first_reading=li["PassedHouseFirstReadingDateTime"][:10], house_2r=li["PassedHouseSecondReadingDateTime"][:10], house_3r=li["PassedHouseThirdReadingDateTime"][:10], senate_1r=li["PassedSenateFirstReadingDateTime"][:10], senate_2r=li["PassedSenateSecondReadingDateTime"][:10], senate_3r=li["PassedSenateThirdReadingDateTime"][:10], royal_assent=li["ReceivedRoyalAssentDateTime"][:10], statute="S.C. %s, c. %s" % (li["StatuteYear"], li["StatuteChapter"]), status=li["StatusNameEn"]) divisions = [ {"n": v["DivisionNumber"], "subject": v["DivisionSubjectEn"], "yeas": v["DivisionVotesYeas"], "nays": v["DivisionVotesNays"], "paired": v["DivisionVotePaired"], "total": v["DivisionVoteTotal"], "result": v["DecisionResultNameEn"], "date": v["DecisionDateTime"][:10]} for v in li["HouseVoteDetails"]] hstages = li["BillStages"].get("HouseBillStages", []) fina_meetings = [] for st in hstages: c = st.get("Committee") or {} for m in (st.get("CommitteeMeetings") or []): fina_meetings.append({"committee": m["CommitteeAcronym"], "number": m["Number"], "date": m["Date"][:10]}) seen = set(); fina_meetings = [m for m in fina_meetings if not ((m["committee"], m["number"]) in seen or seen.add((m["committee"], m["number"])))] fina_meetings.sort(key=lambda m: m["date"]) # ------------------------------------------------- 2. STATUTES (machine-derived) st = json.load(open(os.path.join(RAW, "c44_statutes.json"))) DROP = {"Budget Implementation Act, 2017, No. 1"} # the Act's own short title FIXUP = {"Consequential Amendment to the Budget Implementation Act, 2016, No. 1": "Budget Implementation Act, 2016, No. 1"} acts = [] for a in st["acts"]: name = FIXUP.get(a["act"], a["act"]) if name in DROP or a["part"] is None: continue acts.append({**a, "act": name}) def slug(s): import re return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-") N("statute:sc-2017-c-20", "statute", "S.C. 2017, c. 20", ("legisinfo","sc2017c20"), note="The bill as enacted: 4 Parts, 21 Divisions in Part 4.") E("bill:c-44-42-1", "amended", "statute:sc-2017-c-20", "legisinfo", note="Assented 22 June 2017.") for a in acts: sid = "statute:" + slug(a["act"]) if not any(n["id"] == sid for n in nodes): N(sid, "statute", a["act"], "sc2017c20") E("bill:c-44-42-1", "amended" if a["relation"] == "amended" else "authorized", sid, "sc2017c20", part=a["part"], division=a["division"], division_title=a["division_title"], first_section=a["first_section"], relation=a["relation"]) # ------------------------------------------------------ 3. THE CROWN CORPORATION N("crown_corporation:cib", "crown_corporation", "Canada Infrastructure Bank", "cibact", established="2017-06-22", purpose='"to invest, and seek to attract investment from private sector investors and ' 'institutional investors, in infrastructure projects in Canada or partly in Canada ' 'that will generate revenue and that will be in the public interest" (s. 6)', note="Created by Part 4, Division 18, s. 403 of C-44.") E("statute:canada-infrastructure-bank-act", "authorized", "crown_corporation:cib", "cibact", section="s. 5", note="Establishment and organization of the Bank.") N("appropriation:cib-s23", "appropriation", "Ceiling on payments to the CIB — s. 23", "cibact", amount_ceiling=45_000_000_000, text='"The Minister of Finance may pay to the Bank … amounts of not more than ' '$45,000,000,000 in the aggregate." (s. 23)', note="Statutory authority, not an appropriation. The mandate figure is lower.") E("statute:canada-infrastructure-bank-act", "authorized", "appropriation:cib-s23", "cibact", section="s. 23") N("appropriation:cib-mandate", "appropriation", "CIB investment mandate — $35B over 11 years", "pbo2025", amount=35_000_000_000, net_fiscal_expense=15_000_000_000, note="Mandate and net fiscal expense as reported by the PBO. Distinct from the " "$45B statutory ceiling in s. 23.") E("appropriation:cib-s23", "funded", "appropriation:cib-mandate", "pbo2025") E("appropriation:cib-mandate", "funded", "crown_corporation:cib", "pbo2025") # ------------------------------------------------------------- 4. THE STATE SIDE N("minister:morneau", "minister", "Bill Morneau", "legisinfo", role="Minister of Finance", riding="Toronto Centre", note="Sponsor of C-44.") E("minister:morneau", "authorized", "bill:c-44-42-1", "legisinfo", note="Bill sponsor.") N("department:finance", "department", "Department of Finance Canada", "cibact", note="s. 23 places the payment power with the Minister of Finance.") E("department:finance", "authorized", "appropriation:cib-s23", "cibact", section="s. 23") N("minister:mckenna", "minister", "Catherine McKenna", "cibchair2020", role="Minister of Infrastructure and Communities; Minister responsible for the CIB", note="Issued the 3 April 2020 CIB leadership release.") N("department:infc", "department", "Infrastructure Canada", "si201740", note="The designated Minister for the purposes of the Act is the Minister of " "Infrastructure, Communities and Intergovernmental Affairs (SI-2017-40).") E("department:infc", "regulated", "crown_corporation:cib", "si201740", note="Designated Minister under the Act.") E("minister:mckenna", "regulated", "crown_corporation:cib", "cibchair2020") # --------------------------------------------------------- 5. THE INFLUENCE SIDE N("official:barton", "official", "Dominic Barton", "acegrowth", role="Chair, Advisory Council on Economic Growth", concurrent="Global managing director, McKinsey & Company") N("official:wiseman", "official", "Mark Wiseman", "acegrowth", role="Member, Advisory Council on Economic Growth", concurrent="Senior managing director, BlackRock Inc.") N("official:sabia", "official", "Michael Sabia", ("acegrowth","pmsabia","cibchair2020","sabiadm"), role="Member, Advisory Council on Economic Growth (2016)", timeline=[ {"date":"2009-2020","what":"President and CEO, la Caisse de dépôt et placement du Québec","src":"pmsabia"}, {"date":"2016-10-20","what":"Named member of the Advisory Council on Economic Growth that recommended a national infrastructure bank","src":"acegrowth"}, {"date":"2020-02","what":"Director, Munk School of Global Affairs and Public Policy","src":"pmsabia"}, {"date":"2020-04-15","what":"Chair of the Board, Canada Infrastructure Bank","src":"cibchair2020"}, {"date":"2020-12-14","what":"Deputy Minister of Finance","src":"sabiadm"}]) N("corporation:mckinsey", "corporation", "McKinsey & Company", "acegrowth") N("corporation:blackrock", "corporation", "BlackRock Inc.", "acegrowth") N("pension_fund:cdpq", "pension_fund", "Caisse de dépôt et placement du Québec", ("acegrowth","caisserem")) E("corporation:mckinsey", "employed", "official:barton", "acegrowth") E("corporation:blackrock", "employed", "official:wiseman", "acegrowth") E("pension_fund:cdpq", "employed", "official:sabia", "pmsabia", period="2009–2020") N("program:aceg", "program", "Advisory Council on Economic Growth", "acegrowth", recommendation="A national infrastructure bank capitalized with $40 billion in federal " "funds, projected to attract institutional investors and raise over " "$200 billion in infrastructure investment over the decade.", recommended_capital=40_000_000_000, date="2016-10-20", note="Recommendation predates the bill by six months.") for who in ("official:barton","official:wiseman","official:sabia"): E(who, "lobbied", "program:aceg", "acegrowth", note="Council membership. Advisory, not a registered lobbying communication.") E("program:aceg", "lobbied", "bill:c-44-42-1", "acegrowth", note="The Council recommended the institution that Division 18 of C-44 created. " "A recommendation is not a lobbying registration; this edge records advocacy, " "not a registry filing.") E("official:sabia", "employed", "crown_corporation:cib", "cibchair2020", role="Chair of the Board", start="2020-04-15") E("official:sabia", "employed", "department:finance", "sabiadm", role="Deputy Minister of Finance", start="2020-12-14", note="s. 23 of the Act he chaired places the payment power with this department.") N("director:fukakusa", "director", "Janice Fukakusa", "cibchair2020", role="Chair of the Board, CIB", departed="2020-04-15") N("official:lavallee", "official", "Pierre Lavallée", "cibchair2020", role="President and CEO, CIB", departed="2020-04-03") E("crown_corporation:cib", "employed", "director:fukakusa", "cibchair2020") E("crown_corporation:cib", "employed", "official:lavallee", "cibchair2020") # ------------------------------------------------------------------ 6. THE FLOW N("project:rem", "project", "Réseau express métropolitain (REM)", ("cibrem","caisserem"), scale="67 km, 26 stations, Montréal", construction_start="2018-04", total_financing=6_300_000_000) N("subsidiary:cdpq-infra", "subsidiary", "CDPQ Infra", "caisserem", parent="Caisse de dépôt et placement du Québec") E("pension_fund:cdpq", "owned", "subsidiary:cdpq-infra", "caisserem") E("subsidiary:cdpq-infra", "owned", "project:rem", "caisserem", equity_share="~70%", note="Government of Québec holds ~30%.") N("contract:cib-rem-loan", "contract", "CIB senior secured loan to the REM", ("cibrem","caisserem"), amount=1_280_000_000, term_years=15, instrument="15-year senior secured loan", rate="1% escalating to 3% over the term", announced="2018-08", note="The CIB's first investment.") E("crown_corporation:cib", "financed", "project:rem", ("cibrem","caisserem"), amount=1_280_000_000, via="contract:cib-rem-loan") E("crown_corporation:cib", "contracted", "contract:cib-rem-loan", "cibrem") E("contract:cib-rem-loan", "invested", "project:rem", "cibrem", amount=1_280_000_000) for nid, label, amt, ntype in [ ("subsidiary:cdpq-infra", "CDPQ Infra", 2_950_000_000, None), ("financial_institution:iq", "Investissement Québec", 1_280_000_000, "financial_institution"), ("crown_corporation:hydro-quebec", "Hydro-Québec", 295_000_000, "crown_corporation"), ("department:artm", "Autorité régionale de transport métropolitain", 512_000_000, "department"), ]: if ntype and not any(n["id"] == nid for n in nodes): N(nid, ntype, label, "caisserem") E(nid, "financed", "project:rem", "caisserem", amount=amt) # --------------------------------------------------------------- 7. THE OUTCOME N("program:icp", "program", "Investing in Canada Plan", "oag2021r9", commitment=188_000_000_000) E("department:infc", "funded", "program:icp", "oag2021r9") N("program:cib-sectors", "program", "CIB sector investment targets", "pbo2025", targets=[ {"sector":"Public Transit","target":5000,"by_2027_28":3919,"by_2029_30":5178,"pct_2027_28":"78%","pct_2029_30":"target met","gap_2027_28":1081,"gap_2029_30":-178}, {"sector":"Green Infrastructure","target":10000,"by_2027_28":2999,"by_2029_30":3943,"pct_2027_28":"30%","pct_2029_30":"39%","gap_2027_28":7001,"gap_2029_30":6057,"original_target":5000}, {"sector":"Trade & Transportation","target":5000,"by_2027_28":1246,"by_2029_30":1704,"pct_2027_28":"25%","pct_2029_30":"34%","gap_2027_28":3754,"gap_2029_30":3296}, {"sector":"Broadband","target":3000,"by_2027_28":2229,"by_2029_30":2724,"pct_2027_28":"74%","pct_2029_30":"91%","gap_2027_28":771,"gap_2029_30":276,"original_target":1000}, {"sector":"Clean Power","target":10000,"by_2027_28":4465,"by_2029_30":7043,"pct_2027_28":"45%","pct_2029_30":"70%","gap_2027_28":5535,"gap_2029_30":2957}, {"sector":"Project Acceleration","target":500,"by_2027_28":46,"by_2029_30":82,"pct_2027_28":"9%","pct_2029_30":"16%","gap_2027_28":454,"gap_2029_30":418}, {"sector":"Total","target":35000,"by_2027_28":14902,"by_2029_30":20607,"pct_2027_28":"43%","pct_2029_30":"59%","gap_2027_28":20098,"gap_2029_30":14325}, ], units="millions of dollars", note="PBO Table 3. Green Infrastructure's target was raised from $5B to $10B and " "Broadband's from $1B to $3B after the fact.") E("crown_corporation:cib", "funded", "program:cib-sectors", "pbo2025") N("official:giroux", "official", "Yves Giroux", "pbo2025", role="Parliamentary Budget Officer") N("statute:parliament-of-canada-act-pbo", "statute", "Parliament of Canada Act — Parliamentary Budget Officer provisions", "sc2017c20", note="Part 4, Division 7 of the same bill restructured the Parliamentary Budget Officer.") E("bill:c-44-42-1", "amended", "statute:parliament-of-canada-act-pbo", "sc2017c20", part=4, division=7, division_title="Parliamentary Budget Officer and Board of Internal Economy", first_section="122") E("official:giroux", "regulated", "crown_corporation:cib", "pbo2025", note="Reports on the Bank's spending against target.") N_ACTS = len({a["act"] for a in acts}) N_ENACTED = sum(1 for a in acts if a["relation"] == "enacted") # --------------------------------------------------------------- findings FINDINGS = [ {"id":"purpose-vs-partners", "claim":"The Bank's statutory purpose is to attract private and institutional capital. " "Two-thirds of partner funding since inception has come from the public sector.", "left":{"text":'s. 6: "to invest, and seek to attract investment from private sector ' 'investors and institutional investors"',"src":"cibact"}, "right":{"text":'"Since the CIB was established, two-thirds of partner funding has come ' 'from public-sector partners."',"src":"pbo2025"}, "join":"statute:canada-infrastructure-bank-act → crown_corporation:cib → program:cib-sectors"}, {"id":"target-vs-delivery", "claim":"Projected to disburse $14.9B of a $35B mandate by 2027-28 — $20.1B short, and " "on track in no sector.", "left":{"text":"Mandate: $35B over 11 years","src":"pbo2025"}, "right":{"text":"$14,902M by 2027-28; $20,675M by 2029-30; 43% of target. The 2021 PBO " "report projected $15,937M — the outlook got worse, not better.","src":"pbo2025"}, "join":"appropriation:cib-mandate → program:cib-sectors"}, {"id":"moved-goalposts", "claim":"Two sector targets were raised after the fact, changing what counts as success.", "left":{"text":"Green Infrastructure original target $5B; Broadband original target $1B","src":"pbo2025"}, "right":{"text":"Current targets $10B and $3B respectively","src":"pbo2025"}, "join":"program:cib-sectors"}, {"id":"council-to-beneficiary", "claim":"A member of the council that recommended the Bank was, at the time, chief " "executive of the pension fund whose subsidiary received the Bank's first loan. " "He later chaired the Bank, then became Deputy Minister of the department that " "pays it.", "left":{"text":"Michael Sabia, CEO of CDPQ 2009–2020, named on the Advisory Council on " "Economic Growth that recommended a national infrastructure bank on " "20 October 2016","src":"acegrowth"}, "right":{"text":"August 2018: the CIB's first investment is a $1.28B loan to the REM, " "~70% owned by CDPQ Infra, a CDPQ subsidiary. April 2020: Sabia becomes " "CIB Board Chair. December 2020: Deputy Minister of Finance — the " "department holding the s. 23 payment power.", "src":["cibrem","caisserem","cibchair2020","sabiadm"]}, "join":"official:sabia → pension_fund:cdpq → subsidiary:cdpq-infra → project:rem ← crown_corporation:cib", "note":"No allegation of wrongdoing. Every step is a public appointment or a published " "transaction. The point is that no Canadian system joins them."}, {"id":"pbo-in-the-same-bill", "claim":"The omnibus that created the Bank also restructured the Parliamentary Budget " "Officer — the office that now reports the Bank is missing every target. Both " "changes are in Part 4 of C-44.", "left":{"text":"Part 4, Division 7: Parliamentary Budget Officer and Board of Internal " "Economy, s. 122","src":"sc2017c20"}, "right":{"text":"Part 4, Division 18: Canada Infrastructure Bank Act, s. 403","src":"sc2017c20"}, "join":"bill:c-44-42-1 → statute:parliament-of-canada-act-pbo + statute:canada-infrastructure-bank-act"}, {"id":"closure", "claim":f"Debate on a bill amending {N_ACTS} Acts was time-allocated twice, and all 12 " "report-stage amendments were negatived.", "left":{"text":"Divisions 265 (173–123) and 291 (166–124): time allocation, both agreed to","src":"legisinfo"}, "right":{"text":"Divisions 293–303: twelve report-stage amendments, all negatived","src":"legisinfo"}, "join":"bill:c-44-42-1"}, ] # --------------------------------------------------------------- blocked joins BLOCKED = [ {"join":"bill / statute → registered lobbying communications", "what":"Which registrants contacted which designated public office holders about the " "infrastructure bank, and when.", "published":"Yes — Monthly Communication Reports name the DPOH, the registrant, the " "client and the subject matter, monthly, since 2008.", "why_blocked":"The bulk CSV is served from lobbycanada.gc.ca behind an interstitial " "challenge that refuses automated retrieval, including from a headless " "browser. The dataset is catalogued on the Open Government portal but " "carries no datastore API, so there is no machine-readable path to it.", "src":"oclcomms", "consequence":"The single richest influence dataset in Canada — better than anything the " "United States publishes — cannot be joined to legislation without " "scraping a challenge-gated endpoint."}, {"join":"bill → sponsor's political financing", "what":"Money from the beneficiaries of a bill to the people who passed it.", "published":"Yes — Elections Canada publishes every contribution over $200 with name, " "city, province and postal code, weekly, back to 2004.", "why_blocked":"Not blocked — empty. Corporate and union contributions have been " "prohibited federally since 2004-06 and individuals are capped near " "$1,800 a year. There is no federal money edge of a size that would " "explain a $35B institution.", "src":"eccontrib", "consequence":"The American question does not have a Canadian answer. Influence here " "runs through advisory appointments, access and procurement, not " "donations — which is why the lobbying join above matters more."}, {"join":"appropriation → contract → subcontract → beneficial owner", "what":"Following a dollar from the vote in Parliament to the person who ultimately " "receives it.", "published":"Partly. Contracts over $10,000 are proactively disclosed; the federal " "beneficial ownership registry covers CBCA corporations only.", "why_blocked":"Procurement disclosure carries no stable identifier linking an award to " "the appropriation that funded it or to a corporate registry entry. " "Subcontracts are not disclosed at all.", "src":"oag2021r9", "consequence":"The chain breaks at exactly the point where the money reaches a private " "party."}, {"join":"commitment → outcome, at the level of the provision", "what":"Whether a specific clause did what it was said to do.", "published":"Departmental results reports, OAG and PBO findings exist.", "why_blocked":"None of them are keyed to bill, division or section. The OAG found " "Infrastructure Canada's own reporting excluded programs predating the " "Investing in Canada Plan that account for almost half of its $188B.", "src":"oag2021r9", "consequence":"Outcome evidence exists but cannot be attached to the words that " "authorized the spending."}, ] # ------------------------------------------------------------------ ten rows LEDGER = [ {"row":"What government said", "value":"The Advisory Council on Economic Growth recommended a national infrastructure " "bank capitalized with $40B in federal funds, projected to raise over $200B in " "infrastructure investment over the decade.", "date":"2016-10-20","src":"acegrowth","nodes":["program:aceg"]}, {"row":"What Parliament passed", "value":"Bill C-44, An Act to implement certain provisions of the budget tabled in " "Parliament on March 22, 2017 and other measures. Sponsored by the Minister of " "Finance. 17 recorded divisions, including two time-allocation motions. Studied " "by FINA across 10 meetings. Royal assent 22 June 2017 as S.C. 2017, c. 20.", "date":"2017-06-22","src":"legisinfo","nodes":["bill:c-44-42-1"]}, {"row":"What laws changed", "value":f"{N_ACTS} distinct Acts across 4 Parts and 21 Divisions. {N_ENACTED} new Acts created: the " "Borrowing Authority Act, the Canada Infrastructure Bank Act, the Invest in " "Canada Act and the Service Fees Act.", "date":"2017-06-22","src":"sc2017c20","nodes":["statute:sc-2017-c-20"]}, {"row":"What money was authorized", "value":"s. 23 of the Canada Infrastructure Bank Act permits the Minister of Finance to " "pay the Bank up to $45,000,000,000 in the aggregate. s. 20 disapplies s. 91 of " "the Financial Administration Act. s. 19 permits recommending loan guarantees.", "date":"2017-06-22","src":"cibact","nodes":["appropriation:cib-s23"]}, {"row":"What government spent", "value":"The Bank is projected to disburse $14,902M by 2027-28 against a $35,000M " "mandate, and $20,675M by 2029-30. The PBO's 2021 report projected $15,937M by " "2027-28 — the outlook has worsened by 6%.", "date":"2025-07-10","src":"pbo2025","nodes":["program:cib-sectors"]}, {"row":"Who received it", "value":"First investment: a $1.28B, 15-year senior secured loan at 1% escalating to 3% " "to the Réseau express métropolitain, ~70% owned by CDPQ Infra, a subsidiary of " "the Caisse de dépôt et placement du Québec.", "date":"2018-08","src":["cibrem","caisserem"], "nodes":["contract:cib-rem-loan","project:rem","subsidiary:cdpq-infra"]}, {"row":"Who lobbied for it", "value":"Not answerable from joinable records. The pre-legislative advocacy is on the " "record — the Advisory Council on Economic Growth, chaired by McKinsey's global " "managing director, with BlackRock's senior managing director and CDPQ's chief " "executive among its members. Registered lobbying communications naming the " "office holders contacted exist but cannot be machine-retrieved.", "date":"2016-10-20","src":["acegrowth","oclcomms"], "nodes":["program:aceg","official:barton","official:wiseman","official:sabia"], "blocked":True}, {"row":"What was delivered", "value":"On track in no sector. Public Transit 78% of target by 2027-28, Green " "Infrastructure 30%, Trade & Transportation 25%, Broadband 74%, Clean Power 45%, " "Project Acceleration 9%. Indigenous investment met its $1B target.", "date":"2025-07-10","src":"pbo2025","nodes":["program:cib-sectors"]}, {"row":"What it cost", "value":"$35B mandate against a $15B net fiscal expense and a $45B statutory ceiling. " "Green Infrastructure's target was raised from $5B to $10B and Broadband's from " "$1B to $3B after the fact.", "date":"2025-07-10","src":["cibact","pbo2025"], "nodes":["appropriation:cib-s23","appropriation:cib-mandate","program:cib-sectors"]}, {"row":"What happened", "value":"OAG 2021 Report 9 found Infrastructure Canada could not show the $188B " "Investing in Canada Plan was on track and excluded from its reporting programs " "predating the plan that account for almost half of it. The Commons Transport " "Committee reported separately on the Bank in the 44th Parliament. The PBO, " "restructured by Division 7 of the same bill, now reports the Bank will miss " "every sector target.", "date":"2025-07-10","src":["oag2021r9","tran44r3","pbo2025"], "nodes":["program:icp","official:giroux"]}, ] # ------------------------------------------------------------------- 13 stages STAGES = [ ("Law","bill:c-44-42-1","Bill C-44 (42-1) → S.C. 2017, c. 20","legisinfo"), ("Diff","statute:sc-2017-c-20",f"{N_ACTS} Acts touched; {N_ENACTED} Acts created","sc2017c20"), ("Authority","statute:canada-infrastructure-bank-act","Canada Infrastructure Bank Act, s. 403","cibact"), ("Institution","crown_corporation:cib","Canada Infrastructure Bank","cibact"), ("Appropriation","appropriation:cib-s23","s. 23 — up to $45B aggregate","cibact"), ("Mandate","appropriation:cib-mandate","$35B over 11 years; $15B net fiscal expense","pbo2025"), ("Financing","contract:cib-rem-loan","$1.28B, 15-year senior secured loan at 1%→3%","cibrem"), ("Project","project:rem","Réseau express métropolitain — 67 km, 26 stations","cibrem"), ("Ownership","subsidiary:cdpq-infra","CDPQ Infra ~70%; Government of Québec ~30%","caisserem"), ("Beneficiary","pension_fund:cdpq","Caisse de dépôt et placement du Québec","caisserem"), ("Influence","program:aceg","Advisory Council on Economic Growth, 20 Oct 2016","acegrowth"), ("Revolving door","official:sabia","CDPQ → Council → CIB Chair → Deputy Minister of Finance", "pmsabia"), ("Outcome","program:cib-sectors","43% of mandate by 2027-28; no sector on track","pbo2025"), ] # ---------------------------------------------------------------------- emit counts = {t: sum(1 for n in nodes if n["type"] == t) for t in NODE_TYPES} ecounts = {t: sum(1 for e in edges if e["rel"] == t) for t in EDGE_TYPES} graph = { "generated": datetime.date.today().isoformat(), "schema": {"node_types": NODE_TYPES, "edge_types": EDGE_TYPES, "source": "https://followthemoney.felineunion.org/#segment-12"}, "subject": {"bill": "C-44", "parliament": 42, "session": 1, "statute": "S.C. 2017, c. 20", "title": li["ShortTitleEn"], "long_title": li["LongTitleEn"]}, "counts": {"nodes": len(nodes), "edges": len(edges), "by_node_type": counts, "by_edge_type": ecounts, "populated_node_types": sum(1 for v in counts.values() if v), "populated_edge_types": sum(1 for v in ecounts.values() if v), "distinct_acts": len({a["act"] for a in acts}), "acts_enacted": sum(1 for a in acts if a["relation"] == "enacted"), "divisions_recorded": len(divisions)}, "sources": SOURCES, "nodes": nodes, "edges": edges, "ledger": LEDGER, "stages": STAGES, "findings": FINDINGS, "blocked_joins": BLOCKED, "divisions": divisions, "committee_meetings": fina_meetings, "acts": acts, } out = sys.argv[1] if len(sys.argv) > 1 else os.path.join(HERE, "graph.json") json.dump(graph, open(out, "w"), indent=1, ensure_ascii=False) print(f"nodes={len(nodes)} edges={len(edges)}") print(f"node types populated: {graph['counts']['populated_node_types']}/{len(NODE_TYPES)}") print(f"edge types populated: {graph['counts']['populated_edge_types']}/{len(EDGE_TYPES)}") print(f"distinct Acts={graph['counts']['distinct_acts']} enacted={graph['counts']['acts_enacted']} divisions={len(divisions)}") print("empty node types:", [t for t,v in counts.items() if not v]) print("empty edge types:", [t for t,v in ecounts.items() if not v]) print("->", out)