@catalyst-cloud/schema 0.1.51 → 0.1.52
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 +1 -1
- package/src/migrations.generated.ts +9 -0
- package/src/mirror.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@catalyst-cloud/schema",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.52",
|
|
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",
|
|
@@ -277,6 +277,13 @@ export const MIRROR_MIGRATIONS = {
|
|
|
277
277
|
tag: "0037_ctc1597_workflow_slot_intake",
|
|
278
278
|
breakpoints: true,
|
|
279
279
|
},
|
|
280
|
+
{
|
|
281
|
+
idx: 38,
|
|
282
|
+
version: "6",
|
|
283
|
+
when: 1788900456820,
|
|
284
|
+
tag: "0038_ctc1855_fleet_activity_routing",
|
|
285
|
+
breakpoints: true,
|
|
286
|
+
},
|
|
280
287
|
],
|
|
281
288
|
},
|
|
282
289
|
migrations: {
|
|
@@ -353,5 +360,7 @@ export const MIRROR_MIGRATIONS = {
|
|
|
353
360
|
"CREATE TABLE `fleet_activity_rate` (\n\t`host_id` text NOT NULL,\n\t`ticket` text NOT NULL,\n\t`bucket_start_ms` integer NOT NULL,\n\t`events` integer NOT NULL,\n\tPRIMARY KEY(`host_id`, `ticket`, `bucket_start_ms`)\n);\n--> statement-breakpoint\nCREATE TABLE `fleet_anomalies` (\n\t`kind` text NOT NULL,\n\t`host_id` text NOT NULL,\n\t`ticket` text NOT NULL,\n\t`detected_at_ms` integer NOT NULL,\n\t`observed` integer NOT NULL,\n\t`baseline` integer NOT NULL,\n\t`detail` text,\n\t`updated_at` integer NOT NULL,\n\tPRIMARY KEY(`kind`, `host_id`, `ticket`)\n);\n--> statement-breakpoint\nCREATE TABLE `fleet_health_sends` (\n\t`host_id` text NOT NULL,\n\t`status` text NOT NULL,\n\t`status_changed_at_ms` integer NOT NULL,\n\t`sent_at_ms` integer NOT NULL,\n\t`delivered` integer NOT NULL,\n\t`failed` integer NOT NULL,\n\tPRIMARY KEY(`host_id`, `status`, `status_changed_at_ms`)\n);\n--> statement-breakpoint\nCREATE TABLE `fleet_host_liveness` (\n\t`host_id` text PRIMARY KEY NOT NULL,\n\t`status` text NOT NULL,\n\t`reason` text,\n\t`last_heartbeat_ms` integer,\n\t`last_activity_ms` integer,\n\t`last_seen_ms` integer,\n\t`period_ms` integer,\n\t`grace_ms` integer,\n\t`agent_version` text,\n\t`status_changed_at_ms` integer,\n\t`updated_at` integer NOT NULL\n);\n",
|
|
354
361
|
"0037_ctc1597_workflow_slot_intake":
|
|
355
362
|
"-- CTC-1597 — rename the persisted workflow slot `triage` -> `intake`.\n--\n-- ⭐ Deliberately a DATA migration in the SHARED bundle (the 0014/0031 pattern): the DO and every\n-- host / OPFS replica apply the same MIRROR_MIGRATIONS through the same runner, so each side renames\n-- its OWN rows locally. That converges every replica WITHOUT emitting a change_log delta per row\n-- (migrations bypass appendChange), so no ring-buffer flood.\n--\n-- ⚠️ THE REGISTRY D1 IS THE AUTHORITY and gets its own migration\n-- (apps/mirror/src/registry/migrations/20260903T1928_workflow_slot_intake.sql); this one exists\n-- because a D1-only rewrite bumps no `workflow_rev` and pushes nothing, so a DO that is never\n-- re-saved would sit on the old value forever. THIS migration is what makes the rename correct on\n-- every DO/replica, including one offline at merge time. There is no separate re-projection script:\n-- an already-connected browser/host that needs to see the rename before its own next open converges\n-- the ordinary way — an operator re-saving that team's stage mapping calls the existing full-replace\n-- projection handler (`handleWorkflowMappingUpsert`, MirrorDO.ts), which DOES emit a change_log\n-- delta. No new production route was added for a one-time rename.\n--\n-- PK-safe: (team_id, slot) — and the PK does NOT consider `removed_at`, so a SOFT-DELETED `intake`\n-- row still occupies the slot. Drop a stale `triage` row for a team that already holds ANY `intake`\n-- row — live or soft-deleted — then rename what is left. Idempotent under execReplaySafe replay — a\n-- row already renamed to `intake` no longer matches `slot = 'triage'` on a re-run.\n--\n-- ⛔ CTC-1597 remediate (C2): an earlier draft of the EXISTS guard filtered `removed_at IS NULL`,\n-- reasoning that a soft-deleted `intake` row should never cause a still-live `triage` row to be\n-- dropped instead of renamed. That reasoning had it backwards — the PK collision this guard exists\n-- to prevent happens precisely BECAUSE `removed_at` is not part of the primary key: a host that\n-- receives a soft-deleted `intake` row via replication (from a DO that already renamed and was then\n-- unmapped) before it has applied this migration locally still has its own live `triage` row: the\n-- DELETE's old filter left the `triage` row in place, and the following blind UPDATE then tried to\n-- rename it to a slot value a row already occupies, violating the PK and aborting the whole bundle.\n-- Matching on ANY `intake` row (regardless of `removed_at`) fixes it: the stale `triage` row is\n-- dropped, not renamed, whenever the slot is already spoken for.\n--\n-- ⛔ CTC-1597 remediate (validate-plan finding 1) — a `triage`-slot row whose OWN mapped state is\n-- ITSELF type='triage' (Linear's reserved Triage inbox, legally name-matched into the OLD\n-- `RECOMMENDED_STAGES` entry before this ticket) must NOT be renamed blind: `SLOT_STATE_TYPES.intake`\n-- no longer accepts that type (Scope B), so renaming it in place would silently flip the team's\n-- `types_compatible` check from pass to a blocking fail with no data fix and no recourse — the write\n-- path's own validation (the same narrowing) would refuse a re-save of the identical row. Soft-delete\n-- it instead, via `removed_at` — this table's own convention for \"this slot is unmapped\" (see the\n-- table's doc comment in packages/schema/src/mirror.ts) — so the team lands in the ordinary,\n-- already-actionable \"needs a stage\" state a brand-new team starts in, which Scope C's per-team\n-- runbook resolves. Runs BEFORE the final rename so no live-or-dead row anywhere keeps the retired\n-- `triage` slot value; guarded by `removed_at IS NULL` so a replay is a no-op.\nUPDATE `team_workflow_mapping`\n SET `removed_at` = CAST(unixepoch() AS INTEGER) * 1000\n WHERE `slot` = 'triage' AND `linear_state_type` = 'triage' AND `removed_at` IS NULL;\n--> statement-breakpoint\nDELETE FROM `team_workflow_mapping`\n WHERE `slot` = 'triage'\n AND EXISTS (SELECT 1 FROM `team_workflow_mapping` m2\n WHERE m2.`team_id` = `team_workflow_mapping`.`team_id` AND m2.`slot` = 'intake');\n--> statement-breakpoint\nUPDATE `team_workflow_mapping` SET `slot` = 'intake' WHERE `slot` = 'triage';\n",
|
|
363
|
+
"0038_ctc1855_fleet_activity_routing":
|
|
364
|
+
"ALTER TABLE `fleet_activity` ADD `provider` text;--> statement-breakpoint\nALTER TABLE `fleet_activity` ADD `model` text;--> statement-breakpoint\nALTER TABLE `fleet_activity` ADD `effort` text;--> statement-breakpoint\nALTER TABLE `fleet_activity` ADD `routing_source` text;",
|
|
356
365
|
},
|
|
357
366
|
} as const;
|
package/src/mirror.ts
CHANGED
|
@@ -1179,6 +1179,14 @@ export const fleet_activity = sqliteTable(
|
|
|
1179
1179
|
pr_number: integer("pr_number"),
|
|
1180
1180
|
pr_url: text("pr_url"),
|
|
1181
1181
|
orch_id: text("orch_id"),
|
|
1182
|
+
// CTC-1855 — the CTC-1095 routing tuple a phase actually started with, projected from the
|
|
1183
|
+
// worker.session.started / phase.<p>.complete attrs the runner already emits. COALESCE-forward
|
|
1184
|
+
// in reduceFleetActivity (a tuple-less later event never wipes it). Nullable: sibling-daemon
|
|
1185
|
+
// rows and pre-migration rows genuinely have no tuple, and absence must stay absence.
|
|
1186
|
+
provider: text("provider"),
|
|
1187
|
+
model: text("model"),
|
|
1188
|
+
effort: text("effort"),
|
|
1189
|
+
routing_source: text("routing_source"), // StageRouting.source verbatim: "exact" | "fallback"
|
|
1182
1190
|
last_event_name: text("last_event_name"),
|
|
1183
1191
|
last_event_ts: integer("last_event_ts"), // ms epoch — the reducer watermark
|
|
1184
1192
|
updated_at: integer("updated_at"), // ms epoch — mirrors last_event_ts; upsertRow guard column
|