@catalyst-cloud/schema 0.1.57 → 0.1.59

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.57",
3
+ "version": "0.1.59",
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",
@@ -2121,6 +2121,15 @@ export interface TelemetryEventSpec {
2121
2121
  * time CTC-1510 read it — re-measure before citing it, don't re-derive it from this text.
2122
2122
  */
2123
2123
  export const telemetryEventTypes = {
2124
+ "telemetry.ingest.tenant-forged": {
2125
+ reason:
2126
+ "CTC-2788 — a gateway payload named a tenant other than its token's on `account_id` or " +
2127
+ "`catalyst.tenant`, and the gateway overwrote it. Rare by construction: a current runner image " +
2128
+ "emits `catalyst.tenant` equal to its own tenant, so this fires only on a stale or wrong token, " +
2129
+ "or on a deliberate forgery. Each occurrence is independently actionable (which tenant held the " +
2130
+ "token, which tenant was claimed, which signal), so it is never sampled away.",
2131
+ sampling: { kind: "always" },
2132
+ },
2124
2133
  "account.ratelimit.sampled": {
2125
2134
  reason: "A periodic provider rate-limit budget reading — a gauge, not a state transition.",
2126
2135
  },
package/src/index.ts CHANGED
@@ -358,3 +358,92 @@ export function tableMeta(table: SQLiteTable): TableMeta {
358
358
  export const MIRROR_TABLE_META: Record<MirrorEntityName, TableMeta> = Object.fromEntries(
359
359
  Object.entries(mirrorEntityTables).map(([name, table]) => [name, tableMeta(table)]),
360
360
  ) as Record<MirrorEntityName, TableMeta>;
361
+
362
+ // ── CTC-151 — THE ONE entity→provider partition ────────────────────────────────────────────────────
363
+ //
364
+ // ⭐ Buckets are keyed off `feedEntityTables` (CTC-671 doctrine: feed membership has exactly one
365
+ // definition), NOT off apps/mirror's SNAPSHOT_TABLES (which omits `push_events`, a real feed
366
+ // entity) and NOT off the SDK's four-name `entitySource` map — measured wrong for 9 of the
367
+ // mirror's 13 GitHub snapshot entities (a `pr_review_comments` apply event arrives labeled
368
+ // `source:"linear"`), which is why host-sync relabels through THIS partition and never trusts the
369
+ // SDK's field. Consumers: apps/mirror's rebroadcast scope (derived from GITHUB_FEED_ENTITIES) and
370
+ // apps/host-sync's per-provider freshness observations (folded through feedEntitySource).
371
+
372
+ /** The upstream provider a feed entity originates from. Catalyst/registry-plane entities have NO
373
+ * provider — see NON_PROVIDER_FEED_ENTITIES. */
374
+ export type FeedEntitySource = "linear" | "github";
375
+
376
+ /** The GitHub-sourced feed entities (14). */
377
+ export const GITHUB_FEED_ENTITIES: readonly FeedEntityName[] = [
378
+ "pull_requests",
379
+ "check_runs",
380
+ "commit_statuses",
381
+ "reviews",
382
+ // CTC-575/577 — inline review comments, PR conversation comments, PR commits, PR timeline events.
383
+ "pr_review_comments",
384
+ "pr_conversation_comments",
385
+ "pr_commits",
386
+ "pr_events",
387
+ // CTC-667 — the pushed git ref head, deployments + their status history, PR review thread
388
+ // resolution state.
389
+ "pushes",
390
+ "deployments",
391
+ "deployment_statuses",
392
+ "pr_review_threads",
393
+ // CTC-667 item 4 / CTC-704 — GitHub's own check-suite rollup and the per-DELIVERY push log.
394
+ "check_suites",
395
+ "push_events",
396
+ ];
397
+
398
+ /** The Linear-sourced feed entities (14). `users` is mixed-provider at the row level; callers
399
+ * needing provider-specific timestamps must filter its `source` column. */
400
+ export const LINEAR_FEED_ENTITIES: readonly FeedEntityName[] = [
401
+ "issues",
402
+ "labels",
403
+ "users",
404
+ "issue_labels",
405
+ "relations",
406
+ "issue_history",
407
+ "projects",
408
+ "cycles",
409
+ "workflow_states",
410
+ "initiatives",
411
+ "project_initiatives",
412
+ "comments",
413
+ // CTC-524 — populated from Linear session/activity reconciliation.
414
+ "agent_sessions",
415
+ "agent_activities",
416
+ ];
417
+
418
+ /**
419
+ * The feed entities with NO provider (4). ⛔ Never file these under a provider bucket: filing
420
+ * catalyst-plane activity under Linear would manufacture Linear freshness from non-Linear rows —
421
+ * "answering one source's question with the other's data is the failure mode this whole surface
422
+ * exists to expose" (apps/mirror/src/do/changefeed.ts, the github-deferrals rule).
423
+ */
424
+ export const NON_PROVIDER_FEED_ENTITIES: readonly FeedEntityName[] = [
425
+ // CTC-624 — the per-team workflow decision, projected from the D1 registry (ADR-0033). (The
426
+ // mirror's rebroadcast scope deliberately keeps it on the Linear SIDE so a mapping travels with
427
+ // the workflow_states rows it resolves against; that is a purge-scope choice, not attribution.)
428
+ "team_workflow_mapping",
429
+ // CTC-350 — fleet coordination current-state.
430
+ "fleet_activity",
431
+ // CTC-355 — per-host fleet liveness + open anomaly signals.
432
+ "fleet_host_liveness",
433
+ "fleet_anomalies",
434
+ ];
435
+
436
+ const GITHUB_ENTITY_SET: ReadonlySet<string> = new Set(GITHUB_FEED_ENTITIES);
437
+ const LINEAR_ENTITY_SET: ReadonlySet<string> = new Set(LINEAR_FEED_ENTITIES);
438
+
439
+ /**
440
+ * Runtime lookup: the provider a wire `entity` name originates from. Typed string in, TRI-STATE
441
+ * out — a non-provider feed entity, an infra table, or an unknown/future name yields `null`, never
442
+ * a defaulted bucket (the SDK's "everything else is linear" default is the defect this replaces).
443
+ * Exhaustiveness over FEED_ENTITY_NAMES is pinned by test/entity-sources.test.ts.
444
+ */
445
+ export function feedEntitySource(entity: string): FeedEntitySource | null {
446
+ if (GITHUB_ENTITY_SET.has(entity)) return "github";
447
+ if (LINEAR_ENTITY_SET.has(entity)) return "linear";
448
+ return null;
449
+ }