Loading…
Loading…
Everything this project holds, what it is licensed under, what each field means, and what it does not yet know. The figures on this page are computed from the live database each time it is served; none of them is written into the page.
547
events on record
35
pass the publication gate
839
participations, 511 distinct people
Crossing the Floor. The Crossing the Floor Database, release 2026-08-01.1. crossingthefloor.ca, 2026. [DOI pending]. Licensed CC BY 4.0.
Party-affiliation facts compiled from public parliamentary records, including PARLINFO (Library of Parliament) and the House of Commons of Canada, together with provincial and territorial legislatures and election authorities. This is not an official publication of the Senate, the House of Commons, a provincial legislature or the Library of Parliament, and is not endorsed by them. Reproductions of parliamentary proceedings are accurate to the best of our ability and are not presented as official. Portrait images are individually credited and are not covered by the data licence. Any biographical text adapted from an encyclopedia is separately marked and licensed CC BY-SA 4.0. The Crossing the Floor Database is released under CC BY 4.0: Crossing the Floor (crossingthefloor.ca), CC BY 4.0.
/api/crossingsThe original compilation, one row per crossing, as a paged JSON envelope of the shape { rows, total, page, perPage }. It carries no verification level, no citation graph and no group-event structure, because the legacy model has nowhere to put them. It is served for continuity with existing reusers; new work should wait for the versioned v2 export below.
These addresses return 404 today. Nothing on this page links to them as a download and they are excluded from the machine-readable dataset description, so a data-search crawler will not offer them to you either.
/api/v2/export?format=jsonEvents, participants, people, parties, jurisdictions, claims, citations and sources in the canonical model, with every verification and precision field carried through rather than flattened away.
This address returns 404 today. It is listed so that you know it is coming and can plan for it, not because you can fetch it now.
/api/v2/export?format=csvThe same records as a flat table per entity, for a spreadsheet or an R or Python session. Unknown values are empty cells and are documented as unknown in the data dictionary; they are never written as zero.
This address returns 404 today. The page you are reading has never offered a CSV that worked; the button that used to claim it returned JSON.
Database: CC BY 4.0 Creative Commons Attribution 4.0 International
Site code, design and visual identity: rights reserved
The Crossing the Floor Database: the events, participants, persons, parties, jurisdictions, classifications, claims, citation metadata and release manifests authored by this project, and the project’s own written descriptions of them in English and French.
Copy this exactly. A link to the site, placed where a reader will find it, satisfies the licence.
Crossing the Floor (crossingthefloor.ca), CC BY 4.0
Party-affiliation facts compiled from public parliamentary records, including PARLINFO (Library of Parliament) and the House of Commons of Canada, together with provincial and territorial legislatures and election authorities. This is not an official publication of the Senate, the House of Commons, a provincial legislature or the Library of Parliament, and is not endorsed by them. Reproductions of parliamentary proceedings are accurate to the best of our ability and are not presented as official. Portrait images are individually credited and are not covered by the data licence. Any biographical text adapted from an encyclopedia is separately marked and licensed CC BY-SA 4.0. The Crossing the Floor Database is released under CC BY 4.0: Crossing the Floor (crossingthefloor.ca), CC BY 4.0.
A citation should quote a release version. The counts below are the counts AS OF that release and are not recomputed; the coverage report is what the database holds now.
2026-08-01.1CTF-REL-2026-08-01.12026-08-01# Release 2026-08-01.1 Scope: canonical archive v2. This immutable release contains 239 event records, 231 participant changes, 222 people, and 153 source records. It publishes the source-bound 2024–2026 Quebec affiliation chronology and Elenore Sturko's 2025 caucus expulsion, including complete affiliation intervals, bilingual fields, claim-level citations, and four separately classified office or nomination outcomes. The inherited Maïté Blanchette Vézina identifier and slug remain stable while the collapsed year-only path is corrected into two dated events. Unverified historical leads remain explicitly labelled; no motive, reward, or causal exchange is inferred.
Recorded data licence: OGL-Canada-2.0 (project-authored structured data only) · code licence: repository licence
This release was stamped with a different data licence from the one the project now publishes. The licence that governs your reuse is the one stated on this page. The release record is shown unaltered because a package you have already downloaded carries the older statement, and you should be able to see that the two differ rather than discover it later.
The files below were generated when this release was built and their sizes and checksums are recorded. They are not currently served at those addresses — every one of them returns 404, checked on 31 August 2026. The manifest is published anyway so that the contents and checksums of a release can be verified against a copy obtained any other way, and so that the gap is visible instead of silent.
| File | Format | Size | SHA-256 |
|---|---|---|---|
| checksums.sha256 | checksums | 4.6 kB | f807f603b7931905… |
| CITATION.cff | citation | 341 B | 649c68bd5f6fd687… |
| affiliation_history.csv | csv | 11.5 kB | 0fd87d76f0c52cd2… |
| alternate_identities.csv | csv | 113 B | 604582604863d108… |
| chambers.csv | csv | 2.1 kB | 12635a7623e15e28… |
| claim_citations.csv | csv | 63.5 kB | 8ab24d5110c0d402… |
| claims.csv | csv | 91.9 kB | 4ac1ad681ddd22af… |
| editorial_reviews.csv | csv | 36.8 kB | 9d57890d2c943e79… |
| events.csv | csv | 64.5 kB | 842a9e8fc0c89819… |
| jurisdictions.csv | csv | 1.6 kB | 3237536123402c53… |
| legislatures.csv | csv | 2.2 kB | 78c46f63c42cb8ca… |
| outcomes.csv | csv | 20.2 kB | 4b9404382805c2dd… |
| participants.csv | csv | 81.9 kB | f9b4e70a8f62b1bb… |
| parties.csv | csv | 9.8 kB | d412150e5f3605af… |
| party_aliases.csv | csv | 7.5 kB | 0695585e2be4dd4d… |
| party_relationships.csv | csv | 134 B | ca9b14cf4f2c58b4… |
| people.csv | csv | 27.9 kB | 7d991b4d368a11cf… |
| revisions.csv | csv | 142.2 kB | 8d0158f8d0d48a43… |
| riding_lineage.csv | csv | 143 B | 0fb9cef226cf0108… |
| riding_names.csv | csv | 83 B | fba4ff04def4ce32… |
| ridings.csv | csv | 2.2 kB | 004909eb94e61baa… |
| sessions.csv | csv | 10 kB | a33d802e312555ab… |
| source_link_checks.csv | csv | 22.9 kB | aede3cbfd432a80e… |
| sources.csv | csv | 52.3 kB | 335228fb64bcd307… |
| translations.csv | csv | 10.3 kB | 6b5d67e039fe908e… |
| data-dictionary.en.json | dictionary | 67.1 kB | 34eb4390f18b4366… |
| data-dictionary.fr.json | dictionary | 75.1 kB | 2a8f22767af3e8fe… |
| release-notes.en.md | documentation | 680 B | e23cd8f71e410f38… |
| release-notes.fr.md | documentation | 833 B | 8d92688f2648410f… |
| archive.json | json | 1.4 MB | ccc2995d1803033e… |
| LICENSE.txt | license | 359 B | ef581ac95e26e1b4… |
| manifest.json | manifest | 9.1 kB | 88f9922cdc62980f… |
| affiliation_history.parquet | parquet | 5 kB | 3aea9e440f16a452… |
| alternate_identities.parquet | parquet | 203 B | 2083e17a04e38244… |
| chambers.parquet | parquet | 1.9 kB | ed24f190515ddf5a… |
| claim_citations.parquet | parquet | 13.7 kB | 1aeaaecc4219d53a… |
| claims.parquet | parquet | 27.7 kB | 1eb74852b0b47988… |
| editorial_reviews.parquet | parquet | 3.8 kB | 58204d7880b7e5a0… |
| events.parquet | parquet | 22 kB | de41c9b25162b21d… |
| jurisdictions.parquet | parquet | 2 kB | 78b48539ee97cfc7… |
| legislatures.parquet | parquet | 2.6 kB | 54d842c3d88875f3… |
| outcomes.parquet | parquet | 13.1 kB | 458f027cfc2cf30a… |
| participants.parquet | parquet | 22.3 kB | d79df961861e54f0… |
| parties.parquet | parquet | 4.9 kB | 77d54dcd74797a9c… |
| party_aliases.parquet | parquet | 3.5 kB | d91baa1ebf2569fb… |
| party_relationships.parquet | parquet | 218 B | db76371c9b609198… |
| people.parquet | parquet | 13.7 kB | 3c349a52f1c0ee5c… |
| revisions.parquet | parquet | 10.3 kB | 94737f59dbba8f0b… |
| riding_lineage.parquet | parquet | 225 B | ccb84f638b5f8eff… |
| riding_names.parquet | parquet | 165 B | 1486bc906425cf11… |
| ridings.parquet | parquet | 2.6 kB | 271ae9180420c5cb… |
| sessions.parquet | parquet | 4.7 kB | dcf4a5b5a5b5b460… |
| source_link_checks.parquet | parquet | 10.5 kB | 9b1ac7f4c6ae2f53… |
| sources.parquet | parquet | 22.6 kB | 1ab8c700684cf501… |
| translations.parquet | parquet | 3.1 kB | d5f5cabc8caeac31… |
| schema.json | schema | 53.2 kB | d32fab2aedcd3642… |
| archive.sqlite | sqlite | 1.6 MB | d10b6bf629e00c88… |
Every field a distribution carries, its type, whether it can be unknown, and what unknown means for that field specifically. "Unknown" is a recorded value in this model, not an absence and never a zero: the coverage figure beside a field is measured live and tells you how much of the column is actually populated.
62 fields documented across 7 table groups.
affiliation_eventsOne affiliation change, as defined by the published inclusion criteria. This is the table the headline count is taken from.
One row per event. A caucus that moved together on one day is ONE row here and several rows in participants.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
public_idPublic identifier | text | Always present | The stable identifier of the form CTF-E-nnnnnn. Cite this, not the numeric id, and not the slug: the slug can be rewritten, this cannot. |
slugSlug | text | Always present | The URL segment for the record page. Readable, but not a citation target. |
permanent_uriPermanent URI | text | Always present | The recorded citation address. Three different URL shapes are stored across the table and the majority shape uses a language-prefixed path this site does not serve, so it does not resolve. Repairing the column is a pending data correction; until then, prefer the address shown on the record page. |
event_dateEvent date | date | Empty when unknown | When the affiliation changed. Always read it together with date_precision: a value of 1930-01-01 with year precision does not mean the first of January. Empty means no date has been established at all, not that the event is undated in the world. |
date_precisionDate precision | text | A value that means unknown 413 / 551 known | How exactly event_date is known: day, month, year, circa, range or unknown. This is the single most important field for a reporter. Most of the record is dated to a year only, and a year-precision row cannot support a sentence naming a month or a day. The literal value unknown means the precision itself was never assessed — weaker than year precision, not equal to it. |
date_endEnd of date range | date | Empty when unknown | The upper bound when date_precision is range. Empty on every row that is not a range. Not a defect. |
event_typeEvent type | text | A value that means unknown 463 / 551 known | The kind of affiliation change: joined_party, left_to_independent, expelled, suspended, party_formation, party_dissolution, merger, caucus_departure, return_to_party, changed_affiliation or other. The value other means the change did not fit the vocabulary, not that it was unclassifiable in principle. |
event_scopeEvent scope | text | Always present 551 / 551 known | individual, group or institutional. A group event is one event involving several people; it is the reason an event count and a person count are different numbers and cannot be compared directly. |
participant_count_knownConfirmed head count | integer | Empty when unknown | The editorially confirmed number of people involved, where one has been established. Empty means no head count has been confirmed. Do not substitute the number of named participants: on group events those differ, which is the whole point of the field. |
participant_count_estimateEstimated head count | integer | Empty when unknown | The record’s own estimate of how many people were involved, for example 17 for a caucus described in a source as "about seventeen members". It is the record declaring an estimate, not a projection computed here. Empty means no estimate was recorded, which is different from an estimate of zero. |
participant_resolution_statusParticipant resolution | text | A value that means unknown | not_applicable, unresolved, partial or complete — how far the work of naming the individuals has got. unresolved means the event says more people were involved than are named. Rendering such an event with an empty participant list, or counting its participants as its head count, understates it. |
verification_levelVerification level | text | A value that means unknown 38 / 551 known | unverified, single_source, corroborated or official_and_independent — the strength of the evidence behind the record. unverified means nobody has checked it against a source yet. Filtering on this field ALONE is unsafe: a withdrawn record can still carry a corroborated level, so exclude withdrawn as well. |
publication_statusPublication status | text | A value that means unknown 35 / 551 known | legacy_lead, pending_review, verified, disputed or withdrawn — the editorial lifecycle of the record. legacy_lead means imported and never reviewed. Most of the table sits here. A lead is a research pointer, not a published fact. |
published_atPublished at | timestamp with time zone | Empty when unknown | When the record was published. The third leg of the publication gate: verified status AND corroborated evidence or better AND this timestamp. Empty means never published, whatever the other two fields say. |
last_verified_atLast verified at | timestamp with time zone | Empty when unknown | When a human last checked this record against its sources. Empty means never verified. It does not mean verified long ago. |
jurisdiction_idJurisdiction | bigint | Always present | Foreign key to jurisdictions. Province and territory names come from that table, never from free text — which is why the same province can no longer appear under two spellings the way it did in the legacy model. |
legislature_idLegislature | bigint | Empty when unknown 549 / 551 known | Foreign key to legislatures, and the ONLY source of federal / provincial / territorial. There is no level column on the event itself. Empty means the event has no level at all, so any filter by level necessarily excludes it. Filtering by level and then reporting the result as a total is the easiest way to lose rows silently. |
chamber_idChamber | bigint | Empty when unknown 549 / 551 known | Foreign key to chambers. Empty means no chamber recorded. Note separately that the chambers table does contain an upper chamber, the Senate of Canada, and that Senate records exist here — none of them published, so they appear only when you ask for unpublished records. |
session_idParliamentary session | bigint | Empty when unknown 0 / 551 known | Foreign key to sessions. Empty on every row in the live database. The sessions table is populated; nothing has been linked to it. Do not build a session-based analysis on this column. |
title_en / title_frTitle | text | Always present | The event title in each language. Both columns are NOT NULL. Because neither column can be empty, a missing translation shows up as the French being byte-identical to the English rather than as a null. A null-based check will report this table as fully bilingual when much of it is not; the API and the site flag identical pairs for exactly this reason. |
summary_en / summary_frSummary | text | Empty when unknown 520 / 551 known | A short prose description of the event in each language. Empty means no summary was written in that language. It is served as absent, never machine-translated on the fly. |
revisionRevision | integer | Always present | Increments on every material change. Paired with the revisions table, it lets you reconstruct what the record said when you cited it. |
legacy_crossing_idLegacy crossing id | integer | Empty when unknown | Link back to the row in the original 25-table model, for anyone reconciling against an older export. Empty means the record has no legacy counterpart — usually because it was created after the migration. |
event_participantsOne person’s leg of one event: what they left, what they joined, and under what circumstances.
One row per person per event. Summing this table gives a participation count, which is neither an event count nor a person count.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
person_idPerson | integer | Empty when unknown | Foreign key to persons. Empty means the leg is recorded but the individual is not yet identified. |
from_party_id / to_party_idParty left / party joined | bigint | Empty when unknown 583 / 839 known | Foreign keys to political_parties. Empty is common and meaningful. A member who went Independent has no destination party at all, and a member who came from a body with no party row has no origin party. Neither is missing data; use the affiliation label instead, and never treat an empty to_party_id as "stayed put". |
from_affiliation_label / to_affiliation_labelAffiliation labels | text | Empty when unknown 621 / 839 known | The verbatim label for each side, used where no party row exists — for example Independent. Empty means neither a party nor a label was recorded for that side. |
voluntary_statusVoluntary status | text | A value that means unknown 163 / 839 known | voluntary, involuntary, mixed or unknown — whether the member jumped or was pushed. unknown is the default and is the value on the large majority of rows. It means the question has not been answered, not that the move was neutral. Any share computed over this field must be taken over the rows where it is not unknown, and published beside that denominator. |
appointed_statusAppointment following | text | A value that means unknown 154 / 839 known | yes, no, unknown or not_applicable — whether an appointment followed the change. unknown dominates this column. It is the field a "were they rewarded?" story would rest on, and it is mostly unanswered; treat a small known set as a small known set. |
government_directionDirection relative to government | text | A value that means unknown 17 / 839 known | to_government, from_government, between_opposition, government_to_independent, opposition_to_independent, unknown or not_applicable. unknown means the direction was never established, which is the case on most rows. |
seat_balance_delta_from / seat_balance_delta_toSeat-balance change | integer | Empty when unknown 0 / 839 known | How the standing of each caucus changed. Empty on every row in the live database. The arithmetic is obvious and has deliberately not been inferred, because an inferred number is indistinguishable from a recorded one once it is exported. |
riding_idRiding | integer | Empty when unknown 25 / 839 known | Foreign key to ridings. Empty means no riding recorded for this leg. |
effective_date / effective_date_endEffective dates | date | Empty when unknown | When this person’s leg took effect, which can differ from the event date when a group moved over several days. Empty means the leg carries no date of its own; fall back to the event date and its precision. |
sequenceSequence | integer | Always present | Order of this leg within its event. It is a display order, not a ranking of importance. |
personsThe individuals who appear in events.
One row per person. A person who crossed three times is one row here and three rows in participants.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
public_idPublic identifier | text | Always present | The stable identifier for the person. |
name_en / name_frName | text | Always present | The person’s name in each language. These two are frequently identical, and for a personal name that is usually correct rather than a missing translation. Do not read an identical pair here as an untranslated record without checking. |
birth_year / death_yearBirth and death years | integer | Empty when unknown | Years only, never full dates. An empty death year means no death year is recorded. It does NOT mean the person is living, and must never be used to infer that. |
living_person_review_statusLiving-person review | text | A value that means unknown | Whether the record has been reviewed under the stricter standard applied to living people. An unreviewed value means the review has not happened, not that the person is dead. |
portrait_urlPortrait address | text | Empty when unknown | The address of an image, with its rights status, credit, licence and source page in the neighbouring columns. Data packages carry the address and the credit fields, never the image file. Empty means no portrait is held, which may be because one was removed for want of a rights basis rather than because none exists. |
evidence_sourcesThe documents the record is built on. Held link-only: the address, the locator and the bibliographic metadata, never the document itself.
One row per source document.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
source_typeSource type | text | Always present | hansard, journal, official_member_profile, official_party_record, government_record, election_record, news, academic and others. |
reliability_tierReliability tier | text | A value that means unknown 239 / 264 known | How much weight the sourcing standard gives this kind of document. An unassessed tier means nobody has placed the source yet, not that it is untrustworthy. |
urlAddress | text | Empty when unknown 258 / 264 known | Where the document can be read. Empty means an offline source with no address — a bound volume, a microfilm. That is different from a source whose link has never been checked. |
archive_url / archive_captured_atArchive copy | text / timestamp with time zone | Empty when unknown 223 / 264 known | A preservation copy of the document and when it was captured. Empty on every row in the live database: nothing has been archived yet. A source is therefore only as durable as the site that hosts it. |
checksum / checksum_algorithm / checksum_scope / checksum_inputChecksum | text | Empty when unknown 92 / 264 known | A hash of the source and, crucially, a statement of WHAT was hashed. A checksum without its scope cannot be reproduced by anyone else and so verifies nothing. Empty means no hash was taken. A hash present without a scope is counted here as unverifiable, not as verified. |
locator_type / locator_valueLocator | text | Empty when unknown | Where inside the document the passage sits — a page, a column, a timestamp. Empty means the citation points at the document as a whole and a reader must find the passage themselves. |
rights_status / rights_noteRights status | text | A value that means unknown | What may be done with the source document. It governs the document, not our metadata about it. An unassessed status means the question has not been settled; treat the document as all-rights-reserved until it is. |
languageLanguage | text | A value that means unknown | en, fr, und (undetermined) or mul (multiple). und means the language was never determined, not that the document has none. |
claimsWhat the record asserts about a subject, and which source supports or contradicts each assertion. This is the layer that makes a record auditable field by field rather than as a whole.
One claim per asserted field. One citation per claim-source pair.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
subject_type / subject_public_idSubject | text | Always present | What the claim is about, by public identifier rather than by numeric key, so a claim survives a re-import. |
field_keyField | text | Always present | Which field of the subject the claim asserts. |
assertion_statusAssertion status | text | A value that means unknown 99 / 1,538 known | pending_review, supported, partially_supported, disputed, unsupported, unknown or withdrawn. pending_review is the value on most claims and means no reviewer has looked at it. A claim in that state is not evidence of anything except that someone recorded an assertion. |
confidenceConfidence | text | A value that means unknown | high, medium, low or unknown. unknown means no confidence was assigned, which is not the same as low confidence. |
living_person_sensitiveConcerns a living person | boolean | Always present | Flags claims held to the stricter standard because they are about someone still living. |
supports (claim_citations)Supports or contradicts | boolean | Always present 1,154 / 1,538 known | False marks a source that CONTRADICTS its claim. Such citations must never be filtered out of a citation count: a record with a contradicting source is better documented than one with none, and hiding them would make the evidence look cleaner than it is. |
quote_excerpt (claim_citations)Quoted passage | text | Empty when unknown | The passage in the source that carries the claim. Empty means no excerpt was transcribed. It never means the source was paraphrased into the field. |
corrections_ledgerEvery published change to a record, with the revision it produced. A reference work that cannot show what it used to say cannot be audited.
One row per published correction.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
record_type / record_public_idCorrected record | text | Always present | Which record was corrected, by public identifier. |
materialMaterial | boolean | Always present | True when the correction changes what a reader would reasonably have understood — the kind of change that would oblige you to update a story you had already filed. |
corrected_atCorrected at | timestamp with time zone | Always present | When the correction was made. Compare it with the retrieval date in your citation to know whether what you cited has since changed. |
revision_idRevision | bigint | Always present | The revision this correction produced, so the before and after states can both be recovered. |
jurisdictions / legislatures / chambers / political_partiesThe controlled tables every place and party name is drawn from. Nothing in the canonical model stores a place or party as free text.
One row per jurisdiction, legislature, chamber or party.
| Field | Type | Unknown | Meaning |
|---|---|---|---|
jurisdictions.iso_codeISO code | text | Always present | CA for the country, CA-ON, CA-NS and so on for provinces and territories. The safe join key for merging with another dataset. |
legislatures.levelLevel | text | Always present | federal, provincial or territorial. This column is the only place the level lives; events reach it through legislature_id. |
chambers.chamber_typeChamber type | text | Always present | lower, upper or unicameral. A row of type upper exists in the live database: the Senate of Canada. The Senate is present in the record and absent from the published record, because none of the Senate events has passed the publication gate. Treat an empty Senate result as a statement about review, not about the schema and not about whether senators change affiliation. |
political_parties.colourParty colour | text | Empty when unknown | The party’s own published colour. Empty on nearly every party. A colour is not invented for a party that does not publish one, so a chart drawn from this column will be mostly uncoloured — by design. |
political_parties.party_kindParty kind | text | Always present | party, parliamentary_group or coalition. A parliamentary group is not a registered party and counting the two together will overstate the number of parties. |
The endpoints marked "legacy" are shaped by the original 25-table model, which has no verification level, no citation graph and no way to represent a caucus that moved together. They remain available so that existing reusers do not break. The canonical model is what the site itself now reads and what the versioned export will carry; if you are starting work today, build against that.
API →