@catalyst-cloud/schema 0.1.17 → 0.1.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catalyst-cloud/schema",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "type": "module",
5
5
  "description": "Typed Drizzle schema = single source of truth for the per-tenant Mirror DO SQLite store (CTC-13 / ADR-0002). Shared by the mirror Worker, the host-sync replica, and the browser OPFS replica.",
6
6
  "license": "MIT",
@@ -207,6 +207,13 @@ export const MIRROR_MIGRATIONS = {
207
207
  tag: "0027_closed_miek",
208
208
  breakpoints: true,
209
209
  },
210
+ {
211
+ idx: 28,
212
+ version: "6",
213
+ when: 1787038129996,
214
+ tag: "0028_burly_nemesis",
215
+ breakpoints: true,
216
+ },
210
217
  ],
211
218
  },
212
219
  migrations: {
@@ -264,5 +271,6 @@ export const MIRROR_MIGRATIONS = {
264
271
  "CREATE TABLE `deployment_statuses` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`deployment_id` text NOT NULL,\n\t`state` text,\n\t`environment` text,\n\t`target_url` text,\n\t`environment_url` text,\n\t`description` text,\n\t`creator_id` text,\n\t`created_at` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_deployment_statuses_deployment` ON `deployment_statuses` (`deployment_id`,`created_at`);--> statement-breakpoint\nCREATE TABLE `deployments` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`ref` text,\n\t`sha` text,\n\t`task` text,\n\t`environment` text,\n\t`production_environment` integer,\n\t`transient_environment` integer,\n\t`description` text,\n\t`creator_id` text,\n\t`created_at` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_deployments_repo_env` ON `deployments` (`repo_id`,`environment`,`created_at`);--> statement-breakpoint\nCREATE TABLE `pr_review_threads` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`resolved` integer,\n\t`resolved_at` integer,\n\t`resolver_id` text,\n\t`first_comment_id` text,\n\t`comment_count` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_pr_review_threads_pr` ON `pr_review_threads` (`repo_id`,`pr_number`);",
265
272
  "0027_closed_miek":
266
273
  "CREATE TABLE `check_suites` (\n\t`repo_id` text NOT NULL,\n\t`check_suite_id` text PRIMARY KEY NOT NULL,\n\t`head_sha` text,\n\t`head_branch` text,\n\t`status` text,\n\t`conclusion` text,\n\t`app_slug` text,\n\t`latest_check_runs_count` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_check_suites_sha` ON `check_suites` (`head_sha`);--> statement-breakpoint\nCREATE TABLE `push_events` (\n\t`delivery_id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`ref` text NOT NULL,\n\t`before` text,\n\t`after` text,\n\t`forced` integer,\n\t`created` integer,\n\t`deleted` integer,\n\t`base_ref` text,\n\t`pusher_id` text,\n\t`head_commit_sha` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_push_events_repo_ref` ON `push_events` (`repo_id`,`ref`,`updated_at`);--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `merge_commit_sha` text;",
274
+ "0028_burly_nemesis": "ALTER TABLE `check_suites` ADD `pull_request_numbers` text;",
267
275
  },
268
276
  } as const;
package/src/mirror.ts CHANGED
@@ -843,6 +843,37 @@ export const check_suites = sqliteTable(
843
843
  app_slug: text("app_slug"),
844
844
  /** GitHub's own count of the runs in the suite; useful for spotting a suite still filling up. */
845
845
  latest_check_runs_count: integer("latest_check_runs_count"),
846
+ /**
847
+ * CTC-712 — the PRs GitHub itself attributed this suite to, as a JSON array of numbers
848
+ * (`"[123,124]"`). ⛔ THE CONSUMER'S ONLY KEY. `broker/router.mjs:1497` reaches an interest for
849
+ * `github.check_suite.completed` exclusively through `detail.prNumbers`; an empty one means the
850
+ * CI wait is never resolved, and under `enforce` there is no smee copy to recover it from.
851
+ *
852
+ * ⛔⛔ DO NOT DERIVE THIS FROM `head_sha` → `pull_requests.head_sha`. `pull_requests.head_sha` is
853
+ * LAST-STATE, so a suite that ran against a head the PR has since moved past can never be joined
854
+ * back. Measured by CTL on mini-2 (CTC-712): of 202 suites, 93 joined (46%) and 109 missed (54%)
855
+ * — and the misses were active PR branches (`ryan/ctl-1944-direnv-fleet` 25, `ryan/ctl-1949-ask-
856
+ * traps` 19), not main. ⭐ The sharpest row: `ctc-pin-sdk-0.8.13` appears in BOTH the hits (10)
857
+ * and the misses (10) — one branch, where only the suites matching the PR's CURRENT head join.
858
+ * That is the superseded-head pattern isolated in a single branch, so the 46% is structural.
859
+ *
860
+ * ⚠️ Worse than a coverage gap, it is a RACE: the join cannot tell a legitimately-superseded
861
+ * suite from a current one whose PR moved a moment later, and it drops both — silently, as an
862
+ * emit-decline rather than an error. Same class as the `pushes` collapse (CTC-704), fixed the
863
+ * same way: store the EDGE the payload carries, not a projection of state.
864
+ *
865
+ * ⚠️ `null` AND `"[]"` ARE DIFFERENT ANSWERS and the distinction is deliberate. `null` = GitHub's
866
+ * payload carried no `pull_requests` field at all (we do not know); `"[]"` = GitHub told us this
867
+ * suite belongs to no PR (a `main` push, `release-please--*`). A consumer that must not
868
+ * distinguish them collapses both to the empty list — which is exactly what the tunnel producer
869
+ * already does (`webhook-events.ts` `parseCheckSuite` builds `prNumbers: []` for both), so this
870
+ * column is at PARITY with the tunnel it replaces and strictly more informative.
871
+ *
872
+ * ⚠️ KNOWN LIMIT, stated rather than discovered later: GitHub delivers an EMPTY `pull_requests`
873
+ * for a suite on a FORK's PR. That is a real blind spot — but it is the tunnel's blind spot too,
874
+ * for the same reason, so retiring the tunnel loses nothing here.
875
+ */
876
+ pull_request_numbers: text("pull_request_numbers"),
846
877
  updated_at: integer("updated_at"),
847
878
  },
848
879
  (t) => [index("idx_check_suites_sha").on(t.head_sha)],