@ttt-productions/q-core 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/constants/sports.d.ts +1 -0
  2. package/dist/constants/sports.d.ts.map +1 -1
  3. package/dist/constants/sports.js +2 -0
  4. package/dist/constants/sports.js.map +1 -1
  5. package/dist/doc-schemas/admin-notifications.d.ts +1 -1
  6. package/dist/doc-schemas/audit-event.d.ts +2 -0
  7. package/dist/doc-schemas/audit-event.d.ts.map +1 -1
  8. package/dist/doc-schemas/award-group-grant.d.ts +2 -2
  9. package/dist/doc-schemas/gallery.d.ts.map +1 -1
  10. package/dist/doc-schemas/gallery.js +9 -3
  11. package/dist/doc-schemas/gallery.js.map +1 -1
  12. package/dist/doc-schemas/game-stat-history.js +2 -2
  13. package/dist/doc-schemas/game-stat-history.js.map +1 -1
  14. package/dist/doc-schemas/migration-console.d.ts +21 -5
  15. package/dist/doc-schemas/migration-console.d.ts.map +1 -1
  16. package/dist/doc-schemas/pending-media.d.ts.map +1 -1
  17. package/dist/doc-schemas/pending-media.js +8 -3
  18. package/dist/doc-schemas/pending-media.js.map +1 -1
  19. package/dist/doc-schemas/picture-retirement.d.ts.map +1 -1
  20. package/dist/doc-schemas/picture-retirement.js +8 -3
  21. package/dist/doc-schemas/picture-retirement.js.map +1 -1
  22. package/dist/doc-schemas/registry.d.ts +25 -14
  23. package/dist/doc-schemas/registry.d.ts.map +1 -1
  24. package/dist/doc-schemas/stats-operation.d.ts +22 -18
  25. package/dist/doc-schemas/stats-operation.d.ts.map +1 -1
  26. package/dist/doc-schemas/stats-operation.js +5 -0
  27. package/dist/doc-schemas/stats-operation.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/migration-console/action-ids.d.ts +4 -0
  33. package/dist/migration-console/action-ids.d.ts.map +1 -1
  34. package/dist/migration-console/action-ids.js +6 -0
  35. package/dist/migration-console/action-ids.js.map +1 -1
  36. package/dist/migration-console/console-lock.d.ts +10 -0
  37. package/dist/migration-console/console-lock.d.ts.map +1 -0
  38. package/dist/migration-console/console-lock.js +14 -0
  39. package/dist/migration-console/console-lock.js.map +1 -0
  40. package/dist/migration-console/consumed-source.d.ts +4 -0
  41. package/dist/migration-console/consumed-source.d.ts.map +1 -0
  42. package/dist/migration-console/consumed-source.js +10 -0
  43. package/dist/migration-console/consumed-source.js.map +1 -0
  44. package/dist/migration-console/manifest.d.ts +2 -0
  45. package/dist/migration-console/manifest.d.ts.map +1 -1
  46. package/dist/migration-console/manifest.js +173 -5
  47. package/dist/migration-console/manifest.js.map +1 -1
  48. package/dist/migration-console/run-state.d.ts +2 -0
  49. package/dist/migration-console/run-state.d.ts.map +1 -1
  50. package/dist/migration-console/run-state.js +3 -0
  51. package/dist/migration-console/run-state.js.map +1 -1
  52. package/dist/paths/picture-owner-paths.d.ts.map +1 -1
  53. package/dist/paths/picture-owner-paths.js +2 -1
  54. package/dist/paths/picture-owner-paths.js.map +1 -1
  55. package/dist/schemas/awards.d.ts +3 -3
  56. package/dist/schemas/migration-console.d.ts +58 -8
  57. package/dist/schemas/migration-console.d.ts.map +1 -1
  58. package/dist/schemas/migration-console.js +4 -0
  59. package/dist/schemas/migration-console.js.map +1 -1
  60. package/dist/schemas/scoring.d.ts +20 -20
  61. package/dist/schemas/stats.d.ts +12 -0
  62. package/dist/schemas/stats.d.ts.map +1 -1
  63. package/dist/schemas/stats.js +21 -1
  64. package/dist/schemas/stats.js.map +1 -1
  65. package/dist/sports/finalized-record.d.ts +2 -2
  66. package/dist/sports/finalized-record.d.ts.map +1 -1
  67. package/dist/sports/finalized-record.js +21 -2
  68. package/dist/sports/finalized-record.js.map +1 -1
  69. package/dist/types/audit.d.ts +1 -1
  70. package/dist/types/audit.d.ts.map +1 -1
  71. package/dist/types/audit.js +1 -0
  72. package/dist/types/audit.js.map +1 -1
  73. package/dist/utils/index.d.ts +1 -0
  74. package/dist/utils/index.d.ts.map +1 -1
  75. package/dist/utils/index.js +1 -0
  76. package/dist/utils/index.js.map +1 -1
  77. package/dist/utils/league-calendar.d.ts.map +1 -1
  78. package/dist/utils/league-calendar.js +6 -1
  79. package/dist/utils/league-calendar.js.map +1 -1
  80. package/dist/utils/stats-operation-request.d.ts +20 -0
  81. package/dist/utils/stats-operation-request.d.ts.map +1 -0
  82. package/dist/utils/stats-operation-request.js +10 -0
  83. package/dist/utils/stats-operation-request.js.map +1 -0
  84. package/package.json +2 -1
@@ -1,4 +1,6 @@
1
1
  import { MIGRATION_ACTION_IDS as A } from './action-ids.js';
2
+ import { SPORT_KEYS } from '../types/sports.js';
3
+ import { MAX_MIGRATION_PAGE_SIZE, MIGRATION_COMMIT_WRITE_LIMIT } from './run-state.js';
2
4
  export const MIGRATION_STEP_KIND_KEYS = [
3
5
  'executable',
4
6
  'productControl',
@@ -34,6 +36,7 @@ const SINGLE_DOCUMENT = 'One source document; it is never paged.';
34
36
  const COPY_RECOVERY = 'Fix the transform and run the copy again; it refuses a live destination.';
35
37
  const VERIFY_RECOVERY = 'Repair what it reports, through its copy or its resolution, and verify again.';
36
38
  const DELETE_RECOVERY = 'Forward repair only: the retained V1 Firestore export holds what was deleted.';
39
+ const V1_CHECK_RECOVERY = 'Fix what it reports in V1, then run the check again.';
37
40
  function copyStep(id, options) {
38
41
  return {
39
42
  kind: 'executable',
@@ -43,10 +46,12 @@ function copyStep(id, options) {
43
46
  destructive: false,
44
47
  paged: true,
45
48
  defaultPageSize: options.defaultPageSize ?? 100,
49
+ maxPageSize: options.maxPageSize ?? MAX_MIGRATION_PAGE_SIZE,
46
50
  informational: false,
47
51
  idempotency: COPY_IDEMPOTENCY,
48
52
  resumeKey: options.resumeKey ?? BY_DOCUMENT_ID,
49
53
  recovery: COPY_RECOVERY,
54
+ consumes: [],
50
55
  title: options.title,
51
56
  summary: options.summary,
52
57
  owningStep: options.owningStep,
@@ -63,10 +68,12 @@ function verifyStep(id, options) {
63
68
  destructive: false,
64
69
  paged: true,
65
70
  defaultPageSize: options.defaultPageSize ?? 100,
71
+ maxPageSize: options.maxPageSize ?? MAX_MIGRATION_PAGE_SIZE,
66
72
  informational: options.informational ?? false,
67
73
  idempotency: VERIFY_IDEMPOTENCY,
68
74
  resumeKey: options.resumeKey ?? BY_DOCUMENT_ID,
69
- recovery: VERIFY_RECOVERY,
75
+ recovery: options.recovery ?? VERIFY_RECOVERY,
76
+ consumes: [],
70
77
  title: options.title,
71
78
  summary: options.summary,
72
79
  owningStep: options.owningStep,
@@ -74,6 +81,13 @@ function verifyStep(id, options) {
74
81
  orderedAfter: options.orderedAfter ?? [],
75
82
  };
76
83
  }
84
+ function v1CheckStep(id, options) {
85
+ return verifyStep(id, {
86
+ dependsOn: [A.checkpointV1FirestoreExport],
87
+ ...options,
88
+ recovery: V1_CHECK_RECOVERY,
89
+ });
90
+ }
77
91
  function deleteStep(id, options) {
78
92
  return {
79
93
  kind: 'executable',
@@ -83,10 +97,12 @@ function deleteStep(id, options) {
83
97
  destructive: true,
84
98
  paged: true,
85
99
  defaultPageSize: options.defaultPageSize ?? 100,
100
+ maxPageSize: options.maxPageSize ?? MAX_MIGRATION_PAGE_SIZE,
86
101
  informational: false,
87
102
  idempotency: DELETE_IDEMPOTENCY,
88
103
  resumeKey: options.resumeKey ?? BY_DOCUMENT_ID,
89
104
  recovery: DELETE_RECOVERY,
105
+ consumes: options.consumes,
90
106
  title: options.title,
91
107
  summary: options.summary,
92
108
  owningStep: options.owningStep,
@@ -140,6 +156,27 @@ export const MIGRATION_CUTOVER_MANIFEST = [
140
156
  evidence: 'The export operation name and the bucket path it wrote to.',
141
157
  noReturnBoundary: null,
142
158
  },
159
+ v1CheckStep(A.verifyV1DisplayNamesUnique, {
160
+ title: 'Check no two V1 display names collide',
161
+ summary: 'Lists every group of V1 accounts whose display names normalize to one reservation key. The profiles are copied only once it finds none.',
162
+ owningStep: 'migration-console',
163
+ }),
164
+ v1CheckStep(A.verifyV1TextFitsLimits, {
165
+ title: 'Check every V1 text fits its V2 field',
166
+ summary: 'Lists every V1 text a copy carries into a capped V2 field that is over the field’s limit or that its schema would change. The copies it covers run only once it finds none.',
167
+ owningStep: 'migration-console',
168
+ }),
169
+ v1CheckStep(A.verifyV1LeagueCapacity, {
170
+ title: 'Check no V1 league is over capacity',
171
+ summary: 'Lists every V1 league holding more games or teams than a league may. The leagues, teams, and games are copied only once it finds none.',
172
+ owningStep: 'migration-console',
173
+ }),
174
+ v1CheckStep(A.verifyV1HardwareContractIdsUnique, {
175
+ title: 'Check no hardware contract id is in both V1 collections',
176
+ summary: 'Lists every contract id found in both V1 hardware collections. The contracts are copied only once it finds none.',
177
+ owningStep: 'migration-console',
178
+ resumeKey: 'The V1 collections in turn, each by document id; the resume key is `{collection}/{id}`.',
179
+ }),
143
180
  copyStep(A.copyAdminList, {
144
181
  title: 'Copy the admin and referee rosters',
145
182
  summary: 'The `landing/admin` role maps become `_systemData/adminList`, the roster every role check reads.',
@@ -157,12 +194,14 @@ export const MIGRATION_CUTOVER_MANIFEST = [
157
194
  title: 'Copy the app configuration',
158
195
  summary: 'The version and the banner from `landing/base` become `_appConfig/app`, its switches at their open defaults.',
159
196
  owningStep: 'q-core',
197
+ dependsOn: [A.verifyV1TextFitsLimits],
160
198
  resumeKey: SINGLE_DOCUMENT,
161
199
  }),
162
200
  copyStep(A.copyLandingPageConfig, {
163
201
  title: 'Copy the landing page copy',
164
202
  summary: 'The hero title and the about text become `_appConfig/landingPage`; its picture arrives with the picture carry.',
165
203
  owningStep: 'q-core',
204
+ dependsOn: [A.verifyV1TextFitsLimits],
166
205
  resumeKey: SINGLE_DOCUMENT,
167
206
  }),
168
207
  copyStep(A.copyStatsBeacon, {
@@ -196,6 +235,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
196
235
  title: 'Copy the waiver templates',
197
236
  summary: 'Each template under its id, its wording as version 1.',
198
237
  owningStep: 'high-risk-callables',
238
+ dependsOn: [A.verifyV1TextFitsLimits],
239
+ maxPageSize: 200,
199
240
  }),
200
241
  verifyStep(A.verifyWaiverTemplates, {
201
242
  title: 'Verify the waiver templates',
@@ -207,6 +248,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
207
248
  title: 'Copy the game locations',
208
249
  summary: 'Each venue on `landing/admin` becomes a `gameLocations` document under its id; its picture arrives with the picture carry.',
209
250
  owningStep: 'q-core',
251
+ dependsOn: [A.verifyV1TextFitsLimits],
210
252
  resumeKey: 'The venues in array order; the resume key is the last venue id.',
211
253
  }),
212
254
  verifyStep(A.verifyGameLocations, {
@@ -220,6 +262,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
220
262
  title: 'Copy the profiles',
221
263
  summary: 'Each `users` document becomes its profile and its owner-only private document, every account active.',
222
264
  owningStep: 'auth',
265
+ dependsOn: [A.verifyV1DisplayNamesUnique, A.verifyV1TextFitsLimits],
266
+ maxPageSize: Math.floor(MIGRATION_COMMIT_WRITE_LIMIT / 2),
223
267
  }),
224
268
  verifyStep(A.verifyUserProfiles, {
225
269
  title: 'Verify the profiles',
@@ -244,6 +288,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
244
288
  summary: 'Each pre-Q-Sports career total becomes its sport’s `historicalStats` document.',
245
289
  owningStep: 'stat-data-model',
246
290
  dependsOn: [A.copyUserProfiles],
291
+ maxPageSize: Math.floor(MIGRATION_COMMIT_WRITE_LIMIT / SPORT_KEYS.length),
247
292
  }),
248
293
  verifyStep(A.verifyHistoricalStats, {
249
294
  title: 'Verify the historical baselines',
@@ -253,9 +298,10 @@ export const MIGRATION_CUTOVER_MANIFEST = [
253
298
  }),
254
299
  copyStep(A.deriveReservedDisplayNames, {
255
300
  title: 'Reserve the display names',
256
- summary: 'One reservation per copied profile; two names that collide are reported for an admin rename.',
301
+ summary: 'One reservation per copied profile.',
257
302
  owningStep: 'auth',
258
- dependsOn: [A.copyUserProfiles],
303
+ dependsOn: [A.copyUserProfiles, A.verifyV1DisplayNamesUnique],
304
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
259
305
  }),
260
306
  verifyStep(A.verifyReservedDisplayNames, {
261
307
  title: 'Verify the display-name reservations',
@@ -267,6 +313,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
267
313
  title: 'Migrate the public identities in place',
268
314
  summary: 'Each `publicUsers` document is rewritten where it sits: epoch timestamps, the recomputed lowercase name, the ghost flag.',
269
315
  owningStep: 'q-core',
316
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
270
317
  }),
271
318
  verifyStep(A.verifyPublicUsers, {
272
319
  title: 'Verify the public identities',
@@ -278,7 +325,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
278
325
  title: 'Copy the award catalog',
279
326
  summary: 'Each award on `landing/admin` becomes an `awardDefinitions` document with its holder count; its badge arrives with the picture carry.',
280
327
  owningStep: 'uploads-and-media',
281
- dependsOn: [A.copyUserProfiles],
328
+ dependsOn: [A.copyUserProfiles, A.verifyV1TextFitsLimits],
282
329
  resumeKey: 'The awards in array order; the resume key is the last award id.',
283
330
  }),
284
331
  verifyStep(A.verifyAwardDefinitions, {
@@ -292,6 +339,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
292
339
  title: 'Copy the leagues',
293
340
  summary: 'Each league under its id — closed leagues included; its pictures arrive with the picture carry.',
294
341
  owningStep: 'q-core',
342
+ dependsOn: [A.verifyV1LeagueCapacity, A.verifyV1TextFitsLimits],
343
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
295
344
  }),
296
345
  verifyStep(A.verifySportLeagues, {
297
346
  title: 'Verify the leagues',
@@ -303,6 +352,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
303
352
  title: 'Copy the teams',
304
353
  summary: 'Each team under its id, its season lines in its sport’s shape.',
305
354
  owningStep: 'q-core',
355
+ dependsOn: [A.verifyV1LeagueCapacity, A.verifyV1TextFitsLimits],
356
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
306
357
  }),
307
358
  verifyStep(A.verifyLeagueTeams, {
308
359
  title: 'Verify the teams',
@@ -315,6 +366,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
315
366
  summary: 'Each membership under its compound id, `member` becoming `player`; one whose team was not copied into its league is left behind and reported.',
316
367
  owningStep: 'q-core',
317
368
  dependsOn: [A.copyLeagueTeams],
369
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
318
370
  }),
319
371
  verifyStep(A.verifyTeamMemberships, {
320
372
  title: 'Verify the memberships',
@@ -327,6 +379,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
327
379
  summary: 'Each invitation by id; a pending one whose invitee is already on the team is written approved, and a pending one whose team was not copied into its league is left behind and reported.',
328
380
  owningStep: 'high-risk-callables',
329
381
  dependsOn: [A.copyLeagueTeams, A.copyTeamMemberships],
382
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
330
383
  }),
331
384
  verifyStep(A.verifyTeamInvitations, {
332
385
  title: 'Verify the invitations',
@@ -339,6 +392,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
339
392
  summary: 'Each request by id; a pending one whose requester is already on the team is written approved, and a pending one whose team was not copied into its league is left behind and reported.',
340
393
  owningStep: 'high-risk-callables',
341
394
  dependsOn: [A.copyLeagueTeams, A.copyTeamMemberships],
395
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
342
396
  }),
343
397
  verifyStep(A.verifyTeamJoinRequests, {
344
398
  title: 'Verify the join requests',
@@ -351,6 +405,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
351
405
  summary: 'Each signup under its built id; a signup whose player already joined a team in the league is left behind and reported.',
352
406
  owningStep: 'high-risk-callables',
353
407
  dependsOn: [A.copyTeamMemberships],
408
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
354
409
  }),
355
410
  verifyStep(A.verifyLeagueFreeAgents, {
356
411
  title: 'Verify the free-agent signups',
@@ -363,6 +418,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
363
418
  summary: 'Every signed waiver, a ghost’s included, under its id; its signature file stays where it is.',
364
419
  owningStep: 'uploads-and-media',
365
420
  dependsOn: [A.copyWaiverTemplates],
421
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
366
422
  }),
367
423
  verifyStep(A.verifySignedWaivers, {
368
424
  title: 'Verify the signed waivers',
@@ -374,7 +430,9 @@ export const MIGRATION_CUTOVER_MANIFEST = [
374
430
  title: 'Copy the hardware loan contracts',
375
431
  summary: 'Each contract from both V1 collections under its id; its signature file stays where it is.',
376
432
  owningStep: 'high-risk-callables',
433
+ dependsOn: [A.verifyV1HardwareContractIdsUnique],
377
434
  resumeKey: 'The V1 collections in turn, each by document id; the resume key is `{collection}/{id}`.',
435
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
378
436
  }),
379
437
  verifyStep(A.verifyHardwareLoanContracts, {
380
438
  title: 'Verify the hardware loan contracts',
@@ -396,6 +454,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
396
454
  owningStep: 'high-risk-callables',
397
455
  resumeKey: 'The V1 games by document id; the resume key is the last game id.',
398
456
  defaultPageSize: 50,
457
+ maxPageSize: 50,
399
458
  }),
400
459
  {
401
460
  kind: 'executable',
@@ -405,10 +464,12 @@ export const MIGRATION_CUTOVER_MANIFEST = [
405
464
  destructive: false,
406
465
  paged: false,
407
466
  defaultPageSize: 1,
467
+ maxPageSize: MAX_MIGRATION_PAGE_SIZE,
408
468
  informational: false,
409
469
  idempotency: 'A second resolution of the same line is acknowledged and writes nothing.',
410
470
  resumeKey: 'One game, one line; it is never paged.',
411
471
  recovery: 'Resolve the line again with the right team, then copy the game again.',
472
+ consumes: [],
412
473
  title: 'Resolve a stat line no roster places',
413
474
  summary: 'For a line the game copy stops on, the admin names its team: the missing roster entry is written with its reason, and the game copied again.',
414
475
  owningStep: 'stat-data-model',
@@ -419,10 +480,11 @@ export const MIGRATION_CUTOVER_MANIFEST = [
419
480
  title: 'Copy the games',
420
481
  summary: 'Each V1 game with its stats: the event documents, the rollup, the participation lists by roster entry, and a completed game’s finalized record.',
421
482
  owningStep: 'stat-data-model',
422
- dependsOn: [A.copyGameRosterPlayers],
483
+ dependsOn: [A.copyGameRosterPlayers, A.verifyV1LeagueCapacity],
423
484
  orderedAfter: [A.resolveUnrosteredStatLine],
424
485
  resumeKey: 'The V1 games by document id; a game’s documents commit before its id becomes the resume key.',
425
486
  defaultPageSize: 20,
487
+ maxPageSize: 25,
426
488
  }),
427
489
  verifyStep(A.verifySportGames, {
428
490
  title: 'Verify the game schedules',
@@ -436,6 +498,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
436
498
  owningStep: 'stat-data-model',
437
499
  dependsOn: [A.copySportGames],
438
500
  defaultPageSize: 20,
501
+ maxPageSize: 25,
439
502
  }),
440
503
  {
441
504
  kind: 'executable',
@@ -445,10 +508,12 @@ export const MIGRATION_CUTOVER_MANIFEST = [
445
508
  destructive: false,
446
509
  paged: true,
447
510
  defaultPageSize: 20,
511
+ maxPageSize: 25,
448
512
  informational: false,
449
513
  idempotency: 'Each open game is reconciled through the roster core against the copied memberships; a reconciled game changes nothing on a re-run.',
450
514
  resumeKey: 'The open games by document id; the resume key is the last game id.',
451
515
  recovery: 'Run it again: a game held by another operation is reported and reconciled on the next run.',
516
+ consumes: [],
452
517
  title: 'Reconcile the open games’ rosters',
453
518
  summary: 'Each game open at the cutover: stale stat-free entries removed, missing members added.',
454
519
  owningStep: 'high-risk-callables',
@@ -489,10 +554,12 @@ export const MIGRATION_CUTOVER_MANIFEST = [
489
554
  destructive: true,
490
555
  paged: true,
491
556
  defaultPageSize: 100,
557
+ maxPageSize: 100,
492
558
  informational: false,
493
559
  idempotency: 'A ghost document is deleted only when nothing references it; a re-run finds nothing further.',
494
560
  resumeKey: BY_DOCUMENT_ID,
495
561
  recovery: DELETE_RECOVERY,
562
+ consumes: [],
496
563
  title: 'Remove the ghost names nothing references',
497
564
  summary: 'Each ghost `publicUsers` document no membership, roster entry, or unvoided stat event names, reported by disposition first. No signed waiver is touched.',
498
565
  owningStep: 'high-risk-callables',
@@ -586,6 +653,7 @@ export const MIGRATION_CUTOVER_MANIFEST = [
586
653
  owningStep: 'auth',
587
654
  dependsOn: [A.verifyAdminList],
588
655
  resumeKey: SINGLE_DOCUMENT,
656
+ consumes: [A.copyAdminList, A.verifyAdminList],
589
657
  }),
590
658
  deleteStep(A.deleteV1LandingBase, {
591
659
  title: 'Delete `landing/base`',
@@ -598,12 +666,25 @@ export const MIGRATION_CUTOVER_MANIFEST = [
598
666
  A.verifyV1Pictures,
599
667
  ],
600
668
  resumeKey: SINGLE_DOCUMENT,
669
+ consumes: [
670
+ A.copyAppConfig,
671
+ A.copyLandingPageConfig,
672
+ A.copyStatsBeacon,
673
+ A.verifyAppConfig,
674
+ A.verifyLandingPageConfig,
675
+ A.verifyStatsBeacon,
676
+ A.carryV1Pictures,
677
+ A.verifyV1Pictures,
678
+ A.verifyV1TextFitsLimits,
679
+ ],
601
680
  }),
602
681
  deleteStep(A.deleteV1Waivers, {
603
682
  title: 'Delete the V1 waiver templates',
604
683
  summary: 'The `waivers` collection.',
605
684
  owningStep: 'high-risk-callables',
606
685
  dependsOn: [A.verifyWaiverTemplates],
686
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
687
+ consumes: [A.copyWaiverTemplates, A.verifyWaiverTemplates, A.verifyV1TextFitsLimits],
607
688
  }),
608
689
  deleteStep(A.deleteV1GameLocations, {
609
690
  title: 'Remove the V1 venues',
@@ -611,6 +692,13 @@ export const MIGRATION_CUTOVER_MANIFEST = [
611
692
  owningStep: 'q-core',
612
693
  dependsOn: [A.verifyGameLocations, A.verifyV1Pictures],
613
694
  resumeKey: SINGLE_DOCUMENT,
695
+ consumes: [
696
+ A.copyGameLocations,
697
+ A.verifyGameLocations,
698
+ A.carryV1Pictures,
699
+ A.verifyV1Pictures,
700
+ A.verifyV1TextFitsLimits,
701
+ ],
614
702
  }),
615
703
  deleteStep(A.deleteV1AwardCatalog, {
616
704
  title: 'Remove the V1 award catalog',
@@ -623,42 +711,75 @@ export const MIGRATION_CUTOVER_MANIFEST = [
623
711
  A.verifyV1Pictures,
624
712
  ],
625
713
  resumeKey: SINGLE_DOCUMENT,
714
+ consumes: [
715
+ A.copyAwardDefinitions,
716
+ A.verifyAwardDefinitions,
717
+ A.carryV1Pictures,
718
+ A.verifyV1Pictures,
719
+ A.verifyV1TextFitsLimits,
720
+ ],
626
721
  }),
627
722
  deleteStep(A.deleteV1Users, {
628
723
  title: 'Delete the V1 user documents',
629
724
  summary: 'Each `users` document with its historical baselines.',
630
725
  owningStep: 'auth',
631
726
  dependsOn: [A.verifyUserProfiles, A.verifyHistoricalStats, A.verifyReservedDisplayNames],
727
+ maxPageSize: 200,
728
+ consumes: [
729
+ A.copyUserProfiles,
730
+ A.verifyUserProfiles,
731
+ A.copyHistoricalStats,
732
+ A.verifyHistoricalStats,
733
+ A.migratePublicUsers,
734
+ A.verifyPublicUsers,
735
+ A.verifyV1DisplayNamesUnique,
736
+ A.verifyV1TextFitsLimits,
737
+ ],
632
738
  }),
633
739
  deleteStep(A.deleteV1TeamInvites, {
634
740
  title: 'Delete the V1 invitations',
635
741
  summary: 'The `teamInvites` collection.',
636
742
  owningStep: 'high-risk-callables',
637
743
  dependsOn: [A.verifyTeamInvitations],
744
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
745
+ consumes: [A.copyTeamInvitations, A.verifyTeamInvitations],
638
746
  }),
639
747
  deleteStep(A.deleteV1JoinRequests, {
640
748
  title: 'Delete the V1 join requests',
641
749
  summary: 'The `joinRequests` collection.',
642
750
  owningStep: 'high-risk-callables',
643
751
  dependsOn: [A.verifyTeamJoinRequests],
752
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
753
+ consumes: [A.copyTeamJoinRequests, A.verifyTeamJoinRequests],
644
754
  }),
645
755
  deleteStep(A.deleteV1FreeAgentSignups, {
646
756
  title: 'Delete the V1 free-agent signups',
647
757
  summary: 'The `freeAgentSignups` collection, left-behind signups included.',
648
758
  owningStep: 'high-risk-callables',
649
759
  dependsOn: [A.verifyLeagueFreeAgents],
760
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
761
+ consumes: [A.copyLeagueFreeAgents, A.verifyLeagueFreeAgents],
650
762
  }),
651
763
  deleteStep(A.deleteV1TeamMembers, {
652
764
  title: 'Delete the V1 memberships',
653
765
  summary: 'The `teamMembers` collection.',
654
766
  owningStep: 'q-core',
655
767
  dependsOn: [A.verifyTeamMemberships],
768
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
769
+ consumes: [A.copyTeamMemberships, A.verifyTeamMemberships],
656
770
  }),
657
771
  deleteStep(A.deleteV1Teams, {
658
772
  title: 'Delete the V1 teams',
659
773
  summary: 'The `teams` collection; a team still holding a subcollection is reported and kept.',
660
774
  owningStep: 'q-core',
661
775
  dependsOn: [A.verifyLeagueTeams],
776
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
777
+ consumes: [
778
+ A.copyLeagueTeams,
779
+ A.verifyLeagueTeams,
780
+ A.verifyV1LeagueCapacity,
781
+ A.verifyV1TextFitsLimits,
782
+ ],
662
783
  }),
663
784
  {
664
785
  kind: 'executable',
@@ -668,10 +789,12 @@ export const MIGRATION_CUTOVER_MANIFEST = [
668
789
  destructive: true,
669
790
  paged: true,
670
791
  defaultPageSize: 100,
792
+ maxPageSize: 200,
671
793
  informational: false,
672
794
  idempotency: 'Removes a kept file’s download token; a file holding none is skipped. No file is moved or deleted.',
673
795
  resumeKey: 'The signed waivers by id, then the contracts; the resume key is the record path.',
674
796
  recovery: 'Run it again; a file whose token went is skipped.',
797
+ consumes: [],
675
798
  title: 'Revoke the V1 signature download links',
676
799
  summary: 'Each kept signature file loses the download token V1’s stored links carry, so those links stop resolving.',
677
800
  owningStep: 'uploads-and-media',
@@ -687,6 +810,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
687
810
  summary: 'The `waiverSignatures` records; the files stay, named by the copied records.',
688
811
  owningStep: 'uploads-and-media',
689
812
  dependsOn: [A.verifySignedWaivers],
813
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
814
+ consumes: [A.copySignedWaivers, A.verifySignedWaivers],
690
815
  }),
691
816
  deleteStep(A.deleteV1HardwareContracts, {
692
817
  title: 'Delete the V1 hardware contracts',
@@ -694,6 +819,12 @@ export const MIGRATION_CUTOVER_MANIFEST = [
694
819
  owningStep: 'high-risk-callables',
695
820
  dependsOn: [A.verifyHardwareLoanContracts],
696
821
  resumeKey: 'The V1 collections in turn, each by document id; the resume key is `{collection}/{id}`.',
822
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
823
+ consumes: [
824
+ A.copyHardwareLoanContracts,
825
+ A.verifyHardwareLoanContracts,
826
+ A.verifyV1HardwareContractIdsUnique,
827
+ ],
697
828
  }),
698
829
  deleteStep(A.deleteV1GameRosters, {
699
830
  title: 'Delete the V1 game rosters',
@@ -702,6 +833,14 @@ export const MIGRATION_CUTOVER_MANIFEST = [
702
833
  dependsOn: [A.verifyGameRosterPlayers, A.validateStats],
703
834
  resumeKey: 'The V1 games by document id; the resume key is the last game id.',
704
835
  defaultPageSize: 50,
836
+ maxPageSize: 50,
837
+ consumes: [
838
+ A.copyGameRosterPlayers,
839
+ A.verifyGameRosterPlayers,
840
+ A.copySportGames,
841
+ A.verifySportGames,
842
+ A.verifyGameStats,
843
+ ],
705
844
  }),
706
845
  deleteStep(A.deleteV1LeagueGames, {
707
846
  title: 'Delete the V1 games',
@@ -714,6 +853,15 @@ export const MIGRATION_CUTOVER_MANIFEST = [
714
853
  A.validateStats,
715
854
  A.deleteV1GameRosters,
716
855
  ],
856
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
857
+ consumes: [
858
+ A.copySportGames,
859
+ A.verifySportGames,
860
+ A.verifyGameStats,
861
+ A.copyGameRosterPlayers,
862
+ A.verifyGameRosterPlayers,
863
+ A.verifyV1LeagueCapacity,
864
+ ],
717
865
  }),
718
866
  deleteStep(A.deleteV1LeagueChats, {
719
867
  title: 'Delete the V1 league chats',
@@ -722,6 +870,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
722
870
  dependsOn: [A.checkpointV1FirestoreExport],
723
871
  resumeKey: 'The V1 leagues by document id; the resume key is the last league id, or `{leagueId}/unfinished` while a league holds more chats than one page deletes.',
724
872
  defaultPageSize: 50,
873
+ maxPageSize: 50,
874
+ consumes: [],
725
875
  }),
726
876
  deleteStep(A.deleteV1Leagues, {
727
877
  title: 'Delete the V1 leagues',
@@ -729,12 +879,24 @@ export const MIGRATION_CUTOVER_MANIFEST = [
729
879
  owningStep: 'q-core',
730
880
  dependsOn: [A.verifySportLeagues, A.verifyV1Pictures],
731
881
  orderedAfter: [A.verifyLeaguePlayerStats, A.deleteV1LeagueChats],
882
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
883
+ consumes: [
884
+ A.copySportLeagues,
885
+ A.verifySportLeagues,
886
+ A.verifyLeaguePlayerStats,
887
+ A.carryV1Pictures,
888
+ A.verifyV1Pictures,
889
+ A.verifyV1LeagueCapacity,
890
+ A.verifyV1TextFitsLimits,
891
+ ],
732
892
  }),
733
893
  deleteStep(A.deleteV1HallOfFame, {
734
894
  title: 'Delete the V1 hall of fame',
735
895
  summary: 'The `hallOfFame` collection, once every sport that keeps a hall of fame has its rebuilt document.',
736
896
  owningStep: 'stat-data-model',
737
897
  dependsOn: [A.verifySportHallOfFame],
898
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
899
+ consumes: [A.verifySportHallOfFame],
738
900
  }),
739
901
  deleteStep(A.deleteV1ValidationReports, {
740
902
  title: 'Delete the V1 validation reports',
@@ -742,12 +904,16 @@ export const MIGRATION_CUTOVER_MANIFEST = [
742
904
  owningStep: 'stat-data-model',
743
905
  dependsOn: [A.checkpointV1FirestoreExport],
744
906
  orderedAfter: [A.validateStats],
907
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
908
+ consumes: [],
745
909
  }),
746
910
  deleteStep(A.deleteV1AdminStats, {
747
911
  title: 'Delete the V1 dashboard counts',
748
912
  summary: 'The `adminStats` collection. Nothing is copied: the dashboard counts are counted live.',
749
913
  owningStep: 'q-core',
750
914
  dependsOn: [A.checkpointV1FirestoreExport],
915
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
916
+ consumes: [],
751
917
  }),
752
918
  verifyStep(A.verifyV1CommerceDiscardable, {
753
919
  title: 'Check the V1 store holds no purchase',
@@ -762,6 +928,8 @@ export const MIGRATION_CUTOVER_MANIFEST = [
762
928
  owningStep: 'high-risk-callables',
763
929
  dependsOn: [A.verifyV1CommerceDiscardable],
764
930
  resumeKey: 'The six store collections in turn, each by document id.',
931
+ maxPageSize: MIGRATION_COMMIT_WRITE_LIMIT,
932
+ consumes: [A.verifyV1CommerceDiscardable],
765
933
  }),
766
934
  {
767
935
  kind: 'operatorCheckpoint',