77 buildDependentCountsSql ,
88 buildGoDependentCountsSql ,
99 buildNugetDependentCountsSql ,
10+ buildRubygemsDependentCountsSql ,
1011} from '../queries/dependentCountsSql'
1112
1213const { bqExportToGcs } = proxyActivities < typeof depsDevActivities > ( {
@@ -40,18 +41,19 @@ const { setJobStep } = proxyActivities<typeof depsDevActivities>({
4041 retry : { maximumAttempts : 3 } ,
4142} )
4243
43- // The dependent-counts ingest runs three independent ways, one per source of reverse-dependent data:
44- // - 'edges' : NPM/MAVEN/PYPI/CARGO from the deps.dev `Dependents` reverse index (single SELECT)
45- // - 'go' : GO from the GoRequirementsLatest exact reverse transitive closure (BQ script)
46- // - 'nuget' : NUGET from the NuGetRequirementsLatest exact reverse transitive closure (BQ script)
47- // All three produce the same three columns (dependent_count, transitive_dependent_count,
44+ // The dependent-counts ingest runs four independent ways, one per source of reverse-dependent data:
45+ // - 'edges' : NPM/MAVEN/PYPI/CARGO from the deps.dev `Dependents` reverse index (single SELECT)
46+ // - 'go' : GO from the GoRequirementsLatest exact reverse transitive closure (BQ script)
47+ // - 'nuget' : NUGET from the NuGetRequirementsLatest exact reverse transitive closure (BQ script)
48+ // - 'rubygems' : RUBYGEMS from the RubyGemsRequirementsLatest exact reverse transitive closure (BQ script)
49+ // All four produce the same three columns (dependent_count, transitive_dependent_count,
4850// dependent_repos_count) — deps.dev gives the edge systems their transitive graph directly, while
49- // GO/NUGET compute it via the semi-naive closure script (isScript, see ADR-0004 + dependentCountsSql).
50- // Each way is its own job kind, staging table, guard baseline, and purl-disjoint merge — so a corrupt
51- // edge snapshot aborts only the edge way and the GO/NUGET counts ( manifest-sourced, unaffected) still
52- // update. 'edges' keeps the original `dependent_counts` kind so existing job history / monitor / guard
53- // baseline stay continuous.
54- export type DependentCountsVariant = 'edges' | 'go' | 'nuget'
51+ // GO/NUGET/RUBYGEMS compute it via the semi-naive closure script (isScript, see ADR-0004 +
52+ // dependentCountsSql). Each way is its own job kind, staging table, guard baseline, and purl-disjoint
53+ // merge — so a corrupt edge snapshot aborts only the edge way and the manifest-sourced counts
54+ // (unaffected) still update. 'edges' keeps the original `dependent_counts` kind so existing job
55+ // history / monitor / guard baseline stay continuous.
56+ export type DependentCountsVariant = 'edges' | 'go' | 'nuget' | 'rubygems'
5557
5658interface VariantConfig {
5759 jobKind : OsspckgsJobKind
@@ -61,10 +63,11 @@ interface VariantConfig {
6163 pgColumns : string [ ]
6264 maxBytesGb : number
6365 buildSql : ( snapshotDate : string ) => string
64- // When true, buildSql returns a multi-statement BQ script (the GO/NUGET exact reverse transitive
65- // closure) that ends by creating TEMP TABLE _export_data, rather than a single SELECT. The export
66- // activity then appends only EXPORT DATA and enforces the byte ceiling via maximumBytesBilled
67- // instead of a dry-run. See ADR-0004. Unset (single-SELECT) for the edges variant; set for GO/NUGET.
66+ // When true, buildSql returns a multi-statement BQ script (the GO/NUGET/RUBYGEMS exact reverse
67+ // transitive closure) that ends by creating TEMP TABLE _export_data, rather than a single SELECT.
68+ // The export activity then appends only EXPORT DATA and enforces the byte ceiling via
69+ // maximumBytesBilled instead of a dry-run. See ADR-0004. Unset (single-SELECT) for the edges
70+ // variant; set for GO/NUGET/RUBYGEMS.
6871 isScript ?: boolean
6972}
7073
@@ -73,8 +76,9 @@ interface VariantConfig {
7376const EDGES_STAGING = 'staging.osspckgs_dependent_counts_raw'
7477const GO_STAGING = 'staging.osspckgs_dependent_counts_go_raw'
7578const NUGET_STAGING = 'staging.osspckgs_dependent_counts_nuget_raw'
79+ const RUBYGEMS_STAGING = 'staging.osspckgs_dependent_counts_rubygems_raw'
7680
77- // All three ways now produce the same shape: purl + the three count columns. Each variant has its own
81+ // All four ways now produce the same shape: purl + the three count columns. Each variant has its own
7882// staging table (parallel-safe) but identical DDL/merge; the merges touch disjoint purl spaces (one
7983// per ecosystem), so they never collide.
8084const PG_COLUMNS = [
@@ -116,11 +120,11 @@ const VARIANTS: Record<DependentCountsVariant, VariantConfig> = {
116120 maxBytesGb : 2000 ,
117121 buildSql : ( snapshotDate ) => buildDependentCountsSql ( snapshotDate ) ,
118122 } ,
119- // GO/NUGET run the exact reverse transitive closure script (isScript). maxBytesGb is the
120- // server-side maximumBytesBilled runaway cap, set well above the validated full-pipeline spend
121- // (GO 2.31 TB incl. the all-depth repos aggregation; NUGET ~32 GB) so a normal week never trips
122- // it — the iteration cap inside the script is the deterministic guard. Env-overridable via
123- // BQ_DATASET_INGEST_DEPENDENT_COUNTS_GO_MAX_BQ_GB / _NUGET_.
123+ // GO/NUGET/RUBYGEMS run the exact reverse transitive closure script (isScript). maxBytesGb is
124+ // the server-side maximumBytesBilled runaway cap, set well above the validated full-pipeline
125+ // spend (GO 2.31 TB incl. the all-depth repos aggregation; NUGET ~32 GB) so a normal week never
126+ // trips it — the iteration cap inside the script is the deterministic guard. Env-overridable via
127+ // BQ_DATASET_INGEST_DEPENDENT_COUNTS_GO_MAX_BQ_GB / _NUGET_ / _RUBYGEMS_ .
124128 go : {
125129 jobKind : 'dependent_counts_go' ,
126130 stagingTable : GO_STAGING ,
@@ -141,6 +145,18 @@ const VARIANTS: Record<DependentCountsVariant, VariantConfig> = {
141145 buildSql : ( snapshotDate ) => buildNugetDependentCountsSql ( snapshotDate ) ,
142146 isScript : true ,
143147 } ,
148+ // RubyGems: same shape as NUGET (manifest-sourced closure), similarly small corpus
149+ // (~1.7M pkgs / ~4.5M runtime edges — verified via BQ 2026-07-13).
150+ rubygems : {
151+ jobKind : 'dependent_counts_rubygems' ,
152+ stagingTable : RUBYGEMS_STAGING ,
153+ stagingDdl : stagingDdl ( RUBYGEMS_STAGING ) ,
154+ mergeSql : dependentCountsMerge ( RUBYGEMS_STAGING ) ,
155+ pgColumns : PG_COLUMNS ,
156+ maxBytesGb : 200 ,
157+ buildSql : ( snapshotDate ) => buildRubygemsDependentCountsSql ( snapshotDate ) ,
158+ isScript : true ,
159+ } ,
144160}
145161
146162const ROWS_PER_CHUNK = 1_000_000
0 commit comments