Scope
- Platform: BigQuery
- Scope: projects lab-a (data); regions EU, europe-west1, US
- Privilege level: 2 (+ queries (normalized forms), reads per table, policies)
- SQL mode: read-only
- Reads: 18 done out of 22
- Content read: 9 tables, 12 objects, 3 query families
- Hidden schemas or datasets read: _tmp
- Versions: canot 0.1.0, duckdb 1.5.6, sqlglot 30.22.0
Capabilities
This report is an inventory: inventoried, neither exported nor replayed.
| Level | This report | Canot on BigQuery |
|---|---|---|
| Inventory | done by this scan (level 2) | full, levels 1 to 3 |
| Export | not done by this scan | iceberg, with canot drill |
| Evidence | not done by this scan | P1 data parity; P2 query replay, with canot drill |
BigQuery connector: tested; recorded test: canot drill, 2026-10-13: public dataset thelook_ecommerce (docs/ecarts.md).
What Canot cannot prove here: the declared forms (P1, P2) cover tables and queries; objects to rebuild besides tables are counted, not proven.
Observed costs
Window: 180 days. On-demand and reserved: two billing models, never added together.
On demand
| Item | Value | Nature and basis |
|---|---|---|
| Billed bytes | 3.8 TB | measured · B10, B11, B12 |
| Queries | 1,200 queries | measured · B10, B11, B12 |
| In dollars | $0.00 to $21.88
| estimated, low confidence · B10, B11, B12 billed TiB × list price, free tier deducted or not |
Reserved
| Item | Value | Nature and basis |
|---|---|---|
| Slot-hours | 820.5 slot-hours | measured · B10, B11, B12 |
| Queries | 300 queries | measured · B10, B11, B12 |
| In dollars | Not estimated: your contract price not read. | not estimated |
On demand and reserved do not add up: two billing models, two bases.
Storage
| Item | Value | Nature and basis |
|---|---|---|
| Average billed storage | Not read: not provided by collection. | not read |
| Storage in dollars | Not estimated: your contract price not read. | not estimated |
Movements
2 frozen, 7 live, 0 recreated, 0 not determined.
recreated: DDL less than 7 days old with no later write; live: write less than 30 days old; frozen: older last write; not determined: writes not read. Based on: B03, B04, B05, B07, B10, B11 ….
| Table | Type | Volume | Movement | Evidence |
|---|---|---|---|---|
| lab-a.archive.archive_2023 | TABLE | 3 GB | frozen | last write on 2025-03-01 |
| lab-a.raw.orders | TABLE | 900 MB | live | last write on 2026-10-15 |
| lab-a.raw.read_by_api_only | TABLE | 700 MB | frozen | last write on 2026-09-01 |
| lab-a.raw.customers | TABLE | 200 MB | live | last write on 2026-10-15 |
| lab-a.raw.events_20261001 | TABLE | 120 MB | live | last write on 2026-10-15 |
| lab-a._tmp.scratch | TABLE | 50 MB | live | last write on 2026-10-15 |
| lab-a.raw.orders_snap | SNAPSHOT | 10 MB | live | last write on 2026-10-15 |
| lab-a.ext.gcs_events | EXTERNAL | not read | live | last write on 2026-10-15 |
| lab-a.ext.sheet_targets | EXTERNAL | not read | live | last write on 2026-10-15 |
What does not leave with the copy
Objects to rebuild or describe
| Type | Count | Examples |
|---|---|---|
| function | 1 | lab-a.mart.js_clean |
| ML model | 1 | lab-a.ml.churn |
| share | 1 | lab-a.hub.listing_sales |
| row access policy | 1 | lab-a.raw.rap_country |
| procedure | 1 | lab-a.mart.sp_rebuild |
| scheduled query | 4 | lab-a.sq_daily_kpi, lab-a.sq_export, lab-a.sq_old, lab-a.sq_weekly |
| view | 2 | lab-a.mart.v_legacy, lab-a.mart.v_sheet |
| materialized view | 1 | lab-a.mart.mv_daily |
Routines per language: JAVASCRIPT 1, SQL 1.
Columns with a platform-specific type (3)
| Table | Column | Type |
|---|---|---|
| lab-a.raw.customers | geo | GEOGRAPHY |
| lab-a.raw.events_20261001 | payload | JSON |
| lab-a.raw.events_20261001 | ctx | STRUCT<a INT64, b STRING> |
Billed history
| Item | Value | Nature and basis |
|---|---|---|
| Time Travel and Fail-safe (1 table) | 250 MB | computed · B07 Time Travel + Fail-safe of present tables, + bytes still billed for dropped tables |
Dependencies
External dependencies (F01)
| Object | Type | Location |
|---|---|---|
| lab-a.ext.gcs_events | table | gs://lab-bucket |
| lab-a.ext.sheet_targets | table | docs.google.com |
Hidden external dependencies (F02)
| Object | Path | Location |
|---|---|---|
| lab-a.mart.v_sheet | lab-a.mart.v_sheet → lab-a.ext.sheet_targets | docs.google.com |
Writes outside the platform (F03)
| Source | Mode | Destination |
|---|---|---|
| family 333333333333 | observed | gs://lab-exports |
| object lab-a.sq_export | declared | gs://lab-exports |
External consumers (F09)
| Share | Accounts |
|---|---|
| lab-a.hub.listing_sales | 1 |
Tools seen in queries
| Tool | Families | Executions |
|---|---|---|
| looker | 1 | 900 |
| scheduled_query | 1 | 180 |
| notebook | 1 | 40 |
Query replayability
| Category | Meaning | Families | Executions | Weight |
|---|---|---|---|---|
| C0 | translated and accepted by DuckDB | 1 | 900 | 2 TB |
| C1 | not parseable | 0 | 0 | 0 B |
| C2 | command, not analyzed | 0 | 0 | 0 B |
| C3 | translation impossible | 0 | 0 | 0 B |
| C4 | DuckDB parse error | 1 | 40 | 500 GB |
| C5 | binding error (platform-specific object or function) | 0 | 0 | 0 B |
| C6 | variable | 0 | 0 | 0 B |
| C7 | DDL, COPY, MERGE, metadata queries: counted separately | 1 | 180 | 10 GB |
| Item | Value | Nature and basis |
|---|---|---|
| C0 rate, by families | 50.0% | computed · B10, B11, B12 C0 ÷ C0 to C6, in families; C7 counted separately |
| C0 rate, by executions | 95.7% | computed · B10, B11, B12 C0 ÷ C0 to C6, in executions; C7 counted separately |
| C0 rate, weighted | 80.0% | computed · B10, B11, B12 C0 ÷ C0 to C6, in bytes; C7 counted separately |
Based on: 3/3 families, from 2026-04-20 to 2026-10-17, sqlglot 30.22.0, duckdb 1.5.6.
accepted ≠ identical result. Translated to DuckDB, not compared.
Most executed families (normalized forms)
| Category | Executions | Tool | Normalized form |
|---|---|---|---|
| C0 | 900 | looker | SELECT * FROM `lab-a.raw.orders` WHERE d >= ? |
| C7 | 180 | scheduled_query | EXPORT DATA OPTIONS (uri = ?, format = ?) AS SELECT * FROM `lab-a.mart.kpi` |
| C4 | 40 | notebook | SELECT * FROM `lab-a.raw.events_*` WHERE _TABLE_SUFFIX = ? |
Ranges
Planning estimates: each range carries its assumptions. A canot drill replaces the assumed throughput with a measurement.
| Item | Value | Nature and basis |
|---|---|---|
| Volume to copy | 5 GB
| computed · B07 sum of active bytes |
| Copy read time | 1 min to 4 min
| estimated, low confidence · B07 volume ÷ assumed throughput |
| Copy read cost | Not estimated: your contract price not read.
| not estimated |
| Rework | 3.0 d to 18.0 d
| estimated, low confidence · B13, B19, B20 objects × days per object + columns × days per column |
Findings
Each finding is labeled "To review", with no severity level. It states what is observed and what is not.
F01 · External dependencyTo review
2 findings
| Target | Observed |
|---|---|
| table lab-a.ext.gcs_events | External table: data outside the platform (gs://lab-bucket). |
| table lab-a.ext.sheet_targets | External table: data outside the platform (docs.google.com). |
F02 · Hidden external dependencyTo review
1 finding
| Target | Observed |
|---|---|
| object lab-a.mart.v_sheet | Depends on lab-a.ext.sheet_targets, outside the platform, through 1 level: lab-a.mart.v_sheet → lab-a.ext.sheet_targets (docs.google.com). |
F03 · Write outside the platformTo review
2 findings
| Target | Observed |
|---|---|
| family 333333333333 | Write outside the platform observed: 180 executions (scheduled_query); destination: gs://lab-exports. |
| object lab-a.sq_export | Scheduled query that writes outside the platform (declared in its definition); destination: gs://lab-exports. |
F05 · Storage with no observed readTo review
2 findings
| Target | Observed |
|---|---|
| table lab-a.archive.archive_2023 | 3 GB stored. No read observed in INFORMATION_SCHEMA.JOBS from 2026-04-20 to 2026-10-17; blind spots: reads through the Storage Read API, queries run from other projects, Analytics Hub consumers. |
| table lab-a.raw.read_by_api_only | 700 MB stored. No read observed in INFORMATION_SCHEMA.JOBS from 2026-04-20 to 2026-10-17; blind spots: reads through the Storage Read API, queries run from other projects, Analytics Hub consumers. |
F06 · Billed history that does not transferTo review
1 finding
| Target | Observed |
|---|---|
| table lab-a.raw.orders | 250 MB of billed history (Time Travel and Fail-safe), retention 7 days, for 900 MB active; this history does not leave with the copy. |
F08 · Dynamic SQLTo review
1 finding
| Target | Observed |
|---|---|
| object lab-a.mart.sp_rebuild | Procedure (SQL): builds SQL at run time; the objects it touches cannot be read from the code. |
F09 · External consumersTo review
1 finding
| Target | Observed |
|---|---|
| object lab-a.hub.listing_sales | Share to 1 subscriber; 1 shared object. Consumer reads are not seen by this scan. |
F10 · Security to rebuildTo review
2 findings
| Target | Observed |
|---|---|
| object lab-a.raw.rap_country | Row access policy applied to 1 object; it does not leave with the copy; the copy requires an unfiltered principal. |
| table lab-a.raw.customers | Policies: pt-pii, rap_country. They do not leave with the copy; the copy requires a principal not filtered by these policies. |
F11 · Scheduled chain and its failuresTo review
4 findings
| Target | Observed |
|---|---|
| object lab-a.sq_daily_kpi | Scheduled query, schedule every 24 hours, state active; 180 runs, 3 failures, last on 2026-10-17. |
| object lab-a.sq_export | Scheduled query, schedule every day 05:00, state active; 180 runs, 0 failures. |
| object lab-a.sq_old | Scheduled query, schedule every 1 hours, state disabled; 0 runs, 0 failures. |
| object lab-a.sq_weekly | Scheduled query, schedule every monday 06:00, state active; 26 runs, 0 failures. |
F12 · Incomplete readTo review
3 findings
| Target | Observed |
|---|---|
| read B15 | API connections.list not read (missing privilege); limits: external connections (F01). |
| read B18 | `region-eu`.INFORMATION_SCHEMA.RESERVATIONS not read (privilege level not requested); limits: reserved capacity. |
| read B22 | `region-eu`.INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION not read (privilege level not requested); limits: queries run from other projects. |
No finding for: F04, F07. An absence of findings only holds for the reads done (see F12 and the method).
What this report does not quantify
- Average billed storage: not provided by collection.
- Storage cost: your contract price not read.
- Reserved, in dollars: your contract price not read.
- Copy read cost (Storage Read API, network egress): your contract price not read.
- Your contract rate: your contract price not read.
- Destination storage, running both platforms in parallel, operations after the exit: depend on your contract and your architecture.
- Identical results of translated queries: accepted ≠ identical result: translated to DuckDB, not compared; a canot drill compares the results.
- Cost projections provided by the platform: not used: they cannot be verified from the scan.
- BigQuery free tier: shared by the billing account, cannot be attributed per project.
- Reads through the Storage Read API: missing from INFORMATION_SCHEMA.JOBS.
- Billed bytes of queries under a row access policy: NULL value in INFORMATION_SCHEMA.JOBS.
Using this report for your regulatory work (GDPR, DORA, NIS2, Data Act, SecNumCloud, EBA)
These elements can support your own work on GDPR, DORA, NIS2, the Data Act, SecNumCloud or the EBA outsourcing guidelines. They are evidence, not a finding: this report is not a certification, it is not legal advice, and it does not say whether your contracts or your organization meet any regulation.
| Framework | What it asks, in short | What this report gives you | What it does not cover |
|---|---|---|---|
| DORA (Regulation (EU) 2022/2554) | Art. 28(8) and 30(3)(f): a realistic transition, with an adequate period. | Measured throughput and a recovery time range from the exercise; a copy duration range (estimated) in the scan. | Excludes human validation and the cutover of your applications. |
| DORA (Regulation (EU) 2022/2554) | Art. 28: knowing what depends on the ICT provider. | What does not move as is: views, routines, tasks, policies, external dependencies, with the evidence behind each finding. | An inventory of the platform, not of your contracts or of the applications connected to it. |
| Data Act (Regulation (EU) 2023/2854) | Art. 29: switching charges are withdrawn from 12 January 2027. | The effort that remains yours: read cost, copy duration and rework estimates, each marked measured, computed or estimated. | Says nothing about charges your provider may still apply before that date. Prices are dated catalogue figures, not your contract. |
| GDPR (Regulation (EU) 2016/679) | Chapter V (transfers) and Art. 32 (security of processing). | Where the copy is hosted, and which security objects do not move with it (masking and row policies, tags). | The hosting location is the destination you chose. The legal assessment of a transfer is yours. |
| GDPR (Regulation (EU) 2016/679) | Art. 5(1)(c): data minimisation. | The scan reads metadata and execution history, not table contents. SQL text is masked and identities are pseudonymised. | Applies to the scan only: an exit exercise (drill) reads the data it copies. |
| NIS2 (Directive (EU) 2022/2555) | Art. 21(2)(d): security of the supply chain, including your relationship with each direct service provider. | What ties you to this provider: external dependencies and objects that do not move as is, with the evidence behind each finding. | Does not assess the provider's security measures. |
| EBA Guidelines on outsourcing arrangements (EBA/GL/2019/02) | Exit strategies: documented, realistic, sufficiently tested and reviewed periodically for the outsourcing the guidelines target. | The exit exercise (drill) and the inventory of what does not move (scan), as test evidence in your exit file. | One exercise. Alternative providers, the business side and the periodic review are yours. Check which text applies to you alongside DORA. |
References as of 2026-10-19. Check the current texts: they evolve, and their application depends on your situation.
Method
18 reads done out of 22. Each read is recorded with its status and its reason; a value that was not read stays empty, never 0.
| Id | View | Status | Reason | Rows | Window | Latency |
|---|---|---|---|---|---|---|
| B06 | `region-eu`.INFORMATION_SCHEMA.TABLE_STORAGE | not read | absent or not exposed; limits: none: tables.get read instead | not read | ||
| B15 | API connections.list | not read | missing privilege; limits: external connections (F01) | not read | ||
| B18 | `region-eu`.INFORMATION_SCHEMA.RESERVATIONS | not read | privilege level not requested; limits: reserved capacity | not read | ||
| B22 | `region-eu`.INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION | not read | privilege level not requested; limits: queries run from other projects | not read | ||
| B01 | API datasets.list | read | 10 | |||
| B02 | API datasets.get | read | 10 | |||
| B03 | `region-eu`.INFORMATION_SCHEMA.TABLES | read | 10 | |||
| B04 | `region-europe-west1`.INFORMATION_SCHEMA.TABLES | read | 10 | |||
| B05 | `region-us`.INFORMATION_SCHEMA.TABLES | read | 10 | |||
| B07 | API tables.get | read | 10 | |||
| B08 | `region-eu`.INFORMATION_SCHEMA.TABLE_OPTIONS | read | 10 | |||
| B09 | `region-eu`.INFORMATION_SCHEMA.COLUMN_FIELD_PATHS | read | 10 | |||
| B10 | `region-eu`.INFORMATION_SCHEMA.JOBS | read | 10 | from 2026-04-20 to 2026-10-17 | 0.1 h | |
| B11 | `region-europe-west1`.INFORMATION_SCHEMA.JOBS | read | 10 | from 2026-04-20 to 2026-10-17 | 0.1 h | |
| B12 | `region-us`.INFORMATION_SCHEMA.JOBS | read | 10 | from 2026-04-20 to 2026-10-17 | 0.1 h | |
| B13 | API transferConfigs.list | read | 10 | |||
| B14 | API rowAccessPolicies.list | read | 10 | |||
| B16 | `region-eu`.INFORMATION_SCHEMA.SCHEMATA_LINKS | read | 10 | |||
| B17 | `region-eu`.INFORMATION_SCHEMA.SHARED_DATASET_USAGE | read | 10 | |||
| B19 | `region-eu`.INFORMATION_SCHEMA.ROUTINES | read | 10 |
… and 2 more in reads.csv.
Privileges used
Level 2: bigquery.jobs.create, jobs.listAll, datasets.get, tables.list, tables.get, routines.list, routines.get, models.list, models.getMetadata, rowAccessPolicies.list, transfers.get, connections.list, dataPolicies.list (optional). Never requested: tables.getData, bigquery.user and jobUser roles.
Cost of the scan
| Item | Value | Nature and basis |
|---|---|---|
| Queries sent | 20 queries
| computed · B01, B02, B03, B04, B05, B06 … reads attempted, read or refused by the platform |
| Read time | Not read: duration not provided by collection. | not read |
Safeguards
- Every SQL statement sent goes through a read-only guard: only SELECT, SHOW, DESCRIBE and ALTER SESSION SET statements go out. No write, no API activation, no parameter change.
- Query users and roles pseudonymized with HMAC, using a salt drawn for this scan and never written; tag values hashed; locations reduced to the bucket.
- Raw SQL text is never written: only normalized forms, with literals masked, leave collection.
Rules
- Movement: recreated: DDL less than 7 days old with no later write; live: write less than 30 days old; frozen: older last write; not determined: writes not read.
- Storage with no read: actual window of the view read, compared with 180 days; the blind spots of each view are listed in the finding.
- Copy time: assumed throughput of 20 to 80 MB/s.
- List prices are dated and sourced; they do not replace your contract price.
Next steps
This report describes your platform; it recommends neither leaving nor staying.
To measure an exit on a chosen scope: canot drill copies to Apache Iceberg, compares source and copy, and signs an evidence report.
To go further, the q4o assessment, from €22,000 excl. VAT: your contract rate, actual execution, scenarios, the steps to follow. canot.io