Skip to content

feat(infra): Infrastructure → Google Cloud page - #1336

Open
JeremyFunk wants to merge 86 commits into
feat/gcp-dashboard-templatefrom
feat/gcp-infra-page
Open

JeremyFunk wants to merge 86 commits into
feat/gcp-dashboard-templatefrom
feat/gcp-infra-page

Conversation

@JeremyFunk

@JeremyFunk JeremyFunk commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Top of the Google Cloud integration stack. Merge order: bottom up.

Adds Infrastructure → Google Cloud (/infra/gcp) at the feature level of the Railway and Cloudflare infrastructure pages: a health band and one table per curated service built from the gcp.* metrics, a page per workload with its charts, the resource inventory from gcp_resources, and the workloads on the Infrastructure overview and the service map.

Parity matrix

What each infrastructure integration has. "Before" is this PR as first opened (tables only).

Feature Railway Cloudflare PlanetScale Kubernetes / hosts Google Cloud before Google Cloud now
Summary above the list Fleet band: services by peak of limit KPI tiles: requests, 5xx rate, cache hit, bandwidth KPI tiles: databases, branches, worst gauges Fleet band: saturated, elevated, stale None Fleet band over every service: saturated, elevated, erroring
Summary cells narrow the list Yes (scope in the URL) No No Yes No Yes (scope in the URL)
Sparklines on the summary No Yes No No No No (see Not built)
Fleet charts on the index No Yes, by zone No No No No (see Not built)
Workload table, sortable Yes Yes Yes Yes Yes Yes
Search Yes, in the URL Yes, local Sidebar Yes Local Yes, in the URL
Trend sparklines in table rows No (limit meters) No No No (limit meters) No No; a share of a limit and an error rate take their severity color
Filters None Zone page sidebar Branch sidebar Sidebar Type and project on Resources Project and region on every service tab, type and project on Resources, all in the URL
Row opens a detail page Yes Yes Yes Yes No Yes, for every service; Resources rows that are one workload too
Detail page: headline numbers 4 tiles 4 tiles Chips 4 tiles n/a 4 tiles, the first columns of the workload's row
Detail page: charts CPU, memory, network, disk Status classes, cache statuses, latency percentiles, breakdowns Storage, connections, CPU, memory, replica lag CPU, memory against limit and request n/a 4 to 8 per service, listed below
Linked hover cursor across charts Yes Yes Yes Yes n/a Yes
Resource metadata on the detail page Project and environment chips Zone chip Kind, region, plan chips Resource attributes rail n/a Service and identity chips, and the inventory panel in the rail with a link to the product's console page
Time range in the URL, session-sticky, timezone preference, Reload Yes Yes Yes Yes Yes Yes, on the workload pages too
Links to logs, traces, metrics explorer No No No Service lens opens the service No Logs, Traces when a traced service of the name exists, one explorer link per chart
Service lens (/infra/kubernetes/services) No No No Kubernetes only No No: the lens joins on k8s.deployment.name from the collector, which Cloud Monitoring series do not carry
Service map No Edge numbers in the panel of the matching Worker Database nodes Workloads tab No Numbers of the same-named Cloud Run service, function, GKE container or VM in the service panel, with a link
Overview: health strip and findings Yes Yes Yes Yes Names only Yes
Not connected, setup, waiting, quiet, failing, stalled, off states Not connected, syncing, empty Not connected, permissions, ingest phases Setup steps, paused Empty state, install Yes Unchanged, plus per-page loading, error and no-metrics states
Alert menu from the page No No Yes No No No

Google Cloud now has everything Railway and Cloudflare both have, and the cheap extras: the scope cells, the rail panel, the links out, and the service map panel.

The index page

  • Band above the tabs, the FleetBand Railway and the hosts page use: every service's workloads in the selected project and region, split healthy, elevated and critical, with three cells that narrow the tables. Saturated: a percent column (every one is a share of a limit or of capacity) at 90% or more. Elevated: 60% or more. Erroring: an error rate of 1% or more over at least 100 events, the thresholds errorRateLevel and utilizationLevel already set for the rest of the app.
  • Tabs are the link tab strip Hosts, Kubernetes and Alerts use (UnderlineTabStrip; UnderlineTabCount for the count a band cell adds), so height, gap, underline and divider are theirs. The strip sits in the page below the band, not in the header slot those pages use: the band counts every tab, so under header tabs it reads as the selected tab's, and the tab list is only known once the fleet has loaded. On a phone it scrolls sideways. All tabs are read at once (one presence probe, then one query per reporting service), which is what lets the band count every service and a tab switch read nothing.
  • Tables: rows are links to the workload's page; a name search (q), a project and a region filter and the band's scope are in the URL and carry across tabs. The filters show once there is more than one project or region; the region filter is left off the Pub/Sub and Load Balancing tabs, whose resources are global. A VM's zone counts as its region. With a band cell active each tab shows how many of its workloads it holds. A Cloud SQL instance is named without the project Cloud Monitoring puts before it.
  • Resources: a row that is one workload (a Cloud Run service, a 1st gen function, a VM, a Cloud SQL instance, a subscription) opens that workload's page.

Workload pages

/infra/gcp/$service/$name, with the rest of the workload's identity as readable search params (?project=…&region=…). Built from PageHero, StatRail, ChartCard and InfraMetricChart, as the Railway page: every chart is a line chart, with the legend in the card header.

Service Charts
Cloud Run Requests by response class, 5xx rate, request latency p50/p95/p99, instances (active, idle), CPU utilization p50/p95/p99, memory utilization p50/p95/p99, peak concurrency per instance p50/p95/p99, billable instances
Cloud Functions Executions by status, error rate, execution time p50/p95/p99, instances (active, idle), memory per execution p50/p95/p99, network egress
GKE CPU cores, CPU of limit, memory (non-evictable, evictable), memory of limit, restarts; then the cluster's nodes: CPU and memory of allocatable
Compute Engine CPU utilization, memory used (E2 only), network received and sent, disk read and written
Cloud SQL CPU, memory and disk utilization, connections, disk read and write operations, replica lag
Pub/Sub Backlog, age of the oldest unacked message, delivered and acked per second, dead-lettered, push requests by response, push error rate
Load Balancing Requests by response class, 5xx rate, total latency p50/p95/p99, backend latency p50/p95/p99, backend requests by response class, request and response bytes per second
  • Units: shares as percent with the 80% rule, bytes and bytes per second (named in the chart title, bare sizes on the axis), milliseconds (replica lag and message age are converted from seconds), cores, per-second rates for counters including the by-class charts, plain counts for instances, connections and messages (a new count chart unit). A rate divides by the part of the first and last bucket the range covers.
  • Silence is drawn as silence. A Cloud Run service scaled to zero reports nothing. Every bucket between the first and the last the workload reported in is kept: a counter reads zero there, every other line has a gap, and a value between two gaps is a dot. InfraMetricChart takes this as an opt-in gaps prop; its other callers are unchanged.
  • The four tiles say what they are: total in range, average in range or share in range.
  • A chart a workload can never fill says why (E2 machine types only., Read replicas only., Push subscriptions only.).
  • Inventory panel in the right rail when the workload is exactly one inventory row by asset type, project, last name segment and, where the workload has one, location: type, name, project, location, state, labels, and a link to the product's list page in the Google Cloud console, opened on the resource's project (VM instances in Google Cloud). A GKE container shows its cluster. Zero or several candidates show no panel.
  • Links: Logs (the workload's service.name; a managed service opens gcp/<resource type> narrowed by the identifying resource attribute: a URL map opens gcp/http_load_balancer, the type Cloud Logging writes, and a subscription is matched by its full path, which is how Cloud Logging labels it), Traces when the service overview lists a service of that name in the range, and beside each chart title its metric in the metrics explorer, filtered to the workload (service.name, or the resource attribute for a managed service) and grouped by percentile or label as the chart is.

Elsewhere in the product

  • Infrastructure overview: the Google Cloud row has the health strip and up to three findings (critical first), each opening the workload's page. While everything is healthy it still names the services that report. A service whose read failed is a finding of its own (Pub/Sub metrics could not be read, opening that tab) and leads the row's headline; when no service could be read, the row shows the failed-read state every other source has.
  • Service map: the detail panel of a traced service shows a Google Cloud section when a Cloud Run service, function, GKE container or VM reports under the same name: the first four columns of its row (totals marked as such) and a link to its page. It reads nothing unless a connection collects metrics.

Numbers on the integration page

The connected integration page opens with a row of numbers, like the Cloudflare page's (gcp-usage-cards.tsx, rules in gcp-usage.ts with tests). No new endpoint, query or table: every number comes from a read another page already makes.

Tile Source What it reads
Log entries · 24h, with hourly bars and an hourly average The Logs page's volume query (customChartTimeSeries, source: logs, hourly, grouped by severity) with the resource attribute filter maple_ingest_source = gcp-logpush, the stamp ingest puts on every forwarded entry The raw logs table for the org and the last 24 hours. No rollup carries the ingest source, so the filter is the same index-assisted attribute predicate the Logs page runs for that filter. One read per page view, 30 s stale time
Errors · 24h (Warnings · 24h when logs deliver alone) The same read: the severities of its series Nothing more
Workloads · 24h getGcpInfraFleet over 24 hours: the presence probe on metric_catalog, then one query per reporting service What the Infrastructure overview reads for its Google Cloud row
Resources (Projects when metrics deliver alone) GET /internal/integrations/gcp/resources without filters Postgres: totals, types and projects of the inventory
  • The row follows what has delivered: both capabilities give four tiles, one alone gives three of its own, nothing delivered gives none. A number that cannot be counted yet is a dash.
  • Under the row, Workloads by Google Cloud service links each reporting service to its tab here. Each connection's metrics line links to this page; its log line opens Logs filtered to the entries stamped with that connection's id.
  • Numbers are per organization, not per connection: a count per connection would be one raw-log read per connection.
  • A 24-hour total leaves out the partial first hour, as the volume chart does.
  • A tile whose read fails says so; the status below it does not depend on any of these reads.
  • The three prompts and the notice of this page that told the reader to switch metrics on, or to open the setup script, now name Configure (copy only).

Queries

Three builders in packages/query-engine-integrations/src/gcp/gcp-infra.ts, all through WarehouseQueryService.compiledQuery() and pinned in the SQL baseline.

  • gcpInfraMetricsSQL(service) (unchanged SQL): one query per tab. Scans metrics_sum and metrics_gauge, each filtered by OrgId, MetricName IN (that table's curated names of the service's group) and TimeUnix in the range, grouped by identity, metric and label. Capped at 10,000 rows.
  • gcpInfraTimeseriesSQL(source, keys) (new): one query per workload page, serving every chart and the headline tiles. The same two scans with the same OrgId, metric-name and time bounds, plus one equality per identity attribute of the workload (ResourceAttributes[...] = '<value>', 2 to 5 of them), grouped by toStartOfInterval(TimeUnix, bucket), metric and label. At most about 100 buckets (5-minute floor) times the group's metric and label values, capped at 10,000 rows. The GKE page issues it a second time for the gkeNodes source (2 metrics, the cluster's identity).
  • gcpInfraPresenceSQL() (unchanged): the hourly metric_catalog rollup.

The index page, the overview row and the service map panel read the same getGcpInfraFleet: the presence probe, then gcpInfraMetrics once per reporting service (at most 7), concurrently. Before, the page read the probe and the open tab only.

Endpoints: POST /internal/query-engine/gcp-infra-timeseries (session-only; source is a closed literal, bucketSeconds is BucketSeconds, keys is at most 8 strings of at most 512 characters, the times are TinybirdDateTime). GET /internal/integrations/gcp/resources takes name, the last segment of the resource name, compared in SQL on the rows the org, type and project filters already narrowed; no index was needed.

No datasource, materialized view, poller, receiver or connector API change. No metric type was added.

Metrics parity would still need

Not added: every type costs the customer Cloud Monitoring reads, and the list belongs to #1333.

Metric or label What it would enable
kubernetes.io/container/cpu/limit_cores, memory/limit_bytes, cpu/request_utilization, memory/request_utilization Railway-style "of limit" meters with the limit named, and the request charts the Kubernetes pod page has
kubernetes.io/container series per pod (pod_name kept) A pods-behind-this-container table, as the Kubernetes workload page has
agent.googleapis.com/memory/percent_used, disk/percent_used (Ops Agent) Memory and disk utilization for VMs that are not E2
cloudsql.googleapis.com/database/up, database/memory/quota, disk/quota An up/down state and absolute sizes beside the Cloud SQL shares
run.googleapis.com/request_count by revision_name A breakdown by revision, the counterpart of Cloudflare's breakdown panel
pubsub.googleapis.com/subscription/ack_latencies, the subscription's topic_id Ack latency, and the topic's publish rate on the subscription's page
loadbalancing.googleapis.com/https/frontend_tcp_rtt, internal and regional rule types Client round-trip time, and load balancers that are not global external

Not built

  • Sparklines on the band and fleet charts on the index (Cloudflare has both, Railway neither): both need a bucketed query over every service, which no existing builder serves.
  • A filter sidebar with facet counts: two selects in the toolbar, the control the Resources tab already has, cover project and region.
  • Service lens: Kubernetes only among the references.
  • Meter bars and a last-seen column in the tables (Railway has them): the tables keep the numeric columns of the first version, as the Cloudflare tables do.
  • A "more" row under the three overview findings (hosts have one): Railway and Cloudflare stop at three, and the source row beside them carries the count.
  • Pub/Sub topic and Cloud Run job pages: topics have one metric and jobs none in the curated table.
  • Resources rows for a GKE cluster, a URL map or a 2nd gen function open no page: a cluster is many containers, a URL map one page per backend, and a 2nd gen function's Cloud Run service name is derived by Google.
  • An alert menu (PlanetScale only).

Empty and waiting states

State Shown
No connection Full-page prompt to connect, linking to Integrations → Google Cloud
Connections with metrics off, data in the range The tabs with what was collected before, under a neutral notice Google Cloud metrics are off with Open the integration. No Resources tab: the inventory of a connection that stopped collecting is not listed
Connections with metrics off, no data in the range Full-page prompt to turn metrics on under Configure and run the script
Metrics on, no connection's setup script has run Full-page prompt Finish setting up Google Cloud with Open the integration; the page polls status every 10 s and moves on without a reload
The script ran, no read yet Collecting your first Google Cloud metrics with a spinner and the 10-minute expectation, no status code and no button; the Resources tab polls while the inventory is empty
Reads fail and nothing was read in the last 10 minutes Warning Maple can't read Google Cloud metrics with the message and Check the connection
A read from the last 10 minutes came with failed or cut-short queries Warning Some Google Cloud metrics are missing with the message
No read for 30 minutes, no error Warning Google Cloud metrics have stalled
Metrics arrive, none in the range Banner asking to widen the range or reload; on a preset range the presence poll continues, so the tabs appear once the first metrics are queryable
A tab's service is quiet Empty table row
Resource list incomplete (last_resources_error) Notice above the Resources table only; it is not a metrics problem
?tab= names no tab The first tab, not the error page
Inventory empty or filtered to nothing Empty table row

These call gcpMetricsState from the integration card, so the page and the card cannot disagree. A Google Cloud console address in a failure message is a named link.

New on a workload page: chart skeletons while loading, the shared error state when the query fails, No metrics arrived for this <noun> in the selected window. when the workload did not report (the inventory panel still shows), and a per-chart message when one metric is absent. An unknown $service opens the list. A tab whose query failed says so in its table instead of reading as empty.

Inventory read path

  • GcpConnectorService.resources(orgId, { assetType?, projectId?, name? }), served by GET /internal/integrations/gcp/resources (session-only, filters are bounded strings).
  • Org scoping goes through gcp_connectors.org_id joined on the primary key prefix (connector_id, …), so no new index is needed.
  • Returns the first 500 matches by asset type and name, the total match count, and the facets of the whole inventory (types with counts, project ids). Overlapping connections list a resource once per connection; it is shown and counted once, from the freshest sync.
  • A connection with metrics switched off keeps its last inventory in the table but is left out of the read.
  • No join between inventory and metrics: a workload page asks for its one resource by type, project and name.

Decisions

  • Rows are returned long and folded in the browser instead of one hand-written wide query per service. One generic builder serves seven tabs, and adding a column needs no backend change. The cost is a larger payload and an alphabetical cap instead of a top-N by a metric.
  • The inventory endpoint is internal although the connector API is v2. docs/api-v2.md says so.
  • Nav preview: a seventh glyph would have dropped the closed Infrastructure row's miniatures. The preview now skips the child that is the section's own page (Overview), so it still draws six.
  • routeTree.gen.ts is staged with the generator's lines for the two routes and nothing else: the route cannot typecheck without them.
  • CI path filter: the ClickHouse SQL catalog sweep analyzes the integration builders but did not trigger on packages/query-engine-integrations/**, so it was skipped on this PR's first run. The filter now includes that path; the sweep ran and passed against ClickHouse 26.2.
  • Default range is 1 hour.
  • Health is read off the columns. Every percent column is a share of a limit or of capacity and every errorRate column carries its event count, so the band, the table colors, the overview findings and the workload tiles share one rule and no service has thresholds of its own.
  • One page type for seven services. A service is a list of chart specs (charts.ts); the page, the query and the endpoint are shared. A test checks every chart reads only metrics its page's query returns.
  • Readable addresses. A workload's identity is /infra/gcp/<service>/<name>?project=…&region=…, by lower-cased identity label, with a round-trip test over every service.

Known limits

  • Connections with overlapping scopes store each series once per connection, so the counters of those workloads read multiplied. The fix belongs in the poller.
  • Means cover the minutes a series reported.
  • The health band rates the average over the range, where Railway rates the peak: the tab query returns sums and counts, not maxima.
  • The console link opens the product's list page, not the resource: Google documents the list pages (run/services, kubernetes/list, compute/instances, sql, cloudpubsub/subscription, net-services/loadbalancing/list) and not the per-resource addresses, and a link that might 404 was not worth it.
  • A chart's explorer link filters by the workload's name only. Two workloads of one name in different projects or regions open together there.
  • Shared behaviour this page inherits: a long workload name wraps in the top bar at phone width; an axis on a multi-day range labels hours without dates; byte ticks are binary (572 MB); a latency axis starts at 0μs.
  • A percentile drawn over a bucket longer than a minute is the mean of the per-minute percentiles.

Visual smoke checklist

On an org with a Google Cloud connection that collects metrics, with a 7-day range:

  • /infra/gcp: the band counts the workloads of every tab; each cell narrows the open tab, puts a count on every tab and stays when the tab changes; a second click clears it.
  • Every service tab: rows open the workload page; the project and region selects appear once there are two of either; search, filters and scope survive a reload.
  • Resources: a Cloud Run service, a VM, a Cloud SQL instance and a subscription row open their workload page; a project, a cluster and a URL map row do not.
  • One workload page per service: four tiles each marked total, average or share, every chart in its unit (percent, bytes, bytes per second, milliseconds, cores, per second, counts), the 80% rule on shares of a limit, one cursor across the charts on hover.
  • A Cloud Run service that scaled to zero: requests read zero between its bursts, latency and instances have gaps, a single burst on a 7-day range is a dot.
  • A Compute Engine instance that is not E2 says E2 machine types only. in the memory card; a Cloud SQL primary says Read replicas only. in the lag card; a pull subscription says Push subscriptions only. twice.
  • A GKE container's page ends with Nodes of <cluster> and two charts.
  • The rail panel shows on a workload that is in the inventory, and its link opens the product's list page in the console on the resource's project.
  • Logs opens the workload's logs (a subscription's and a URL map's too); Traces shows only for a workload whose name is a traced service; the icon beside a chart title opens that metric in the metrics explorer, filtered to the workload and grouped as the chart is.
  • /infra: the Google Cloud row has a health strip, and a finding per flagged workload that opens its page.
  • /service-map: the panel of a traced service named like a Cloud Run service has a Google Cloud section.
  • 390px wide: the band stacks, the tables scroll sideways, the charts are one column.

After the merge with main

main moved Postgres to effect-orm (#1353) and landed two passes over the shared UI primitives (#1355, #1358). This branch merged them through the layers below.

  • Inventory read on effect-orm. The same two statements: count(DISTINCT name) by asset type and project over gcp_resources JOIN gcp_connectors for the organization's metrics-enabled connections, and SELECT DISTINCT ON (asset_type, name) ... ORDER BY asset_type, name, last_seen_at DESC LIMIT 500. The name filter is still split_part(name, '/', -1) = $n, as a PG.sql template.
  • Presence query. Its start bound is floored to whole seconds (utcSecondsParam), as main now does for every bound inside toDateTime() (fix: warehouse DateTime bounds, run_sql caller errors, Cloudflare 402 and chat rate-limit noise #1354): a bound with milliseconds does not parse there.
  • Startup bundle. The index route's search schema spells out the three scope literals, as the hosts and Railway pages do, instead of importing them from the tab model. The import had put the tab model and the connection-state rules into every page's startup: 696.2 KB of initial JS against the 695 KB budget once main's own growth was merged in, 690.6 KB without it.
  • List filters. main made the toolbar search default-size with default-size selects beside it; the project, region and type filters follow.
  • Sibling primitives. The tab strip is UnderlineTabStrip (see The index page). A search, filter or scope that leaves nothing shows FilteredEmpty, as on the Railway and Hosts lists. Every error state has a title and a retry.
  • Rendered again on 2026-10-10 from the stack top against a fresh database built by the new migrations: the integration page (nothing connected, healthy, the menu, both dialog stages, a pending change, failures) and the index, Resources and workload pages, at 1440 and 390. Compared with the approved screenshots, the differences are main's: icons inside buttons are 14px (16px before, 18px on a phone), and the list search is 32px high (28px before).

The preview's database

The preview's database was built by this stack's earlier drizzle-kit migrations, which are gone from the folder. The deploy applied the four folders it had not recorded without a reset: every statement of the two new migrations is IF NOT EXISTS, except the foreign key of gcp_resources, which was added under its new name next to the old one. On the preview that table therefore carries the same foreign key twice; a fresh database has it once. To remove the leftover there:

ALTER TABLE gcp_resources DROP CONSTRAINT gcp_resources_connector_id_gcp_connectors_id_fkey;

Review notes

Code reviews

Two read-only reviews of the parity work ran before the push (queries, endpoints and inventory; web), on top of the two from the first version of this PR.

Applied:

  • The workload query compares ServiceName, the tables' second sort key column, so it reads the workload's rows instead of the org's (the name is the workload's own for compute and gcp/<resource type> otherwise, from one helper the web shares).
  • Its conditions are a tuple again, so the query's param type keeps orgId and the time bounds.
  • A rate divides by the part of the first and last bucket the window covers, so a counter chart no longer dips at its edges.
  • One service's failing query no longer fails the page, the overview row and the service map panel: that service comes back empty and marked, and its tab says the read failed.
  • A load balancer's chart links open its metrics (gcp/https_lb_rule), its Logs button its logs (gcp/http_load_balancer); the two names were one.
  • The Cloud SQL connections chart links the metric the instance's engine reports.
  • A refresh dims the tiles and charts together.
  • URL map keeps its capitals in the no-metrics message; the docs say which charts draw percentiles and that region and scope apply to the service tabs.
  • Maple review F3 (an empty type= or project= in the address broke the Resources read): an empty param is no filter.
  • Leaner: split_part(name, '/', -1), ChartCardMessage instead of a local empty state, six exports dropped.

Not applied:

  • Dropping the trailing, still-filling bucket: the newest points are worth more than a flat right edge, and the poller's five-minute delay would leave it short either way.
  • Reading the connection status in the service map through gcpStatusQuery(): it would pull the integration catalog module into the service map; the sidebar hook builds the same atom inline for the same reason.
  • GCP_INFRA_SOURCES.gkeNodes.title is unread: the record's type asks for it.

Rendered rounds

Two rounds of a reviewer who saw only screenshots (every tab and every workload page at 1440 and 390, the overview, the service map panel, and where each link landed), compared against the Railway and Cloudflare pages.

Round 1, applied:

  • Lines were drawn across the hours a scaled-to-zero service reported nothing: silence is now zero for counters and a gap for everything else.
  • The by-class charts were Cloudflare's stacked areas, whose outlines did not match the legend once a class was zero: they are lines per second now, and the Cloudflare component is untouched again.
  • Explorer links for managed services opened every resource of the type, and blended the percentiles: they filter by the resource attribute and group by quantile or label.
  • The Pub/Sub Logs link found nothing: Cloud Logging labels a subscription with its full path.
  • Rate ticks were clipped (391 KB/s read 91 KB/s) and a small container's CPU axis read 0, 0, 0: fixed in InfraMetricChart and formatValueWithUnit, for every page that uses them.
  • Legends moved into the card headers so plots in a row align; titles that wrapped were shortened; rate charts name their unit in the title.
  • Overview findings are worst first within a tone and read orders-db-replica at 93% disk.
  • Tiles say total, average or share; tabs show a count while a band cell is active; the region filter is off the global tabs; Cloud SQL instances lose the project prefix; the breadcrumb is three levels with the service as a chip; rail labels have a heading.

Round 2, applied:

  • A single reporting bucket between two gaps drew nothing: it is a dot.
  • Tile sublines fit a phone; the load balancer's Response size column is Bytes sent; the GKE chart is titled CPU cores; disk and instance series were renamed so their colors differ.

Not applied, from both rounds:

  • The overview's words ok / elevated / saturated beside the page's Saturated / Elevated / Erroring: the overview has one vocabulary for every source, and its critical bucket holds Cloudflare's erroring zones too.
  • Shared shell and formatters: the top bar at phone width, hour-only ticks on long ranges, binary byte ticks, 0μs, the 80% label over a line at 81%, rail values breaking mid-word.
  • The GKE tile in millicores above a chart in cores: the table's format is the documented one, the chart's is the Kubernetes pages'.
  • The Resources tab's order, missing sort and missing search: unchanged from the first version of this PR.

From the first version of this PR

Two read-only reviews ran before the PR was opened (queries, endpoints and inventory; web). Applied: the stale inventory of stopped connections is excluded, the freshest copy of a duplicated resource wins, the where-conditions keep their param types, the quiet state keeps polling on preset ranges, the inventory re-reads while empty and on connector changes, the tab strip no longer clips its underline, the overview knows the source, and guards for impossible states were removed.

Not applied:

  • Maple review F1 (samples: Schema.Number would reject a quoted 64-bit count from a BYO ClickHouse): the response schema never sees the warehouse's wire value. The executor decodes every row through the query's derived row schema first, and count() derives the UInt64 codec, which unquotes it. gcp-infra.test.ts now pins that (samples: "60" decodes to 60).
  • Maple review F2 (a required reported field breaks decoding of stored removed connections): not changed. The stored list was only ever written by pre-release builds of this stack, so no customer browser holds the earlier form. A stored value that does not decode is not an error either: Atom.kvs in sync mode skips a failed read and the atom keeps its default, the empty list.
  • Maple review F4 (an empty project= or region= in the address emptied every service tab): fixed. The page reads the filter params once, with empty meaning unset, and the service tabs, the tab links and the Resources tab use that.
  • Maple review F5 (summarizeGcp counted a service whose read failed as no workloads, so the overview read ok): fixed. Such a service is a finding and is named on the Sources row; with no service readable the source shows its failed-read state.
  • De-duplicating metrics across overlapping connections in the tab query: it needs a per-timestamp group over the raw rows, and the duplication is the poller's to avoid.
  • Keeping the sidebar entry and the overview row while metrics are switched off but collected data is still in range (raised in the final rendered check): both follow the switch through the status read the hub already makes, and following stored data instead would put a warehouse read into the nav hook. With metrics off everywhere the page opens by its address and shows what was collected.
  • Handling metrics_available: false on the page: the nav row never appears there, and the integration card already explains it.

Verification

  • Query tests (gcp-infra.test.ts, 10): the workload read is bounded by OrgId, the service's metric names, the time range, ServiceName and every identity attribute; a missing key compares as empty; quotes in a key are escaped; the node source reads gcp/k8s_node. The SQL baseline gains one fixture per source (8) and changes no existing query.
  • GcpConnectorService.test.ts: the name filter matches the last segment only.
  • Web unit tests: tabs.test.ts (36: health levels, the event floor, scopes, the identity round trip through the address, display names), charts.test.ts (16: every chart reads only metrics its page's query returns, rates, classes per second, silent buckets, edge buckets, the explorer's metric and grouping, the fold into the table row's numbers), inventory.test.ts (15: exact match, no match between two candidates, the resource-to-workload round trip, console pages, log, trace and explorer filters), summaries.test.ts (overview segments and findings), chart-utils.test.ts (the count unit, sub-millicore values).
  • CI on the pushed commits: typecheck, lint, tests, the ClickHouse SQL catalog sweep and the web perf suites pass.
  • Rendered against a local stack on 2026-10-09: the real project's metrics and logs for Cloud Run, GKE, Compute Engine and Pub/Sub, and synthetic series in the poller's row layout for Cloud Functions, Cloud SQL, a load balancer URL map and a Cloud Run service named like a locally traced service (the test project has none of those). Every tab, every workload page type, the overview, the service map panel and ten click-throughs (row, resource row, band cell, finding, Logs for a service and a subscription, Traces, two explorer icons, the service map panel), at 1440 and 390, in three capture iterations with two screenshot-only review rounds between them. The inventory rows and the synthetic series were seeded locally and removed afterwards.
  • Not exercised: the console links against a signed-in console (they are the list pages Google's documentation links), hover states, and a connection with overlapping scopes.

End-to-end run

Final regression on 2026-10-10 against a real Google Cloud project at project scope, from the stack top.

  • Passed: the first-time flow, the setup report, a real Cloud Run workload (percentiles and request counts equal to Google's for 22 consecutive minutes), switch changes, the log filter modes, customer-caused failures, and all disconnect paths.
  • Not run: organization and folder scope, a real Cloud Shell session (a Cloud SDK container on bash 5.2 was used), non-admin views, and the plan-limit and rate-limit states.

Summary by CodeRabbit

  • New Features
    • Added Google Cloud infrastructure monitoring for Cloud Run, Cloud Functions, GKE, Compute Engine, Cloud SQL, Pub/Sub, and load balancing, with workload tables, charts, health indicators, and a filterable resource inventory.
    • Added Google Cloud metrics and resource summaries to the infrastructure overview, integration pages, and service details, including links to relevant workloads and resources.
    • Updated Google Cloud log setup to select which runtimes’ application logs to forward or keep an existing filter.
  • Documentation
    • Updated Google Cloud setup, filtering, verification, and troubleshooting guidance.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ac133547-a1a5-41e0-bc8e-2e90e9e3f89d
📥 Commits

Reviewing files that changed from the base of the PR and between e55428d and f13e8d8.

📒 Files selected for processing: 4
  • apps/web/src/components/infra/gcp/gcp-service-table.tsx
  • apps/web/src/components/infra/gcp/tabs.test.ts
  • apps/web/src/components/infra/gcp/tabs.ts
  • apps/web/src/routes/infra/gcp/index.tsx
💤 Files with no reviewable changes: 1
  • apps/web/src/components/infra/gcp/tabs.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.

📝 Walkthrough

This change adds Google Cloud infrastructure queries, resource inventory, workload views, and integration usage reporting. It also replaces GCP log-filter modes with per-runtime application-log selections and reuses a shared count chip in the Cloudflare zone board.

Changes: Google Cloud infrastructure

Layer / File(s) Summary
Infrastructure query contracts and data flow
packages/domain/*, packages/query-engine-integrations/*, apps/api/src/routes/*, apps/web/src/api/warehouse/gcp-infra.ts, apps/web/src/lib/services/atoms/warehouse-query-atoms.ts, .github/workflows/ci.yml
Adds GCP service and source metadata, presence and metric query contracts, SQL builders, API handlers, and web query accessors for aggregate and timeseries data. The CI path filter now includes query-engine integration changes.
Organization resource inventory
packages/backend/src/services/integrations/GcpConnectorService.ts, packages/domain/src/http/integrations.ts, apps/api/src/routes/internal/integrations.http.ts, apps/web/src/components/infra/gcp/inventory.ts, apps/web/src/components/infra/gcp/gcp-resources.tsx
Adds organization-scoped resource listing with filtering, deduplication, and facets. The web inventory view displays resource details and links resources to workload pages when they map to one workload.
Workload health and metric charts
apps/web/src/components/infra/gcp/tabs.ts, apps/web/src/components/infra/gcp/charts.ts, apps/web/src/components/infra/gcp/gcp-service-table.tsx, apps/web/src/components/infra/gcp/gcp-workload-charts.tsx, apps/web/src/components/infra/primitives/infra-metric-chart.tsx, apps/web/src/components/infra/chart-utils.ts, apps/web/src/components/infra/gcp/*test.ts
Adds service-specific workload metrics, health and scope classification, chart series, and bucket calculations. Shared chart behavior and formatting also change, with tests covering calculations and gaps.
Infrastructure routes and entry points
apps/web/src/routes/infra/gcp/*, apps/web/src/components/infra/overview/*, apps/web/src/components/service-map/service-map-view.tsx, apps/web/src/components/dashboard/*, apps/web/src/hooks/use-infra-surfaces.ts, apps/web/src/routeTree.gen.ts, apps/landing/src/content/docs/integrations/gcp.md
Adds GCP infrastructure index and workload routes, overview findings, service-map workload details, and navigation. The infrastructure guide documents the new views.
Connection status and usage reporting
apps/web/src/components/integrations/gcp-integration-card.tsx, apps/web/src/components/integrations/gcp-usage*, apps/web/src/hooks/use-interval-refresh.ts, apps/web/src/hooks/use-interval-refresh.browser.test.tsx, apps/landing/src/content/docs/integrations/gcp.md
Adds separate Logs and Metrics connection statuses and 24-hour log, workload, and resource summaries. The interval-refresh hook can refresh when a hidden page becomes visible.

GCP application-log runtime filters

Layer / File(s) Summary
Runtime selection contract and script generation
packages/primitives/src/index.ts, packages/domain/src/http/v2/integrations-gcp.ts, packages/backend/src/services/integrations/gcp/setup-scripts.ts, packages/backend/src/services/integrations/GcpConnectorService.ts, apps/api/src/routes/v2/integrations-gcp.http.ts, docs/api-v2.md
Replaces the log_filter modes with an application_logs runtime list. The setup script builds exclusions for unselected runtimes and keeps an existing sink’s filter when the selection is null.
Runtime controls, routes, and guidance
apps/web/src/components/integrations/gcp-configure.tsx, apps/web/src/components/integrations/gcp-connector-state.ts, apps/web/src/lab/*gcp*, apps/web/src/routes/lab/gcp.tsx, apps/web/src/routeTree.gen.ts, apps/landing/src/content/docs/integrations/gcp*.md
Adds keep-or-replace controls and runtime checkboxes, and updates the setup lab and GCP guidance. Tests cover selection state, request validation, and generated filter behavior.

Shared integration filter chip

Layer / File(s) Summary
Shared count-chip component
apps/web/src/components/integrations/count-chip.tsx, apps/web/src/components/integrations/cloudflare-zone-board.tsx
Adds CountChip and uses it for the Cloudflare zone board’s All and status filters.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant InfrastructurePage
  participant WarehouseAccessor
  participant QueryEngineAPI
  participant GcpInfraSQL
  participant Warehouse
  InfrastructurePage->>WarehouseAccessor: Request GCP fleet or workload metrics
  WarehouseAccessor->>QueryEngineAPI: Send presence, metrics, or timeseries request
  QueryEngineAPI->>GcpInfraSQL: Compile organization-scoped query
  GcpInfraSQL->>Warehouse: Read GCP metric points
  Warehouse-->>InfrastructurePage: Return services and metric points
Loading
Merge Risk: 🟡 Moderate · up to f13e8

Some platform logs can be omitted by the generated filter, and the setup guidance gives conflicting expectations about default forwarding. Resolve or explicitly accept those risks before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 67.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 90 functions across 56 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main change: adding the Infrastructure → Google Cloud page and related infrastructure views.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 7/10 · likely safe to merge
Verified the tenant scoping, identity keys and label values against gcp/mapping.ts and the docs; the metrics response row schema is the one unverified wire shape.
quality 90/100 · 1 warning · tests partial · risk medium · 4/4 new units observable

Adds Infrastructure → Google Cloud: presence and per-service metric queries, an org-scoped inventory read, and the web tables — correct and well pinned by tests, except the metrics response schema, which rejects the quoted 64-bit samples a BYO-ClickHouse org receives. The open WarehouseInvalidInputError in warehouse-query-atoms.ts is the Cloudflare zone query and is untouched here.

  • gcpInfraMetricsSQL unions metrics_sum and metrics_gauge into one point per workload, metric and label
  • gcpInfraPresenceSQL reads the hourly metric_catalog to decide which service tabs show
  • GcpConnectorService.resources pages the inventory by asset type and name, org-scoped through gcp_connectors
  • /infra/gcp renders one table per reported service plus a Resources tab

Findings

🟠 Warning · F1 · samples: Schema.Number rejects the quoted count a BYO-ClickHouse org sends

correctness · packages/domain/src/http/query-engine.ts:490-491

samples is count(), a UInt64 that ClickHouse FORMAT JSON writes as a JSON string; managed Tinybird unquotes it, a BYO-ClickHouse gateway does not (see packages/query-engine/src/ch/schema.ts:3). Schema.Number rejects "60", so GcpInfraMetricsResponse fails to encode in the handler or to decode in the web client, and every service tab renders the error state instead of its table. Use the shared CHNumber codec (Schema.Union([Schema.Finite, Schema.FiniteFromString])), which CLAUDE.md requires of warehouse row schemas.

				total: Schema.Union([Schema.Finite, Schema.FiniteFromString]),
				samples: Schema.Union([Schema.Finite, Schema.FiniteFromString]),
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit 006f8465467ccddade4e481b8bb3d0d4c63c2bd1. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F1 · Warning · correctness · packages/domain/src/http/query-engine.ts:490-491
`samples: Schema.Number` rejects the quoted count a BYO-ClickHouse org sends
`samples` is `count()`, a UInt64 that ClickHouse `FORMAT JSON` writes as a JSON string; managed Tinybird unquotes it, a BYO-ClickHouse gateway does not (see `packages/query-engine/src/ch/schema.ts:3`). `Schema.Number` rejects `"60"`, so `GcpInfraMetricsResponse` fails to encode in the handler or to decode in the web client, and every service tab renders the error state instead of its table. Use the shared `CHNumber` codec (`Schema.Union([Schema.Finite, Schema.FiniteFromString])`), which CLAUDE.md requires of warehouse row schemas.
Replace those lines with:
				total: Schema.Union([Schema.Finite, Schema.FiniteFromString]),
				samples: Schema.Union([Schema.Finite, Schema.FiniteFromString]),

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:244
What was checked
  • Inventory queries join gcp_connectors and filter ofOrg on both the count and the page (GcpConnectorService.ts:262,280)
  • Tab identity keys match gcpResourceAttributes (cloud.region, cloud.availability_zone, ResourceLabel) in gcp/mapping.ts:95-139
  • Column labels and healthy values match the integration docs table (docs/integrations/gcp.md:171-180)
Observability coverage: 4 of 4 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence server endpoint yes Same runQuery handler path as the sibling cloudflareInfraZones operation, which reports to Maple from the last 7 days (12.5% errors, p95 2.1s)
POST /internal/query-engine/gcp-infra-metrics server endpoint yes Same runQuery handler path as the sibling cloudflareInfraZones operation, which reports to Maple from the last 7 days
GET /internal/integrations/gcp/resources server endpoint yes Sibling integration reads in internal/integrations.http.ts are served by the same route group and are visible as operations
GcpConnectorService.resources inventory read database read yes Postgres read through the shared dbExecute/withPgConnectionScope path used by the other integration reads

006f846 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot maple-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 inline note from Maple's review. The score and summary are in the review comment above.

Comment thread packages/domain/src/http/query-engine.ts
@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Held at 8 because a warning is open.
quality 90/100 · 1 warning · tests not needed · risk low

Adds packages/query-engine-integrations/** to the clickhouse test-lane path filter, so the SQL catalog sweep runs on integration-builder edits. Correct and safe. F1 (samples: Schema.Number) is unchanged at this head and still open; this CI-only change does not touch the WarehouseInvalidInputError issue.

  • CI clickhouse lane now fires on packages/query-engine-integrations/** changes

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:244
What was checked
  • catalog.clickhouse.e2e.test.ts covers both catalogs, including @maple/query-engine-integrations builders, so the new trigger is warranted (.github/workflows/ci.yml:126)
  • F1 re-checked at head: query-engine.ts:491 still samples: Schema.Number with no CHNumber coercion in the route or runner

600752f · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 9/10 · safe to merge
The only delta is a test, and it pins the decode I traced through executor.ts:1023 into the response constructor; F1 no longer reproduces.
quality 100/100 · no findings · tests covered · risk low

Adds one test to gcpInfraMetricsSQL: the query's derived row schema decodes a quoted count() ("60" → 60). Safe to merge — the delta is a test, so it does not touch the open WarehouseInvalidInputError issue.

  • gcp-infra.test.ts pins that samples decodes from ClickHouse's quoted 64-bit JSON

Fixed since the last review

  • ✅ F1 · samples: Schema.Number rejects the quoted count a BYO-ClickHouse org sends

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:244
What was checked
  • Traced the wire path: executor.ts:1023 decodeRows runs the query's row codec before query-engine.http.ts:819 builds GcpInfraMetricsResponse, so samples: Schema.Number never sees the quoted s…
  • The new test can fail: it asserts "60" decodes to 60 on the real derived schema, not a restatement of the SQL
  • The metric-name regex at line 42 cannot pick up 'org_1' or the time literals — only gcp.-prefixed names match

1f8f707 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

# Conflicts:
#	apps/landing/src/content/docs/integrations/gcp.md
@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 9/10 · safe to merge
quality 100/100 · no findings · tests covered · risk medium · 3/3 new units observable

Adds the /infra/gcp page: two new warehouse builders (metrics + presence), two query-engine endpoints, a Postgres inventory read, and the nav/overview wiring, all pinned by tests and the SQL baseline. Nothing in the diff breaks a contract I could confirm; the open WarehouseInvalidInputError from warehouse-query-atoms.ts is not addressed here.

  • /infra/gcp route: one table per reporting service plus the gcp_resources inventory, gated on a connected connector with metrics on
  • gcpInfraMetricsSQL(service) and gcpInfraPresenceSQL() in packages/query-engine-integrations/src/gcp/gcp-infra.ts, served by two new session-only query-engine endpoints
  • GcpConnectorService.resources with GET /internal/integrations/gcp/resources, org-scoped through gcp_connectors.org_id
  • gcp added to the Infrastructure nav, the overview source rows and the SQL catalog sweep in CI

Before merge

  • Manual · Merge the lower Google Cloud PRs first (feat/gcp-dashboard-template, feat/gcp-integration-card): this branch is the top of that stack.

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:244
What was checked
  • Identity keys in gcp-infra.ts match the attribute spelling mapping.ts:75 writes and mapping.test.ts:162-164 pins; quantile label "0.95" matches the dashboard template (`dashboard-templates/inf…
  • Every service tab's metric names are asserted against gcpInfraMetrics(service) in gcp-infra.test.ts, and the generated SQL is pinned in __sql_baseline__/integrations.sql.
  • The samples/total row decode is pinned by the quoted-integer test added in 1f8f707; GcpInfraMetricsResponse is fed already-decoded rows.
Observability coverage: 3 of 3 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence and /gcp-infra-metrics inbound HTTP yes same HTTP layer as cloudflareInfraZones, which reports under apps/api/src/routes/internal/query-engine.http.ts in Maple
GET /internal/integrations/gcp/resources inbound HTTP yes sibling routes /internal/integrations/railway/status and /cloudflare/status appear in maple-api route usage
gcpInfraMetricsSQL / gcpInfraPresenceSQL warehouse reads outbound DB query yes run through WarehouseQueryService.compiledQuery, which reports as executeCompiledQuery in Maple

3a35b64 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Identity attributes and quantile labels were checked against the poller's mapping.ts; the fold, SQL baseline and inventory query each have a test.
quality 100/100 · no findings · tests covered · risk medium · 3/3 new units observable

Adds the Infrastructure → Google Cloud page: one sortable table per curated GCP service over the gcp.* metrics, the Cloud Asset Inventory tab, two query-engine builders behind internal endpoints and the inventory read. Contained and safe to merge; the open WarehouseInvalidInputError in warehouse-query-atoms.ts is untouched by this change and the new reads cannot reach it (a validated time window and a closed service literal).

  • /infra/gcp renders one searchable, sortable table per curated GCP service, then Resources.
  • gcpInfraMetricsSQL/gcpInfraPresenceSQL aggregate gcp.* metrics and the hourly catalog.
  • GcpConnectorService.resources reads the org's gcp_resources inventory behind GET /internal/integrations/gcp/resources.
  • Google Cloud joins the Infrastructure nav and overview, gated on a connector with metrics_enabled.

Before merge

  • Manual · Merge onto feat/gcp-dashboard-template first: this branch is the top of the stack.

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:253
What was checked
  • GCP identity attributes match the poller's mapping: host.name from instance_name (mapping.ts:68), cloud.account.id/cloud.region/gcp.resource.labels.* (mapping.ts:41, :44, :75).
  • Quantile label values are String(q), i.e. 0.95/0.99 (mapping.ts:23, :202), which is what the columns in tabs.ts key on.
  • resources scopes through gcp_connectors.org_id and metrics_enabled and dedupes on the (connector_id, …) prefix (GcpConnectorService.ts:261, :276).
Observability coverage: 3 of 3 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence Server (HTTP route) yes sibling /internal/query-engine/infra-presence reports as a maple-api operation, 341 calls/7d
POST /internal/query-engine/gcp-infra-metrics Server (HTTP route) yes same maple-api queryEngine group as /internal/query-engine/service-cloudflare-stats, which is traced
GET /internal/integrations/gcp/resources Server (HTTP route) yes same group as /internal/integrations/cloudflare/status and /internal/integrations/railway/status, both traced (17 calls/7d)

e4feada · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Verified the metric/label assumptions against gcp-metrics.ts and mapping.test.ts; the new SQL, scoping and column folds hold, and the endpoint/UI paths are the only unexercised-by-me parts.
quality 100/100 · no findings · tests covered · risk medium · 3/3 new units observable

Adds the Infrastructure → Google Cloud page: two query-engine endpoints over the curated gcp.* metrics, a resources-inventory endpoint, and the tabbed table UI. The reviewed hunks are safe to merge. The open WarehouseInvalidInputError in warehouse-query-atoms.ts is untouched by this diff — the two atoms it adds do no input handling of their own.

  • gcpInfraMetricsSQL/gcpInfraPresenceSQL read the gcp.* metrics per tab and the metric_catalog rollup for tab presence
  • GcpConnectorService.resources lists the inventory, scoped by the connector's org_id
  • gcpWorkloads/sortGcpWorkloads fold the points into one row per workload
  • New /infra/gcp route, nav item and Integration-overview source row

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:253
What was checked
  • Quantile labels 0.95/0.99 match what the poller writes (gcp/mapping.ts:208, mapping.test.ts:118)
  • label concatenation is safe: no curated metric carries a label and a quantile at once (gcp-metrics.ts)
  • Both new queries filter OrgId, and resources joins gcp_connectors.org_id (GcpConnectorService.ts:261), pinned by the other-org test
Observability coverage: 3 of 3 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence and /gcp-infra-metrics inbound HTTP yes Handlers reuse the same runQuery path as cloudflareInfraZones (apps/api/src/routes/internal/query-engine.http.ts), which already reports as an operation in Maple
GET /internal/integrations/gcp/resources inbound HTTP yes apps/api HttpApi handler plus an Effect.fn("GcpConnectorService.resources") span with orgId annotation (GcpConnectorService.ts:253)
gcpResources counts + distinct-on read DB query yes Both reads go through dbExecute (GcpConnectorService.ts:262, :274)

97b0640 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 9/10 · safe to merge
Label semantics, identity attributes and org scoping are pinned by the new tests and checked against the poller's own mapping; no hunk went unread.
quality 100/100 · no findings · tests covered · risk medium · 4/4 new units observable

Adds Infrastructure → Google Cloud: a tab per curated gcp.* service plus the Cloud Asset inventory, two agents warehouse endpoints and an org-scoped inventory read. The queries, folding and facets are well tested and safe to merge. The open WarehouseInvalidInputError ("Breakdown query too broad without filters") comes from the breakdown query, not the two atoms this diff adds to that file, so the change does not address it.

  • /infra/gcp renders one sortable table per reporting service tab plus the resource inventory
  • gcpInfraMetricsSQL/gcpInfraPresenceSQL read the curated metrics and the metric_catalog rollup, both OrgId-scoped
  • GcpConnectorService.resources returns the org's deduped, filtered inventory with type and project facets
  • Google Cloud joins the Infrastructure nav and overview behind the metrics-enabled connector gate

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 12.5% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 12.5% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:253
What was checked
  • 5xx/500, ok and ack match the real response_code_class, status and response_class label values in packages/domain/src/gcp-metrics.ts
  • Every identity attribute the tabs read (host.name, k8s.*, gcp.resource.labels.*) is one gcpResourceAttributes writes (packages/backend/src/services/integrations/gcp/mapping.ts:32-77)
  • Org scoping: both SQL builders filter OrgId (asserted single-tenant in gcp-infra.test.ts) and the inventory test proves another org's rows are excluded
Observability coverage: 4 of 4 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence and /gcp-infra-metrics inbound HTTP handler yes Handled in the existing HttpApiBuilder.group(MapleInternalApi, "queryEngine") beside cloudflareInfraZones, which appears in Maple with counts and latency
GET /internal/integrations/gcp/resources inbound HTTP handler yes Same IntegrationsApiGroup handlers as the sibling railwayStatus/githubStatus reads the web client already calls with client spans
gcpInfraMetricsSQL / gcpInfraPresenceSQL warehouse reads outbound ClickHouse query yes Run through WarehouseQueryService.compiledQuery() via Queries.gcpInfraMetrics/gcpInfraPresence in apps/api/src/routes/queries.ts:293-315
Web getGcpInfraPresence / getGcpInfraMetrics atoms outbound HTTP call yes Both wrap the internal client in runWarehouseQuery("gcpInfraPresence"|"gcpInfraMetrics") (apps/web/src/api/warehouse/gcp-infra.ts:26,44), the span-naming helper cloudflareInfraZones already uses

7078247 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
New nav surface, page and two query endpoints, all pinned by tests; I could not verify Google's own label values behind the 5xx and error-rate columns.
quality 100/100 · no findings · tests covered · risk medium · 2/2 new units observable

Adds Infrastructure → Google Cloud: a gated nav entry, /infra/gcp with one table per curated gcp.* service plus the Cloud Asset inventory, two warehouse query builders and a session-scoped inventory read. Safe to merge. The open WarehouseInvalidInputError issue (top frame warehouse-query-atoms.ts) is not addressed: this PR only adds two atom families to that file and changes no error path.

  • gcpInfraMetricsSQL/gcpInfraPresenceSQL read gcp.* metrics and the hourly catalog
  • GcpConnectorService.resources lists the org's inventory by connector
  • /infra/gcp renders one tab per reporting service plus Resources
  • gcp joins the Infrastructure nav and overview as a metrics-gated source

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 11.8% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 11.8% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:253
What was checked
  • Inventory read stays org-scoped and metrics-only (GcpConnectorService.ts:261), pinned by a PGlite test
  • Both union branches filter OrgId; gcp-infra.test.ts asserts single-tenant scope
  • Filter inputs are bounded strings and a closed service literal at the HTTP boundary
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
gcp-infra-metrics / gcp-infra-presence warehouse reads Client yes runWarehouseQuery wraps each adapter in Effect.withSpan(operation) (api/warehouse/effect-utils.ts:236)
gcpResources inventory read Client yes retainedInternalQuery on the integrations client; service annotates its span with orgId (GcpConnectorService.ts:257)

8ac9c70 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The three files changed since the last pass are additive UI glue around already-reviewed atoms; I read each hunk and every symbol it calls and found no defect.
quality 100/100 · no findings · tests partial · risk low · 3/3 new units observable

Adds the Infrastructure -> Google Cloud page, its service-tab queries and the GCP resource inventory read path. The three hunks changed since the last pass are presentation and wiring only; nothing there warrants blocking the merge. The open @maple/web WarehouseInvalidInputError in warehouse-query-atoms.ts (cloudflareInfraZones) is untouched by this change: it adds two GCP atoms beside the existing ones and does not alter that path.

  • GcpResources reads the inventory through retainedInternalQuery, keyed on the integration
  • MetricsStatus on the integration card links to /infra/gcp when metrics are on
  • GcpPage gates on metrics-enabled connectors and follows a settling connection every 10s

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 12 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
apps/api/src/routes/internal/query-engine.http.ts 2 cloudflareInfraZones 2/day, 11.8% err
packages/domain/src/http/query-engine.ts 2 cloudflareInfraZones 2/day, 11.8% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraPresence · apps/web/src/api/warehouse/gcp-infra.ts:20
  • ➕ span name QueryEngine.getGcpInfraMetrics · apps/web/src/api/warehouse/gcp-infra.ts:38
  • ➕ span name GcpConnectorService.resources · packages/backend/src/services/integrations/GcpConnectorService.ts:253
What was checked
  • retainedInternalQuery takes query/reactivityKeys and encodes them for retention (internal-atom-client.ts:47)
  • The tab strip always contains GCP_RESOURCES_TAB, so tab = requested ?? tabs[0] can never be undefined (tabs.ts:241)
  • pickTimeRangeSearch carries only the window, so tab links are well-formed (time-range-picker/search.ts:53)
Observability coverage: 3 of 3 changes observable
Change Kind Observable Evidence
POST /internal/query-engine/gcp-infra-presence inbound endpoint yes Mirrors the cloudflareInfraZones handler in the same group (apps/api/src/routes/internal/query-engine.http.ts:803), which is traced; ~0-traffic dashboard path
POST /internal/query-engine/gcp-infra-metrics inbound endpoint yes Same HttpApiBuilder.group handler shape as its neighbours (apps/api/src/routes/internal/query-engine.http.ts:815)
GET /internal/integrations/gcp/resources inbound endpoint yes Reads GcpConnectorService through the same group as railwayStatus/githubStatus (apps/api/src/routes/internal/integrations.http.ts:510)

83d4756 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The changed files are contained UI and one pure helper pinned by tests; the 1,957 ms gcpInfraMetrics p95 and the pre-existing F9 are the parts that need a careful look.
quality 98/100 · 1 note · tests covered · risk medium

Reworks the Google Cloud log filter into per-runtime application-output ticks wired to the application_logs script parameter, and restyles the connection rows. Safe to merge; the earlier summarizeGcp cap finding still stands at this head, and the WarehouseInvalidInputError in warehouse-query-atoms.ts is untouched.

  • gcpLogFilterChoice returns applicationLogs: omitted keeps an existing sink's filter
  • GcpLogFilterField replaces the named filters with runtime ticks behind an OpenTelemetry notice
  • Connection rows render Status/Band with shortened state labels
  • New /lab/gcp page previews the log filter field

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 183 GET /v2/integrations/gcp 183/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 52 QueryEngine.getGcpInfraMetrics 13/day, 0.0% err
gcpInfraMetrics 13/day, 0.0% err
QueryEngine.getGcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
packages/domain/src/http/query-engine.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/queries.ts 23 gcpInfraMetrics 13/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
gcpInfraTimeseries 4/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 9 GcpConnectorService.resources 6/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
What was checked
  • Client payload matches the API contract: omitted application_logs keeps a sink, [] sets a platform-only filter (setup-scripts.ts)
  • A second connection cannot inherit a filter choice: the dialog remounts and target clears on close (gcp-integration-card.tsx:678)
  • gcpLogFilterChoice and gcpApplicationLogsLine semantics are pinned by the head's tests (gcp-connector-state.test.ts:672-722)

8a2f2fd · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

# Conflicts:
#	apps/web/perf/check-bundle-budget.ts
@JeremyFunk JeremyFunk removed the preview Deploy a full PR preview stack (Cloudflare + AWS ingest); removing it tears it down label Oct 15, 2026
@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The only delta since the last review is the bundle-budget comment and bump; no production code changed in it.
quality 98/100 · 1 note · tests not needed · risk low

Adds the Infrastructure → Google Cloud page (fleet band, per-service tables, workload pages, resource inventory, overview and service-map panels) on the gcp.* metrics, plus its queries, endpoints and contract. Safe to merge: the delta since the last review is only the startup budget bump. The open WarehouseInvalidInputError on the gcp metrics read is addressed in the branch (derived row schema plus the quoted-count pin), and F9 in summarizeGcp is untouched by that delta.

  • check-bundle-budget.ts raises the max startup budget to 700.5 KB for the /infra/gcp additions
  • The GCP fleet, workload, inventory and overview surfaces and their queries ship behind the existing infra routes

Before merge

  • Manual · The latest PR preview deploy failed (Alchemy deploy outcome failure); re-run it and check the Google Cloud connector on a live org

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 183 GET /v2/integrations/gcp 183/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 52 QueryEngine.getGcpInfraMetrics 13/day, 0.0% err
gcpInfraMetrics 13/day, 0.0% err
QueryEngine.getGcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
packages/domain/src/http/query-engine.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/queries.ts 23 gcpInfraMetrics 13/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
gcpInfraTimeseries 4/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 9 GcpConnectorService.resources 6/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
What was checked
  • 854446ef is an ancestor of the head, so only check-bundle-budget.ts is in the since-last-review delta; the lab and attribute-keys files belong to the base branch
  • The quoted point count decodes: gcp-infra.test.ts:70 pins samples: "60" to 60 through the derived row schema
  • summarizeGcp still appends unread-service rows after the MAX_FINDINGS_PER_SOURCE slice (apps/web/src/components/infra/overview/summaries.ts:337), so F9 stands

1b75ecf · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@JeremyFunk JeremyFunk added the preview Deploy a full PR preview stack (Cloudflare + AWS ingest); removing it tears it down label Oct 15, 2026
@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The one file changed since the last review is a documented budget bump; the open Google Cloud summary finding is still in the code.
quality 98/100 · 1 note · tests covered · risk low

Since the last review only apps/web/perf/check-bundle-budget.ts moved: it drops the leftover merge markers and raises the startup budget to 701.5 KB gzip with the #1336 rationale, which is fine. summarizeGcp still appends one unread-service row per failed service past MAX_FINDINGS_PER_SOURCE (F9, left open). The open WarehouseInvalidInputError issue is not addressed here: the diff only adds the GCP atoms beside the ones that already fail.

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 183 GET /v2/integrations/gcp 183/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 52 QueryEngine.getGcpInfraMetrics 13/day, 0.0% err
gcpInfraMetrics 13/day, 0.0% err
QueryEngine.getGcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
packages/domain/src/http/query-engine.ts 32 gcpInfraMetrics 13/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
apps/api/src/routes/queries.ts 23 gcpInfraMetrics 13/day, 0.0% err
gcpInfraPresence 6/day, 0.0% err
gcpInfraTimeseries 4/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 9 GcpConnectorService.resources 6/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
What was checked
  • Budget checker read at head: 701.5 KB threshold and the #1336 comment chain agree, no leftover conflict markers in apps/web
  • summarizeGcp unread rows are still appended after flagged.slice(0, MAX_FINDINGS_PER_SOURCE) (summaries.ts:337)
  • F9 judged at this head: code unchanged, tests pin unread rows alongside flagged ones, finding left open

787de12 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…p queries

The list becomes one view per resource kind (Services, Pub/Sub, Cloud SQL, GKE, VMs, load
balancing, resources) behind a pivot, each with a fleet band whose cells scope the table,
problems-first rows, sparklines (new gcpInfraSparklines query) and a projects strip when
2+ projects report. ?tab links keep working through ?view.

Workload pages get the Worker page shell: header chips, signal strips on one time axis, a
rail, and "All charts" below. Cloud Run and functions show a callout when Google counted
far more server errors than traces did. Cloud SQL instances join their synced settings
(connections against max_connections, replicas folded into the primary, Query Insights
state), list the polled top statements next to what traces saw, and call out a statement
the app waits on far longer than the database runs it.

Labs: /lab/gcp-infra and /lab/gcp-workload render both pages from fixtures.
@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟡 Confidence 6/10 · needs attention
One warn on the Cloud SQL trace read; the six GCP model test files, gcp-workload-lab.tsx and the lab routes went unread.
quality 88/100 · 1 warning · 1 note · tests partial · risk medium · 2/2 new units observable · 7 files not read

Infrastructure → Google Cloud: fleet band, per-service tables, workload pages, inventory and service-map panel, plus new internal query-engine endpoints. One defect: a Cloud SQL trace read loses every database when one fails. The open WarehouseInvalidInputError is untouched; the GCP model test files and the workload lab harness were not read.

  • Adds /infra/gcp index and per-workload pages built from gcp.* metrics
  • New internal query-engine endpoints and six gcp.* ClickHouse queries
  • useIntervalRefresh gains catchUp, refreshing when a hidden tab returns
  • Cloud SQL page reads Query Insights statements with their traced callers

Findings

🟠 Warning · F10 · getGcpCloudSqlTraceSide loses every database's traces when one summary query fails

correctness · apps/web/src/api/warehouse/gcp-infra.ts:194-207

Effect.forEach(databases, getServiceDbQuerySummary) has no per-item fallback, unlike getGcpInfraFleet and getGcpInfraSparklines in this same file, so one database's summary query failing fails the whole read. routes/infra/gcp/$service/$name.tsx:180 maps that to traceSide: undefined, and gcp-cloudsql-top-queries.tsx:50 then renders every statement as not traced in the warn tone with the queried by N services chip gone: a failed read is indistinguishable from traces that recorded nothing.

Isolate each database the way the sibling reads do, e.g. `Effect.orElseSucceed(() => ({ topQueries: [], summary: undefined }))` (with the shape `getServiceDbQuerySummary` actually returns) around each call, so the other databases' traces still show.
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit 08a505ca7fe7c680721f09e2a979ff12b95a9bd9. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F10 · Warning · correctness · apps/web/src/api/warehouse/gcp-infra.ts:194-207
`getGcpCloudSqlTraceSide` loses every database's traces when one summary query fails
`Effect.forEach(databases, getServiceDbQuerySummary)` has no per-item fallback, unlike `getGcpInfraFleet` and `getGcpInfraSparklines` in this same file, so one database's summary query failing fails the whole read. `routes/infra/gcp/$service/$name.tsx:180` maps that to `traceSide: undefined`, and `gcp-cloudsql-top-queries.tsx:50` then renders every statement as `not traced` in the warn tone with the `queried by N services` chip gone: a failed read is indistinguishable from traces that recorded nothing.
Suggested fix: Isolate each database the way the sibling reads do, e.g. `Effect.orElseSucceed(() => ({ topQueries: [], summary: undefined }))` (with the shape `getServiceDbQuerySummary` actually returns) around each call, so the other databases' traces still show.

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 189 GET /v2/integrations/gcp 189/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 59 QueryEngine.getGcpInfraMetrics 14/day, 0.0% err
gcpInfraMetrics 14/day, 0.0% err
QueryEngine.getGcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 35 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
packages/domain/src/http/query-engine.ts 35 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/queries.ts 26 gcpInfraMetrics 14/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
gcpInfraTimeseries 5/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 10 GcpConnectorService.resources 7/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraSparklines · apps/web/src/api/warehouse/gcp-infra.ts:127
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • BYO-ClickHouse quoting of samples: the SQL-derived row schema unquotes it (gcp-infra.test.ts pins "60" → 60), so the domain Schema.Number never sees a string
  • Empty project/region params are dropped as filters (list-model.ts:604-607); a project the page does not know is no scope
  • Fleet and sparkline reads isolate a per-service failure with Effect.orElseSucceed (gcp-infra.ts:93-101, 134-148)
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
gcp-infra-metrics/timeseries/sparklines/presence/cloudsql endpoints (apps/api/src/routes/internal/query-engine.http.ts) server yes new handlers follow the file's existing runQuery pattern; maple-web QueryEngine.gcpInfraMetrics spans already appear in traffic
gcp.* ClickHouse reads (packages/query-engine-integrations/src/gcp/gcp-infra.ts) client yes run through the same Queries.*/runQuery path as every sibling integration query, none of which adds a span of its own
Files not reviewed (7)

The review ended before it read these diffs, so nothing above vouches for them.

  • apps/web/src/components/infra/gcp/cloud-sql-signals.test.ts
  • apps/web/src/components/infra/gcp/inventory.test.ts
  • apps/web/src/components/infra/gcp/list-model.test.ts
  • apps/web/src/components/infra/gcp/tabs.test.ts
  • apps/web/src/components/infra/gcp/workload-signals.test.ts
  • apps/web/src/routes/lab/gcp-infra.tsx
  • apps/web/src/routes/lab/gcp-workload.tsx

08a505c · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The only changed file since the last review is the bundle-budget constant, read in full; both open findings' code is unchanged at this head.
quality 88/100 · 1 warning · 1 note · tests not needed · risk low

Since the last review the only change is the startup budget in check-bundle-budget.ts, 699.5 → 705.5 KB, with the rationale and a note that the pages stay in route chunks. That delta is safe; the WarehouseInvalidInputError issue is untouched by it, and both open findings stand at this head.

  • check-bundle-budget.ts startup budget raised to 705.5 KB for the Google Cloud page redesign

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 189 GET /v2/integrations/gcp 189/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 59 QueryEngine.getGcpInfraMetrics 14/day, 0.0% err
gcpInfraMetrics 14/day, 0.0% err
QueryEngine.getGcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 36 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
packages/domain/src/http/query-engine.ts 36 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/queries.ts 26 gcpInfraMetrics 14/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
gcpInfraTimeseries 5/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 10 GcpConnectorService.resources 7/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraSparklines · apps/web/src/api/warehouse/gcp-infra.ts:127
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • Delta is one constant plus comment; the check logic at check-bundle-budget.ts:141-151 is unchanged
  • getGcpCloudSqlTraceSide still has no per-database error tolerance (gcp-infra.ts:194-207)
  • summarizeGcp still appends unread rows past the cap (summaries.ts:326-346)

29c0215 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

The /infra/gcp list had no right rail, unlike the workload page and the
Cloudflare pages. It now lists what each connection covers, linked to the
project's dashboard or the folder or organization in the resource manager, and
the picked project's Dashboard, Metrics Explorer, Logs Explorer and Asset
Inventory in the Google Cloud console.
@maple-review-bot

maple-review-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 7/10 · likely safe to merge
The one commit since the last review is a small additive UI rail; the empty-project= case in it is the only defect I found.
quality 86/100 · 1 warning · 2 notes · tests partial · risk low

Adds a right rail to /infra/gcp listing each connection and the picked project's Google Cloud console pages, reusing RailLink from the workload rail. Safe to merge; the two earlier findings (F9, F10) are untouched at this head, and the open WarehouseInvalidInputError is not addressed by this change.

  • GcpListRail lists every connection and the picked project's Google Cloud console pages
  • gcpConsoleScopePage / gcpConsoleProjectPages build the resource-manager and project console links
  • RailLink is exported from the workload rail and reused by the list rail
  • /infra/gcp passes the connector status into DashboardPage's rightPanel

Findings

🔵 Note · F11 · Empty ?project= in the URL renders the rail's console links with no project

correctness · apps/web/src/components/infra/gcp/gcp-list-rail.tsx:28

project is Schema.optional(Schema.String) (apps/web/src/routes/infra/gcp/index.tsx:67), so an address like /infra/gcp?project= decodes to "", which is not nullish: shown = project ?? only keeps it, and the rail prints project with a blank id and builds every Google Cloud console link as ?project=. The page's own filter normalizes the same value with search.project || undefined (index.tsx:286).

	const shown = (project === "" ? undefined : project) ?? only
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit aac774baa5456563660d5ef17c92fb356a6263f6. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F11 · Note · correctness · apps/web/src/components/infra/gcp/gcp-list-rail.tsx:28
Empty `?project=` in the URL renders the rail's console links with no project
`project` is `Schema.optional(Schema.String)` (`apps/web/src/routes/infra/gcp/index.tsx:67`), so an address like `/infra/gcp?project=` decodes to `""`, which is not nullish: `shown = project ?? only` keeps it, and the rail prints `project ` with a blank id and builds every Google Cloud console link as `?project=`. The page's own filter normalizes the same value with `search.project || undefined` (`index.tsx:286`).
Replace those lines with:
	const shown = (project === "" ? undefined : project) ?? only

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 189 GET /v2/integrations/gcp 189/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 59 QueryEngine.getGcpInfraMetrics 14/day, 0.0% err
gcpInfraMetrics 14/day, 0.0% err
QueryEngine.getGcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 35 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
packages/domain/src/http/query-engine.ts 35 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 9/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/queries.ts 26 gcpInfraMetrics 14/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
gcpInfraTimeseries 5/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 10 GcpConnectorService.resources 7/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraSparklines · apps/web/src/api/warehouse/gcp-infra.ts:127
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • Console links encode their ids (inventory.ts:126), so a project or folder id cannot break the URL
  • gcpResourceQuery/gcpMatchResource key layouts match GCP_INFRA_SERVICES.identity (packages/domain/src/gcp-infra.ts:31)

aac774b · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

# Conflicts:
#	apps/web/perf/check-bundle-budget.ts
@maple-review-bot

maple-review-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Maple review

🔴 Confidence 4/10 · risky as written
Only a fraction of the 80 changed files was read here; the three earlier findings are all still present at this head.
quality 86/100 · 1 warning · 2 notes · tests partial · risk medium · 0/2 new units observable · 47 files not read

Adds Infrastructure → Google Cloud: fleet band, per-service tables, workload pages, resource inventory and service-map panels over new gcp.* warehouse queries. The three open findings from earlier reviews are all still present at this head; WarehouseInvalidInputError (warehouse-query-atoms.ts) is not addressed. I read ~30 of 80 files: the new API routes, most GCP components, the integration pages, the connector service and the lab files went unread.

  • getGcpInfraFleet probes presence, then queries every reporting service in parallel and isolates a failed service
  • New /infra/gcp index and workload routes drive the list, sparklines and inventory from URL search
  • summarizeGcp adds Google Cloud findings and an overview row to the Infrastructure summaries

Before merge

  • Manual · Confirm the raised startup bundle budget (apps/web/perf/check-bundle-budget.ts) is intended for this feature

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 189 GET /v2/integrations/gcp 189/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 59 QueryEngine.getGcpInfraMetrics 14/day, 0.0% err
gcpInfraMetrics 14/day, 0.0% err
QueryEngine.getGcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 36 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
packages/domain/src/http/query-engine.ts 36 gcpInfraMetrics 14/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
apps/api/src/routes/queries.ts 26 gcpInfraMetrics 14/day, 0.0% err
gcpInfraPresence 7/day, 0.0% err
gcpInfraTimeseries 5/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 10 GcpConnectorService.resources 7/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraSparklines · apps/web/src/api/warehouse/gcp-infra.ts:127
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • F10 still present: getGcpCloudSqlTraceSide runs getServiceDbQuerySummary with no per-database error isolation (apps/web/src/api/warehouse/gcp-infra.ts:194-207)
  • F11 still present: project={search.project} decodes an empty ?project= to "" and shown = project ?? only renders the console links with a blank project (gcp-list-rail.tsx:28, `routes/infra/g…
  • F9 still present: summarizeGcp slices flagged rows at MAX_FINDINGS_PER_SOURCE and then appends every unread-service row (summaries.ts:326-346)
Observability coverage: 0 of 2 changes observable
Change Kind Observable Evidence
GCP infra warehouse endpoints (apps/api/src/routes/queries.ts, internal/query-engine.http.ts, internal/integrations.http.ts) Server no file unread (child group ran out of time)
/infra/gcp and /infra/gcp/$service/$name routes Server no route wiring read; no span helper seen in the route files
Files not reviewed (47)

The review ended before it read these diffs, so nothing above vouches for them.

  • .github/workflows/ci.yml
  • apps/api/src/routes/v2/integrations-gcp.http.test.ts
  • apps/web/perf/check-bundle-budget.ts
  • apps/web/src/components/dashboard/app-sidebar.tsx
  • apps/web/src/components/dashboard/nav-items.test.ts
  • apps/web/src/components/dashboard/nav-items.ts
  • apps/web/src/components/infra/chart-utils.test.ts
  • apps/web/src/components/infra/chart-utils.ts
  • apps/web/src/components/infra/gcp/charts.test.ts
  • apps/web/src/components/infra/gcp/cloud-sql-signals.test.ts
  • apps/web/src/components/infra/gcp/inventory.test.ts
  • apps/web/src/components/infra/gcp/list-model.test.ts
  • apps/web/src/components/infra/gcp/tabs.test.ts
  • apps/web/src/components/infra/gcp/workload-signals.test.ts
  • apps/web/src/components/infra/overview/infra-overview.tsx
  • apps/web/src/components/infra/overview/summaries.test.ts
  • apps/web/src/components/infra/primitives/infra-metric-chart.tsx
  • apps/web/src/components/integrations/cloudflare-zone-board.tsx
  • apps/web/src/components/integrations/count-chip.tsx
  • apps/web/src/components/integrations/gcp-configure.tsx
  • apps/web/src/components/integrations/gcp-connector-state.test.ts
  • apps/web/src/components/integrations/gcp-connector-state.ts
  • apps/web/src/components/integrations/gcp-integration-card.tsx
  • apps/web/src/components/integrations/gcp-usage-cards.tsx
  • apps/web/src/components/integrations/gcp-usage.test.ts
  • apps/web/src/components/integrations/gcp-usage.ts
  • apps/web/src/components/service-map/service-map-view.tsx
  • apps/web/src/hooks/use-infra-surfaces.ts
  • apps/web/src/hooks/use-interval-refresh.browser.test.tsx
  • apps/web/src/hooks/use-interval-refresh.ts
  • and 17 more

3cec807 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…n workload pages

The list page's rail repeated the integration card. On a workload page the
rail's Logs and console links repeated the hero's buttons; what is left
(service map, traced service) reads as icon rows instead of orange mono text.
@maple-review-bot

maple-review-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 7/10 · likely safe to merge
The six files changed since the last review only delete the list rail and rewire the workload rail's link rows; F10 and F9 are still unfixed at this head.
quality 88/100 · 1 warning · 1 note · tests partial · risk low

The last commit deletes the Google Cloud list rail and turns the workload rail's remaining links into plain icon rows; the hero keeps the Logs, Traces and console buttons, so nothing is stranded. The delta is safe to merge; F10 and F9 remain unfixed at this head.

  • GcpWorkloadRail drops its Logs and console links; the hero's buttons keep them
  • GcpListRail deleted; the list page, workloads lab and infra lab render no right rail

Still open from earlier reviews

Fixed since the last review

  • ✅ F11 · Empty ?project= in the URL renders the rail's console links with no project

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 190 GET /v2/integrations/gcp 190/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 67 QueryEngine.getGcpInfraMetrics 16/day, 0.0% err
gcpInfraMetrics 16/day, 0.0% err
QueryEngine.getGcpInfraPresence 8/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 40 gcpInfraMetrics 16/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 8/day, 0.0% err
packages/domain/src/http/query-engine.ts 40 gcpInfraMetrics 16/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 8/day, 0.0% err
apps/api/src/routes/queries.ts 30 gcpInfraMetrics 16/day, 0.0% err
gcpInfraPresence 8/day, 0.0% err
gcpInfraTimeseries 6/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 12 GcpConnectorService.resources 9/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (3)
  • ➕ span name QueryEngine.getGcpInfraSparklines · apps/web/src/api/warehouse/gcp-infra.ts:127
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • No remaining importers of the deleted GcpListRail or the removed RailLink export (grep at head)
  • Logs, Traces and console links still render from GcpWorkloadActions (gcp-workload-page.tsx:126-178)
  • logs/consolePage still consumed at $name.tsx:326-330 and gcp-workload-lab.tsx:416-420

6d7e999 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

# Conflicts:
#	apps/web/src/components/integrations/gcp-integration-card.tsx
#	apps/web/src/lab/registry.ts
@maple-review-bot

maple-review-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 7/10 · likely safe to merge
The hunks changed since the last round are small and read in full, but two earlier correctness findings still stand in files this round did not touch.
quality 88/100 · 1 warning · 1 note · tests covered · risk medium · 2/2 new units observable

Adds the Infrastructure → Google Cloud page, the GCP integration card's usage band and links into it, and the /lab entries for the new GCP surfaces. The new hunks are safe; F9 and F10 from earlier rounds are still present at this head and block a clean merge.

  • GcpConnection gains a View infrastructure menu item and a Metrics signal link on /infra/gcp
  • GcpIntegrationCard renders GcpUsageBand and polls with catchUp
  • GcpMessage lays multiple sentences out as a list
  • LAB_ENTRIES gains /lab/gcp, /lab/gcp-infra and /lab/gcp-workload

Still open from earlier reviews

Production impact

Open errors in the changed files
Issue Service Occurrences File
@maple/web/errors/WarehouseInvalidInputError maple-web 9 apps/web/src/lib/services/atoms/warehouse-query-atoms.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/domain/src/http/integrations.ts 210 GET /v2/integrations/gcp 210/day, 0.0% err
apps/web/src/api/warehouse/gcp-infra.ts 92 QueryEngine.getGcpInfraMetrics 21/day, 0.0% err
gcpInfraMetrics 21/day, 0.0% err
QueryEngine.getGcpInfraPresence 9/day, 0.0% err
apps/api/src/routes/internal/query-engine.http.ts 52 gcpInfraMetrics 21/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 9/day, 0.0% err
packages/domain/src/http/query-engine.ts 52 gcpInfraMetrics 21/day, 0.0% err
cloudflareInfraZones 10/day, 0.0% err
gcpInfraPresence 9/day, 0.0% err
apps/api/src/routes/queries.ts 42 gcpInfraMetrics 21/day, 0.0% err
gcpInfraPresence 9/day, 0.0% err
gcpInfraTimeseries 8/day, 0.0% err
packages/backend/src/services/integrations/GcpConnectorService.ts 14 GcpConnectorService.resources 11/day, 0.0% err
GcpConnectorService.scripts 3/day, 0.0% err
Telemetry this change adds and removes (2)
  • ➕ span name QueryEngine.getGcpCloudSqlTopQueries · apps/web/src/api/warehouse/gcp-infra.ts:154
  • ➕ span name QueryEngine.getGcpCloudSqlTraceSide · apps/web/src/api/warehouse/gcp-infra.ts:179
What was checked
  • infraSearch sends only project, declared in gcpSearchSchema (routes/infra/gcp/index.tsx:66)
  • useIntervalRefresh accepts the new catchUp option (hooks/use-interval-refresh.ts:16)
  • Each new LAB_ENTRIES path has a route added in this PR
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
Google Cloud infra reads from the web page (fleet, timeseries, sparklines, SQL) client yes Maple telemetry shows QueryEngine.getGcpInfraMetrics / gcpInfraMetrics / gcpInfraPresence spans on maple-web
Internal query-engine routes for the GCP infra queries server yes same span names appear under maple-api in the route traffic rollup

b5a69fd · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

This branch is being deployed

1 queued deployment
pr-preview — b5a69fda Deployed Oct 16, 2026 by JeremyFunk via deploy-pr-preview #5178
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Deploy a full PR preview stack (Cloudflare + AWS ingest); removing it tears it down

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant