diff --git a/core/crates/ployz-build/src/execution.rs b/core/crates/ployz-build/src/execution.rs index 28e6d0d431..0b6d018fef 100644 --- a/core/crates/ployz-build/src/execution.rs +++ b/core/crates/ployz-build/src/execution.rs @@ -15,6 +15,8 @@ pub enum Stage { Building, Output, Cleanup, + /// Pushing the built image out of the host, after the Build itself (`ployz build`). + Push, } /// Bounded output and work observations from the execution host. diff --git a/core/crates/ployz-sdk/index.d.ts b/core/crates/ployz-sdk/index.d.ts index 0353be9451..27ae1c4432 100644 --- a/core/crates/ployz-sdk/index.d.ts +++ b/core/crates/ployz-sdk/index.d.ts @@ -125,7 +125,10 @@ export type PreparationEvent = | { Selected: { machine: import("./generated/payloads").Machine; reason: BuilderReason; rejections: string[] } } | { Build: { Stage: string } | { Output: number[] } | { Step: BuildStep } | { StepOutput: { step: string; stderr: boolean; text: string } } | { Timing: unknown } | { Target: { name: string; outcome: unknown } } } | "Transfer" - | { Delivered: { image: string; machine_id: MachineId } }; + /** One Service's image starts going to these Machines, by name. */ + | { Sending: { service: string; machines: string[] } } + /** One Machine received a Service's image. */ + | { Delivered: { image: string; service: string; machine_id: MachineId } }; export type RunningPreparation = AsyncIterable & { abort(): void; diff --git a/core/crates/ployz/src/deploy/pipeline.rs b/core/crates/ployz/src/deploy/pipeline.rs index 2a7048eaf1..9ea3f6cce0 100644 --- a/core/crates/ployz/src/deploy/pipeline.rs +++ b/core/crates/ployz/src/deploy/pipeline.rs @@ -248,12 +248,6 @@ fn invalid_argument(message: String) -> RpcError { } } -#[derive(Clone, Debug, Eq, PartialEq)] -pub(crate) struct PushOutcome { - pub pushed: Vec, - pub failures: Vec, -} - #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct PushedImage { pub image: String, @@ -274,8 +268,8 @@ pub(crate) async fn push_project_images( machines: &[MachineObservation], preview: &DeployPlan, cancellation: &CancellationToken, -) -> Result { - let mut pushed = Vec::new(); + progress: &impl Fn(crate::sdk::prepare::Progress), +) -> Result, crate::sdk::prepare::PreparationError> { let mut failures = Vec::new(); // Check every actual destination before any image or application changes. let deliveries = builds.iter().map(|service| { @@ -297,15 +291,34 @@ pub(crate) async fn push_project_images( if targets.is_empty() { continue; } + // The Build Machine already holds its image; only the others receive it. + let receivers = machines + .iter() + .filter(|machine| machine.machine.id != service.machine_id) + .filter(|machine| targets.contains(&machine.machine.id.to_string())) + .map(|machine| machine.machine.name.clone()) + .collect::>(); + if !receivers.is_empty() { + progress(crate::sdk::prepare::Progress::Sending { + service: service.name.clone(), + machines: receivers, + }); + } match push_image(client, service, machines, &targets, cancellation).await { Ok((images, service_failures)) => { - pushed.extend(images); + for image in images { + progress(crate::sdk::prepare::Progress::Delivered { + image: image.image, + service: service.name.clone(), + machine_id: image.machine_id, + }); + } failures.extend(service_failures); } Err(error) => failures.push(format!("{}: {error}", service.image)), } } - Ok(PushOutcome { pushed, failures }) + Ok(failures) } pub(crate) async fn plan_project( diff --git a/core/crates/ployz/src/handlers/build.rs b/core/crates/ployz/src/handlers/build.rs index 6e55816b7a..27818b21d9 100644 --- a/core/crates/ployz/src/handlers/build.rs +++ b/core/crates/ployz/src/handlers/build.rs @@ -82,26 +82,25 @@ pub(super) fn build(root: &ArgMatches) -> Result<(), Error> { } .into()); } - let events = matches - .get_one::("events") - .map(std::fs::File::create) - .transpose()? - .map(std::sync::Mutex::new); + let events = std::sync::Arc::new(Events( + matches + .get_one::("events") + .map(std::fs::File::create) + .transpose()? + .map(std::sync::Mutex::new), + )); runtime()?.block_on(async { let cancellation = crate::cancellation::on_ctrl_c(); let build = captured.build; let export = cancellation.clone(); + let building = events.clone(); let (build, built) = tokio::task::spawn_blocking(move || { - let built = build.execute_local(&cancellation, &|event| { - if let Some(file) = &events { - write_event(file, event); - } - }); + let built = build.execute_local(&cancellation, &|event| building.write(event)); (build, built) }) .await .map_err(std::io::Error::other)?; - push(&grant, &built.map_err(BuildCommandError::from)?).await?; + push(&grant, &built.map_err(BuildCommandError::from)?, &events).await?; // The pushed image and its printed result are final; uploading cache only speeds up // the next Build, so its failure is a warning and it never reaches the events file. let exported = tokio::task::spawn_blocking(move || build.export_local_cache(&export)) @@ -116,16 +115,28 @@ pub(super) fn build(root: &ArgMatches) -> Result<(), Error> { }) } -/// One `{"at": , "event": }` line, the shape Cloud's build -/// log reads. Progress is best effort: a failed write never fails the build. -fn write_event(file: &std::sync::Mutex, event: &ployz_build::Progress) { - use std::io::Write as _; - let at = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .map_or(0, |elapsed| elapsed.as_millis()); - let line = json!({"at": at, "event": {"Build": event}}); - if let Ok(mut file) = file.lock() { - let _ = writeln!(file, "{line}"); +/// The `--events` file: one `{"at": , "event": {"Build": }}` line per +/// event, the SDK preparation event shape Cloud's build log reads. Progress is best effort: +/// a failed write never fails the build. +struct Events(Option>); + +impl Events { + fn write(&self, event: &ployz_build::Progress) { + use std::io::Write as _; + let Some(file) = &self.0 else { return }; + let at = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_or(0, |elapsed| elapsed.as_millis()); + if let Ok(mut file) = file.lock() { + let _ = writeln!(file, "{}", json!({"at": at, "event": {"Build": event}})); + } + } + + /// One line of the push: output of the open `Push` stage. + fn push_line(&self, line: &str) { + self.write(&ployz_build::Progress::Output( + format!("{line}\n").into_bytes(), + )); } } @@ -179,17 +190,19 @@ fn git(source: &Path, args: &[&str]) -> Result { } /// Push through the grant with `docker push`, which sends only the layers the Machine -/// lacks, and print what the Machine verified it received. -async fn push(grant: &BuildGrant, built: &LocalImage) -> Result<(), Error> { +/// lacks, and print what the Machine verified it received. Each layer's progress line +/// goes to the events file as the push's output. +async fn push(grant: &BuildGrant, built: &LocalImage, events: &Events) -> Result<(), Error> { let digest = &built.image.reference; let hex = digest .strip_prefix("sha256:") .ok_or(BuildCommandError::NotDigestIdentified)?; let tag = format!("{}:{RETAINED_DIGEST_TAG_PREFIX}{hex}", built.repository); + events.write(&ployz_build::Progress::Stage(ployz_build::Stage::Push)); let registry = open_grant_registry(grant, &ManagementRelay::default()).await?; let local = format!("{}/{tag}", registry.address()); docker(&["tag", digest, &local]).await?; - let pushed = docker(&["push", "--quiet", &local]).await; + let pushed = docker_push(&local, events).await; // The loopback name is meaningless once this command exits. let _ = docker(&["image", "rm", &local]).await; if let Err(error) = pushed { @@ -197,6 +210,7 @@ async fn push(grant: &BuildGrant, built: &LocalImage) -> Result<(), Error> { BuildCommandError::GrantRefused(refusal).into() })); } + events.push_line(&format!("Pushed {digest}")); // The Machine stores a tagged manifest only when its bytes hash to the tag's // digest, so a completed push is the Machine's confirmation of `digest`. println!( @@ -206,6 +220,46 @@ async fn push(grant: &BuildGrant, built: &LocalImage) -> Result<(), Error> { Ok(()) } +/// `docker push`, its per-layer lines streamed to the events file as they come. +async fn docker_push(reference: &str, events: &Events) -> Result<(), Error> { + use tokio::io::AsyncBufReadExt as _; + let mut child = tokio::process::Command::new("docker") + .args(["push", reference]) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn()?; + let stderr = child.stderr.take().map(|stderr| { + tokio::spawn(async move { + let mut text = String::new(); + let _ = tokio::io::AsyncReadExt::read_to_string( + &mut tokio::io::BufReader::new(stderr), + &mut text, + ) + .await; + text + }) + }); + if let Some(stdout) = child.stdout.take() { + let mut lines = tokio::io::BufReader::new(stdout).lines(); + while let Ok(Some(line)) = lines.next_line().await { + events.push_line(&line); + } + } + let status = child.wait().await?; + let stderr = match stderr { + Some(task) => task.await.unwrap_or_default(), + None => String::new(), + }; + if status.success() { + return Ok(()); + } + Err(BuildCommandError::Docker { + command: "push".to_owned(), + stderr: stderr.trim().to_owned(), + } + .into()) +} + async fn docker(args: &[&str]) -> Result<(), Error> { let output = tokio::process::Command::new("docker") .args(args) diff --git a/core/crates/ployz/src/sdk/prepare.rs b/core/crates/ployz/src/sdk/prepare.rs index 6a9e37b91b..5f4110122d 100644 --- a/core/crates/ployz/src/sdk/prepare.rs +++ b/core/crates/ployz/src/sdk/prepare.rs @@ -220,8 +220,15 @@ pub enum Progress { Selected(Box), Build(ployz_build::Progress), Transfer, + /// One Service's image starts going to these Machines, by name. + Sending { + service: ployz_core::ServiceName, + machines: Vec, + }, + /// One Machine received a Service's image. Delivered { image: String, + service: ployz_core::ServiceName, machine_id: ployz_core::MachineId, }, } @@ -272,27 +279,22 @@ pub async fn prepare( if !builds.is_empty() { progress(Progress::Transfer); } - let outcome = crate::deploy::pipeline::push_project_images( + let failures = crate::deploy::pipeline::push_project_images( client, &builds, &machines, &plan, cancellation, + &progress, ) .await?; - for image in outcome.pushed { - progress(Progress::Delivered { - image: image.image, - machine_id: image.machine_id, - }); - } if cancellation.is_cancelled() { return Err(PreparationError::Cancelled); } - if !outcome.failures.is_empty() { + if !failures.is_empty() { return Err(PreparationError::Delivery(format!( "image push failed: {}", - outcome.failures.join("; ") + failures.join("; ") ))); } Ok(Prepared { plan, builds }) diff --git a/core/crates/ployz/src/sdk/running.rs b/core/crates/ployz/src/sdk/running.rs index 4095beeb7c..7ada05249d 100644 --- a/core/crates/ployz/src/sdk/running.rs +++ b/core/crates/ployz/src/sdk/running.rs @@ -52,6 +52,7 @@ impl OutputBudget { | Progress::Platforms(_) | Progress::Selected(_) | Progress::Transfer + | Progress::Sending { .. } | Progress::Delivered { .. } => 0, }; buffered.fetch_add(size, Ordering::Relaxed); diff --git a/dashboard/CONTEXT.md b/dashboard/CONTEXT.md index 2d036a25ad..d84c60081f 100644 --- a/dashboard/CONTEXT.md +++ b/dashboard/CONTEXT.md @@ -248,7 +248,7 @@ How a Service's image is described for building: a Dockerfile or Railpack. _Avoid_: Builder, builder type **Build Step**: -One unit of an Image Build as the Engine reports it: a BuildKit step (a Dockerfile instruction, image resolution, or context transfer) or a Ployz-owned phase such as source upload or image delivery. A Build Step is keyed stably within its attempt, changes state until it completes, and owns the output attributed to it. Build Steps are retained with the attempt, separately from lifecycle history. +One unit of an Image Build: a BuildKit step (a Dockerfile instruction, image resolution, or context transfer) or a Ployz-owned phase such as source upload, waiting for a runner, installing ployz, pushing, or sending the image to a Machine. Each is recorded where it happens, so its timing is honest: Cloud times the wait for a runner, the runner its install and push, the Engine the rest. A Build Step is keyed stably within one Builder's go at its Image Build, changes state until it completes, and owns the output attributed to it. Each go is a section of the Image Build's one log; a later one opens with why the build moved there. Build Steps are retained with the attempt, separately from lifecycle history. _Avoid_: Build log line, vertex, build stage (a Cloud Deployment Stage is not a Build Step) Git repository identity and access are separate. Cloud can read a public GitHub repository anonymously or use an Organization member's connected GitHub App installation. Public access never falls back to installation credentials. Both paths pin a commit per Cloud Deployment Attempt and materialize it through the same source acquisition module. Automatic Git deployment and CI gating require installation access; public sources deploy manually. diff --git a/dashboard/drizzle/20260926031614_build_step_attempt/migration.sql b/dashboard/drizzle/20260926031614_build_step_attempt/migration.sql new file mode 100644 index 0000000000..fd31d2d085 --- /dev/null +++ b/dashboard/drizzle/20260926031614_build_step_attempt/migration.sql @@ -0,0 +1,3 @@ +ALTER TABLE "environment_deployment_build_step" ADD COLUMN "attempt" integer DEFAULT 0 NOT NULL;--> statement-breakpoint +ALTER TABLE "environment_deployment_build_step" DROP CONSTRAINT "environment_deployment_build_step_key_unique";--> statement-breakpoint +ALTER TABLE "environment_deployment_build_step" ADD CONSTRAINT "environment_deployment_build_step_key_unique" UNIQUE NULLS NOT DISTINCT("deployment_id","image","attempt","build","key"); \ No newline at end of file diff --git a/dashboard/drizzle/20260926031614_build_step_attempt/snapshot.json b/dashboard/drizzle/20260926031614_build_step_attempt/snapshot.json new file mode 100644 index 0000000000..7d21a73044 --- /dev/null +++ b/dashboard/drizzle/20260926031614_build_step_attempt/snapshot.json @@ -0,0 +1,10933 @@ +{ + "version": "8", + "dialect": "postgres", + "id": "a4bbbd3a-2d08-4ed7-ae96-314abb4987b1", + "prevIds": [ + "49d3687c-4bc4-49e7-a802-9a2be33ef704" + ], + "ddl": [ + { + "isRlsEnabled": false, + "name": "organization", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_change", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "invitation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "member", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "session", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "user", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "verification", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "project", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "user_project_preference", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_canvas_node_position", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_resource", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "resource_lineage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "service", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "service_lineage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "service_registry_credential", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "variable", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "variable_secret", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment_build_output", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment_build_step", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment_event", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment_image_build", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_deployment_secret", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_saved_state_snapshot", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_build_order", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "core_operation_event", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "core_operation_watch", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_node_config_snapshot", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_node_config_snapshot_secret", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_node_introduction", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "environment_node_introduction_secret", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_pairing", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "teardown_attempt", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "volume_remove_attempt", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "enrollment_allocation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "machine_enrollment_token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "machine_remove_attempt", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_machine", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_branch_projection", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_check_suite_projection", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_environment_trigger", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_installation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_repository_cache", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_webhook_delivery", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_billing_state", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization_cluster_domain", + "entityType": "tables", + "schema": "public" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "slug", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "logo", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": { + "type": "always", + "name": "organization_change_seq_seq", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "9223372036854775807", + "cache": 1, + "cycle": false + }, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "xid8", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "pg_current_xact_id()", + "generated": null, + "identity": null, + "name": "xid", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "source_table", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "changed_ids", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "deleted_ids", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "all_rows", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization_change" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "password", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inviter_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'member'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "active_organization_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "active_organization_slug", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "true", + "generated": null, + "identity": null, + "name": "sidebar_open", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ip_address", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_agent", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "email_verified", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "true", + "generated": null, + "identity": null, + "name": "open_started_deployments", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "identifier", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "value", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "namespace", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "intent", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "project" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "project" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "project" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "slug", + "entityType": "columns", + "schema": "public", + "table": "project" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "project" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "user_project_preference" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "resource_type", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "resource_id", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "x", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "y", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "lineage_id", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "implementation_type", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_resource" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "canonical_name", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "canonical_slug", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "resource_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "lineage_id", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'{\"autoDeploy\":true,\"waitForCi\":false,\"watchPaths\":[],\"imageUpdate\":{\"type\":\"off\"}}'", + "generated": null, + "identity": null, + "name": "policy", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "has_registry_credential", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "first_deployed_at", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "service" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "canonical_name", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "canonical_slug", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "service_lineage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "service_registry_credential" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "service_registry_credential" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "service_id", + "entityType": "columns", + "schema": "public", + "table": "service_registry_credential" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_registry_username", + "entityType": "columns", + "schema": "public", + "table": "service_registry_credential" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_registry_secret", + "entityType": "columns", + "schema": "public", + "table": "service_registry_credential" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "variable" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "variable" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "variable" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "service_id", + "entityType": "columns", + "schema": "public", + "table": "variable" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "variable" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "variable_id", + "entityType": "columns", + "schema": "public", + "table": "variable_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "variable_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "variable_secret" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_value", + "entityType": "columns", + "schema": "public", + "table": "variable_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "trigger_origin", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "saved_state_snapshot_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "service_action_policy", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'queued'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "core_deploy_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "retry_of_deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'{}'", + "generated": null, + "identity": null, + "name": "source_pins", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "variable_producers", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deploy_manifest", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deploy_preview", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "runtime_progress", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_code", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_message", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancellation_requested_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dispatch_requested_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "finished_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment" + }, + { + "type": "bigserial", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "step_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "stderr", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "text", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "type": "bigserial", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "attempt", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "build", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "key", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "completed_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "cached", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "error", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "type": "bigserial", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "progress", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "service_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'building'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "machine_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "server_choice", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_receipt", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_message", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "finished_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'server'", + "generated": null, + "identity": null, + "name": "builder", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "github_run_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "checked_in_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "github", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "skips", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_secret" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_runtime_outcome", + "entityType": "columns", + "schema": "public", + "table": "environment_deployment_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor_id", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "intent", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "volume_deletion_authorizations", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_build_order" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "build_order", + "entityType": "columns", + "schema": "public", + "table": "organization_build_order" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization_build_order" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_build_order" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "watch_id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sequence", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "event_type", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "schema_version", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "payload", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "core_operation_event" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "operation_id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expected_kind", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start_sequence", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "next_sequence", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cursor_state", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'active'", + "generated": null, + "identity": null, + "name": "observation_state", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "observation_detail", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deadline_at", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "terminal_at", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "core_operation_watch" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_deployment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_type", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_lineage_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "config_version", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "config", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "credential_revision", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "snapshot_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_registry_username", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_registry_secret", + "entityType": "columns", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_type", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_lineage_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "config_version", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "config", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_type", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "node_id", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "authored_intent", + "entityType": "columns", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_pairing_secret", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "removal_started_at", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "removal_endpoints", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "founder_public_key", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "founder_claim_machine_id", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "founder_machine_id", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "first_connect_deployment_evaluated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_pairing" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "requested_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "project_id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirm_data_loss", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "targets", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "outcome", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_message", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "terminal_at", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "teardown_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "requested_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_deployment_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_resource_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "retry_of_attempt_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "volumes", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "outcome", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_message", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "terminal_at", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cluster_key", + "entityType": "columns", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "assignments", + "entityType": "columns", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token_hash", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "requested_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "machine_id", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirm_data_loss", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inngest_run_id", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "missing_identities", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_code", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_message", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "terminal_at", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "machine_id", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cluster_key", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_capability", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "is_dial_entry", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_machine" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository_id", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ref", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "evaluated_head_sha", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "evaluation_reason", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_delivery_id", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_receipt_sequence", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "evaluation_revision", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_branch_projection" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository_id", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "check_suite_id", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "head_sha", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conclusion", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "source_updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_delivery_id", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_receipt_sequence", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "transition_revision", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "published_revision", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository_id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ref", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "head_sha", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "environment_id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'waiting'", + "generated": null, + "identity": null, + "name": "admission_state", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "changed_paths", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "service_ids", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "selection_mode", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reason", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "source_delivery_id", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "source_receipt_sequence", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "branch_evaluation_revision", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "trigger_revision", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "published_revision", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "publish_state", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "published_at", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_login", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_type", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_avatar_url", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository_id", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "full_name", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "default_branch", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "private", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "html_url", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repo_updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "synced_at", + "entityType": "columns", + "schema": "public", + "table": "github_repository_cache" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "delivery_id", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "bigserial", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "receipt_sequence", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "event_kind", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'received'", + "generated": null, + "identity": null, + "name": "processing_state", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "outcome", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_code", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository_id", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ref", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "branch_state", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "head_sha", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "check_suite_id", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "check_suite_action", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "check_suite_status", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "check_suite_conclusion", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "processing_run_id", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "processing_started_at", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "processed_at", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "active_subscription_id", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "current_period_end", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "has_active_subscription", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "synced_at", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "source_updated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_billing_state" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "endpoint", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_token", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reserved_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "lease_renewed_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "records_synced_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "traffic", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "checked_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "encrypted_certificate_private_key", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "certificate_chain", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "certificate_not_after", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "xid", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "organization_change_organization_id_xid_idx", + "entityType": "indexes", + "schema": "public", + "table": "organization_change" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "xid", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "organization_change_xid_idx", + "entityType": "indexes", + "schema": "public", + "table": "organization_change" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "account_user_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "provider_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "account_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "account_provider_account_idx", + "entityType": "indexes", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "email", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_email_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "session_user_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "identifier", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "verification_identifier_idx", + "entityType": "indexes", + "schema": "public", + "table": "verification" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "user_project_preference_user_idx", + "entityType": "indexes", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "user_project_preference_organization_idx", + "entityType": "indexes", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "user_project_preference_project_idx", + "entityType": "indexes", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_canvas_node_position_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_canvas_node_position_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "resource_type", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_canvas_node_position_resource_lookup_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_resource_project_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_resource_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_resource_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "lineage_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_resource_lineage_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "resource_lineage_project_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "resource_lineage_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "service_project_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "service_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "service_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "lineage_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "service_lineage_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "service_lineage_project_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "service_lineage" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "saved_state_snapshot_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_saved_state_snapshot_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" = 'queued' and \"inngest_run_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_one_building_attempt_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" = 'queued' and \"inngest_run_id\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_one_pending_attempt_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" in ('planning','deploying')", + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_one_started_attempt_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "inngest_run_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_inngest_run_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "retry_of_deployment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_retry_of_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "deployment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_build_output_cursor_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "deployment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_deployment_event_cursor_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_saved_state_snapshot_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_saved_state_snapshot_environment_created_at_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_config_snapshot_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_config_snapshot_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "node_type", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "node_lineage_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_config_snapshot_lineage_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_deployment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_config_snapshot_deployment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "node_type", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "node_lineage_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_introduction_lineage_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "environment_node_introduction_organization_idx", + "entityType": "indexes", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_project_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" in ('pending', 'running')\n and \"scope\" = 'environment'\n and \"environment_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_one_active_environment_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "project_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" in ('pending', 'running')\n and \"scope\" = 'project'\n and \"project_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_one_active_project_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" in ('pending', 'running')\n and \"scope\" = 'organization'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_one_active_organization_idx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "inngest_run_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"inngest_run_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "teardown_attempt_inngest_run_uidx", + "entityType": "indexes", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_environment_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_deployment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_deployment_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_resource_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "retry_of_attempt_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"retry_of_attempt_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_retry_of_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"status\" in ('awaiting_deployment', 'pending', 'running')\n and \"environment_resource_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_one_active_resource_idx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "inngest_run_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"inngest_run_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "volume_remove_attempt_inngest_run_uidx", + "entityType": "indexes", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "token_hash", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "machine_enrollment_token_hash_idx", + "entityType": "indexes", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "machine_enrollment_token_organization_idx", + "entityType": "indexes", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "inngest_run_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"inngest_run_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "machine_remove_attempt_inngest_run_uidx", + "entityType": "indexes", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "machine_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"state\" in ('pending', 'running')", + "with": "", + "method": "btree", + "concurrently": false, + "name": "machine_remove_attempt_one_active_org_machine_idx", + "entityType": "indexes", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "machine_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "organization_machine_machine_idx", + "entityType": "indexes", + "schema": "public", + "table": "organization_machine" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"is_dial_entry\"", + "with": "", + "method": "btree", + "concurrently": false, + "name": "organization_machine_one_dial_entry_idx", + "entityType": "indexes", + "schema": "public", + "table": "organization_machine" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "installation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "repository_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "evaluated_head_sha", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_branch_projection_head_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_branch_projection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "installation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "repository_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "head_sha", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_check_suite_projection_head_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"published_revision\" < \"transition_revision\"", + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_check_suite_projection_unpublished_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "environment_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_environment_trigger_environment_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"publish_state\" = 'pending'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_environment_trigger_pending_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_installation_user_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "installation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_installation_installation_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "installation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_repository_cache_installation_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_repository_cache" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_repository_cache_user_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_repository_cache" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "full_name", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_repository_cache_full_name_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_repository_cache" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "processing_state", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "receipt_sequence", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_webhook_delivery_processing_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "installation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "repository_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_webhook_delivery_identity_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "processing_run_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"processing_run_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_webhook_delivery_processing_run_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": [ + "inviter_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_inviter_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "session_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id", + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "organization_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_IqLeTQthFKCX_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "project_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "project" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "user_project_preference_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "user_project_preference_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "user_project_preference_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "user_project_preference_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_canvas_node_position_4ir4xbHMhQ0b_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_canvas_node_position_DP4bUoilqg6D_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_resource_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_resource_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_resource_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "lineage_id" + ], + "schemaTo": "public", + "tableTo": "resource_lineage", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "environment_resource_lineage_id_resource_lineage_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "project_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_resource_krkfQwOLhWDI_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "lineage_id" + ], + "schemaTo": "public", + "tableTo": "resource_lineage", + "columnsTo": [ + "project_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "environment_resource_zQ2aoOGRLIOR_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "resource_lineage_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "resource_lineage_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "lineage_id" + ], + "schemaTo": "public", + "tableTo": "service_lineage", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "service_lineage_id_service_lineage_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "project_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_bvUAv6STak07_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "lineage_id" + ], + "schemaTo": "public", + "tableTo": "service_lineage", + "columnsTo": [ + "project_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "service_1xRYD1MXFhcT_fkey", + "entityType": "fks", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_lineage_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "project_id" + ], + "schemaTo": "public", + "tableTo": "project", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_lineage_project_id_project_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_registry_credential_fC7nGiZZPNsV_fkey", + "entityType": "fks", + "schema": "public", + "table": "service_registry_credential" + }, + { + "nameExplicit": false, + "columns": [ + "service_id" + ], + "schemaTo": "public", + "tableTo": "service", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "service_registry_credential_service_id_service_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "service_registry_credential" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable" + }, + { + "nameExplicit": false, + "columns": [ + "service_id" + ], + "schemaTo": "public", + "tableTo": "service", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_service_id_service_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "service_id" + ], + "schemaTo": "public", + "tableTo": "service", + "columnsTo": [ + "environment_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_dFGv8UXjv6eg_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_secret_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable_secret" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_secret_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable_secret" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "variable_id" + ], + "schemaTo": "public", + "tableTo": "variable", + "columnsTo": [ + "environment_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "variable_secret_fgbg4UfEzo6H_fkey", + "entityType": "fks", + "schema": "public", + "table": "variable_secret" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": false, + "columns": [ + "retry_of_deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "name": "environment_deployment_Lofdv4M9OTIQ_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "saved_state_snapshot_id" + ], + "schemaTo": "public", + "tableTo": "environment_saved_state_snapshot", + "columnsTo": [ + "environment_id", + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "environment_deployment_92k6WdAbc3AZ_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_build_output_es7jBaLp3vH8_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "nameExplicit": false, + "columns": [ + "deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_build_output_Xp68IrJouNSa_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "nameExplicit": false, + "columns": [ + "step_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment_build_step", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_build_output_XF27nu5BhEx1_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_build_output" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_build_step_28D6Rkzs1URj_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "nameExplicit": false, + "columns": [ + "deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_build_step_mAOz3YRgkCxT_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_event_eW8RHtn0mFyI_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "nameExplicit": false, + "columns": [ + "deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_event_nkhfxU66kCFO_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_event" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_image_build_omhRa2gD2UgI_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "nameExplicit": false, + "columns": [ + "deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_image_build_Ss4XYtuD2fFu_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_secret_IuNsdKp3NB8E_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_secret" + }, + { + "nameExplicit": false, + "columns": [ + "environment_deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_deployment_secret_IIXCU5ibjYPq_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_deployment_secret" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_saved_state_snapshot_QseWcaivJkoo_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_saved_state_snapshot_pYS3zmT4RKuQ_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "actor_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "environment_saved_state_snapshot_actor_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "organization_build_order_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "organization_build_order" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "core_operation_event_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "core_operation_event" + }, + { + "nameExplicit": false, + "columns": [ + "watch_id" + ], + "schemaTo": "public", + "tableTo": "core_operation_watch", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "core_operation_event_watch_id_core_operation_watch_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "core_operation_event" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "core_operation_watch_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "core_operation_watch" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_config_snapshot_3y0HYOFWmCwQ_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "environment_deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_config_snapshot_CUaPaujMBOIs_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_config_snapshot_D4DPm1gvv2Di_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_config_snapshot_secret_jZo1GvXOHIs5_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "nameExplicit": false, + "columns": [ + "snapshot_id" + ], + "schemaTo": "public", + "tableTo": "environment_node_config_snapshot", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_config_snapshot_secret_j5H7VPFuELrf_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_introduction_aSA9HOqVYGRT_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_introduction_YPW21fX4uIUZ_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_introduction_secret_HaNAhrDo0dtU_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "node_type", + "node_id" + ], + "schemaTo": "public", + "tableTo": "environment_node_introduction", + "columnsTo": [ + "environment_id", + "node_type", + "node_id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "environment_node_introduction_secret_sC7ALWFOnE38_fkey", + "entityType": "fks", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "organization_pairing_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "organization_pairing" + }, + { + "nameExplicit": false, + "columns": [ + "requested_by_user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "teardown_attempt_requested_by_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "volume_remove_attempt_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "requested_by_user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "volume_remove_attempt_requested_by_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "volume_remove_attempt_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "environment_deployment_id" + ], + "schemaTo": "public", + "tableTo": "environment_deployment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "volume_remove_attempt_2ncjupSSetid_fkey", + "entityType": "fks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "retry_of_attempt_id" + ], + "schemaTo": "public", + "tableTo": "volume_remove_attempt", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "volume_remove_attempt_FQapB8QhQW1M_fkey", + "entityType": "fks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "enrollment_allocation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "machine_enrollment_token_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "nameExplicit": false, + "columns": [ + "created_by_user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "machine_enrollment_token_created_by_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "machine_remove_attempt_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "requested_by_user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "machine_remove_attempt_requested_by_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "organization_machine_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "organization_machine" + }, + { + "nameExplicit": false, + "columns": [ + "last_delivery_id", + "last_receipt_sequence" + ], + "schemaTo": "public", + "tableTo": "github_webhook_delivery", + "columnsTo": [ + "delivery_id", + "receipt_sequence" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "github_branch_projection_Udo5xaDQmVxR_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "nameExplicit": false, + "columns": [ + "last_delivery_id", + "last_receipt_sequence" + ], + "schemaTo": "public", + "tableTo": "github_webhook_delivery", + "columnsTo": [ + "delivery_id", + "receipt_sequence" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "github_check_suite_projection_9FLSHaRf6WgI_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_environment_trigger_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id" + ], + "schemaTo": "public", + "tableTo": "environment", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_environment_trigger_environment_id_environment_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": false, + "columns": [ + "source_delivery_id", + "source_receipt_sequence" + ], + "schemaTo": "public", + "tableTo": "github_webhook_delivery", + "columnsTo": [ + "delivery_id", + "receipt_sequence" + ], + "onUpdate": "NO ACTION", + "onDelete": "RESTRICT", + "name": "github_environment_trigger_dspFptTlur3h_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_installation_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": false, + "columns": [ + "user_id" + ], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_repository_cache_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_repository_cache" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "organization_billing_state_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "organization_billing_state" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id" + ], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "organization_cluster_domain_eJqKfNjJBhUj_fkey", + "entityType": "fks", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "columns": [ + "environment_id", + "node_type", + "node_id" + ], + "nameExplicit": false, + "name": "environment_node_introduction_pkey", + "entityType": "pks", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "columns": [ + "environment_id", + "node_type", + "node_id" + ], + "nameExplicit": false, + "name": "environment_node_introduction_secret_pkey", + "entityType": "pks", + "schema": "public", + "table": "environment_node_introduction_secret" + }, + { + "columns": [ + "organization_id", + "cluster_key" + ], + "nameExplicit": false, + "name": "enrollment_allocation_pkey", + "entityType": "pks", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "columns": [ + "organization_id", + "machine_id" + ], + "nameExplicit": false, + "name": "organization_machine_pkey", + "entityType": "pks", + "schema": "public", + "table": "organization_machine" + }, + { + "columns": [ + "installation_id", + "repository_id", + "ref" + ], + "nameExplicit": false, + "name": "github_branch_projection_pkey", + "entityType": "pks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "columns": [ + "installation_id", + "repository_id", + "check_suite_id" + ], + "nameExplicit": false, + "name": "github_check_suite_projection_pkey", + "entityType": "pks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "columns": [ + "user_id", + "installation_id", + "repository_id" + ], + "nameExplicit": false, + "name": "github_repository_cache_pkey", + "entityType": "pks", + "schema": "public", + "table": "github_repository_cache" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "organization_pkey", + "schema": "public", + "table": "organization", + "entityType": "pks" + }, + { + "columns": [ + "seq" + ], + "nameExplicit": false, + "name": "organization_change_pkey", + "schema": "public", + "table": "organization_change", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "account_pkey", + "schema": "public", + "table": "account", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "invitation_pkey", + "schema": "public", + "table": "invitation", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "member_pkey", + "schema": "public", + "table": "member", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "session_pkey", + "schema": "public", + "table": "session", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_pkey", + "schema": "public", + "table": "user", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "verification_pkey", + "schema": "public", + "table": "verification", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_pkey", + "schema": "public", + "table": "environment", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "project_pkey", + "schema": "public", + "table": "project", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "user_project_preference_pkey", + "schema": "public", + "table": "user_project_preference", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_canvas_node_position_pkey", + "schema": "public", + "table": "environment_canvas_node_position", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_resource_pkey", + "schema": "public", + "table": "environment_resource", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "resource_lineage_pkey", + "schema": "public", + "table": "resource_lineage", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "service_pkey", + "schema": "public", + "table": "service", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "service_lineage_pkey", + "schema": "public", + "table": "service_lineage", + "entityType": "pks" + }, + { + "columns": [ + "service_id" + ], + "nameExplicit": false, + "name": "service_registry_credential_pkey", + "schema": "public", + "table": "service_registry_credential", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "variable_pkey", + "schema": "public", + "table": "variable", + "entityType": "pks" + }, + { + "columns": [ + "variable_id" + ], + "nameExplicit": false, + "name": "variable_secret_pkey", + "schema": "public", + "table": "variable_secret", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_deployment_pkey", + "schema": "public", + "table": "environment_deployment", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_deployment_build_output_pkey", + "schema": "public", + "table": "environment_deployment_build_output", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_deployment_build_step_pkey", + "schema": "public", + "table": "environment_deployment_build_step", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_deployment_event_pkey", + "schema": "public", + "table": "environment_deployment_event", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_deployment_image_build_pkey", + "schema": "public", + "table": "environment_deployment_image_build", + "entityType": "pks" + }, + { + "columns": [ + "environment_deployment_id" + ], + "nameExplicit": false, + "name": "environment_deployment_secret_pkey", + "schema": "public", + "table": "environment_deployment_secret", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_saved_state_snapshot_pkey", + "schema": "public", + "table": "environment_saved_state_snapshot", + "entityType": "pks" + }, + { + "columns": [ + "organization_id" + ], + "nameExplicit": false, + "name": "organization_build_order_pkey", + "schema": "public", + "table": "organization_build_order", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "core_operation_event_pkey", + "schema": "public", + "table": "core_operation_event", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "core_operation_watch_pkey", + "schema": "public", + "table": "core_operation_watch", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "environment_node_config_snapshot_pkey", + "schema": "public", + "table": "environment_node_config_snapshot", + "entityType": "pks" + }, + { + "columns": [ + "snapshot_id" + ], + "nameExplicit": false, + "name": "environment_node_config_snapshot_secret_pkey", + "schema": "public", + "table": "environment_node_config_snapshot_secret", + "entityType": "pks" + }, + { + "columns": [ + "organization_id" + ], + "nameExplicit": false, + "name": "organization_pairing_pkey", + "schema": "public", + "table": "organization_pairing", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "teardown_attempt_pkey", + "schema": "public", + "table": "teardown_attempt", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "volume_remove_attempt_pkey", + "schema": "public", + "table": "volume_remove_attempt", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "machine_enrollment_token_pkey", + "schema": "public", + "table": "machine_enrollment_token", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "machine_remove_attempt_pkey", + "schema": "public", + "table": "machine_remove_attempt", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "github_environment_trigger_pkey", + "schema": "public", + "table": "github_environment_trigger", + "entityType": "pks" + }, + { + "columns": [ + "id" + ], + "nameExplicit": false, + "name": "github_installation_pkey", + "schema": "public", + "table": "github_installation", + "entityType": "pks" + }, + { + "columns": [ + "delivery_id" + ], + "nameExplicit": false, + "name": "github_webhook_delivery_pkey", + "schema": "public", + "table": "github_webhook_delivery", + "entityType": "pks" + }, + { + "columns": [ + "organization_id" + ], + "nameExplicit": false, + "name": "organization_billing_state_pkey", + "schema": "public", + "table": "organization_billing_state", + "entityType": "pks" + }, + { + "columns": [ + "organization_id" + ], + "nameExplicit": false, + "name": "organization_cluster_domain_pkey", + "schema": "public", + "table": "organization_cluster_domain", + "entityType": "pks" + }, + { + "nameExplicit": false, + "columns": [ + "slug" + ], + "nullsNotDistinct": false, + "name": "organization_slug_unique", + "entityType": "uniques", + "schema": "public", + "table": "organization" + }, + { + "nameExplicit": false, + "columns": [ + "user_id", + "organization_id" + ], + "nullsNotDistinct": false, + "name": "member_user_id_organization_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": [ + "token" + ], + "nullsNotDistinct": false, + "name": "session_token_unique", + "entityType": "uniques", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": false, + "columns": [ + "email" + ], + "nullsNotDistinct": false, + "name": "user_email_unique", + "entityType": "uniques", + "schema": "public", + "table": "user" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "name" + ], + "nullsNotDistinct": false, + "name": "environment_project_id_name_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "id" + ], + "nullsNotDistinct": false, + "name": "environment_project_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id", + "namespace" + ], + "nullsNotDistinct": false, + "name": "environment_organization_id_namespace_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id", + "slug" + ], + "nullsNotDistinct": false, + "name": "project_organization_id_slug_unique", + "entityType": "uniques", + "schema": "public", + "table": "project" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id", + "id" + ], + "nullsNotDistinct": false, + "name": "project_organization_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "project" + }, + { + "nameExplicit": false, + "columns": [ + "user_id", + "project_id" + ], + "nullsNotDistinct": false, + "name": "user_project_preference_user_id_project_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "user_project_preference" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "resource_type", + "resource_id" + ], + "nullsNotDistinct": false, + "name": "environment_canvas_node_position_environment_id_resource_type_resource_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_canvas_node_position" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "id" + ], + "nullsNotDistinct": false, + "name": "environment_resource_project_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "id" + ], + "nullsNotDistinct": false, + "name": "environment_resource_environment_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "lineage_id" + ], + "nullsNotDistinct": false, + "name": "environment_resource_environment_id_lineage_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_resource" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "canonical_slug" + ], + "nullsNotDistinct": false, + "name": "resource_lineage_project_id_canonical_slug_unique", + "entityType": "uniques", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "id" + ], + "nullsNotDistinct": false, + "name": "resource_lineage_project_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "resource_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "id" + ], + "nullsNotDistinct": false, + "name": "service_project_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "id" + ], + "nullsNotDistinct": false, + "name": "service_environment_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "lineage_id" + ], + "nullsNotDistinct": false, + "name": "service_environment_id_lineage_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "service" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "canonical_slug" + ], + "nullsNotDistinct": false, + "name": "service_lineage_project_id_canonical_slug_unique", + "entityType": "uniques", + "schema": "public", + "table": "service_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "project_id", + "id" + ], + "nullsNotDistinct": false, + "name": "service_lineage_project_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "service_lineage" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "id" + ], + "nullsNotDistinct": false, + "name": "variable_environment_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "variable" + }, + { + "nameExplicit": true, + "columns": [ + "deployment_id", + "image", + "attempt", + "build", + "key" + ], + "nullsNotDistinct": true, + "name": "environment_deployment_build_step_key_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_deployment_build_step" + }, + { + "nameExplicit": true, + "columns": [ + "deployment_id", + "service_id" + ], + "nullsNotDistinct": false, + "name": "environment_deployment_image_build_service_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "nameExplicit": false, + "columns": [ + "environment_id", + "id" + ], + "nullsNotDistinct": false, + "name": "environment_saved_state_snapshot_environment_id_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_saved_state_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "watch_id", + "sequence" + ], + "nullsNotDistinct": false, + "name": "core_operation_event_watch_id_sequence_unique", + "entityType": "uniques", + "schema": "public", + "table": "core_operation_event" + }, + { + "nameExplicit": false, + "columns": [ + "organization_id", + "operation_id" + ], + "nullsNotDistinct": false, + "name": "core_operation_watch_organization_id_operation_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "core_operation_watch" + }, + { + "nameExplicit": false, + "columns": [ + "environment_deployment_id", + "node_type", + "node_id" + ], + "nullsNotDistinct": false, + "name": "environment_node_config_snapshot_environment_deployment_id_node_type_node_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "nameExplicit": false, + "columns": [ + "installation_id", + "repository_id", + "ref", + "branch_evaluation_revision", + "environment_id" + ], + "nullsNotDistinct": false, + "name": "github_environment_trigger_installation_id_repository_id_ref_branch_evaluation_revision_environment_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "nameExplicit": false, + "columns": [ + "user_id", + "installation_id" + ], + "nullsNotDistinct": false, + "name": "github_installation_user_id_installation_id_unique", + "entityType": "uniques", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": false, + "columns": [ + "delivery_id", + "receipt_sequence" + ], + "nullsNotDistinct": false, + "name": "github_webhook_delivery_delivery_id_receipt_sequence_unique", + "entityType": "uniques", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "nameExplicit": false, + "columns": [ + "receipt_sequence" + ], + "nullsNotDistinct": false, + "name": "github_webhook_delivery_receipt_sequence_key", + "schema": "public", + "table": "github_webhook_delivery", + "entityType": "uniques" + }, + { + "value": "\"implementation_type\" in ('volume')", + "name": "environment_resource_implementation_type_check", + "entityType": "checks", + "schema": "public", + "table": "environment_resource" + }, + { + "value": "num_nonnulls(\"encrypted_registry_username\", \"encrypted_registry_secret\") > 0", + "name": "service_registry_credential_nonempty_check", + "entityType": "checks", + "schema": "public", + "table": "service_registry_credential" + }, + { + "value": "(\n (\"status\" = 'cancelled' and \"cancellation_requested_at\" is not null and \"finished_at\" is not null)\n or (\"status\" <> 'cancelled')\n )", + "name": "environment_deployment_cancellation_shape_check", + "entityType": "checks", + "schema": "public", + "table": "environment_deployment" + }, + { + "value": "(\"status\" = 'built') = (\"encrypted_receipt\" is not null)", + "name": "environment_deployment_image_build_receipt_check", + "entityType": "checks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "value": "\"builder\" in ('server', 'github')", + "name": "environment_deployment_image_build_builder_check", + "entityType": "checks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "value": "(\"builder\" = 'github') = (\"github\" is not null and \"github_run_id\" is not null)", + "name": "environment_deployment_image_build_github_check", + "entityType": "checks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "value": "\"checked_in_at\" is null or \"builder\" = 'github'", + "name": "environment_deployment_image_build_check_in_check", + "entityType": "checks", + "schema": "public", + "table": "environment_deployment_image_build" + }, + { + "value": "\"build_order\" in ('servers-only', 'github-then-servers', 'servers-then-github', 'github-only')", + "name": "organization_build_order_check", + "entityType": "checks", + "schema": "public", + "table": "organization_build_order" + }, + { + "value": "\"expected_kind\" in ('deploy','cert','machine_add','machine_update','machine_lifecycle','core_replace','credential_grant','network_repair','service_restart','managed_dns_reconcile','ingress_configure','ingress_refresh','namespace_remove','volume_create','volume_remove')", + "name": "core_operation_watch_expected_kind_check", + "entityType": "checks", + "schema": "public", + "table": "core_operation_watch" + }, + { + "value": "\"cursor_state\" in ('more','caught_up','terminal')", + "name": "core_operation_watch_cursor_state_check", + "entityType": "checks", + "schema": "public", + "table": "core_operation_watch" + }, + { + "value": "\"observation_state\" in ('active','core_terminal','cloud_timeout','cloud_cancelled')", + "name": "core_operation_watch_observation_state_check", + "entityType": "checks", + "schema": "public", + "table": "core_operation_watch" + }, + { + "value": "\"node_type\" in ('service', 'volume')", + "name": "environment_node_config_snapshot_node_type_check", + "entityType": "checks", + "schema": "public", + "table": "environment_node_config_snapshot" + }, + { + "value": "num_nonnulls(\"encrypted_registry_username\", \"encrypted_registry_secret\") > 0", + "name": "environment_node_config_snapshot_secret_nonempty_check", + "entityType": "checks", + "schema": "public", + "table": "environment_node_config_snapshot_secret" + }, + { + "value": "\"node_type\" in ('service', 'volume')", + "name": "environment_node_introduction_node_type_check", + "entityType": "checks", + "schema": "public", + "table": "environment_node_introduction" + }, + { + "value": "\n (\"removal_started_at\" is null and \"removal_endpoints\" is null)\n or (\"removal_started_at\" is not null and \"removal_endpoints\" is not null and jsonb_typeof(\"removal_endpoints\") = 'array')\n ", + "name": "organization_pairing_removal_shape_check", + "entityType": "checks", + "schema": "public", + "table": "organization_pairing" + }, + { + "value": "\"founder_public_key\" is not null or \"founder_machine_id\" is not null", + "name": "organization_pairing_state_check", + "entityType": "checks", + "schema": "public", + "table": "organization_pairing" + }, + { + "value": "\"founder_claim_machine_id\" ~ '^[0-9a-f]{32}$'", + "name": "organization_pairing_founder_claim_machine_id_check", + "entityType": "checks", + "schema": "public", + "table": "organization_pairing" + }, + { + "value": "\"founder_machine_id\" is null or \"founder_machine_id\" ~ '^[0-9a-f]{32}$'", + "name": "organization_pairing_founder_machine_id_check", + "entityType": "checks", + "schema": "public", + "table": "organization_pairing" + }, + { + "value": "\"scope\" in ('environment','project','organization')", + "name": "teardown_attempt_scope_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "\"status\" in ('pending','running','completed','partial','failed','cancelled')", + "name": "teardown_attempt_status_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "(\n (\"scope\" = 'environment' and \"environment_id\" is not null\n and \"project_id\" is not null)\n or (\"scope\" = 'project' and \"project_id\" is not null\n and \"environment_id\" is null)\n or (\"scope\" = 'organization' and \"project_id\" is null\n and \"environment_id\" is null)\n )", + "name": "teardown_attempt_scope_ids_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "jsonb_typeof(\"confirm_data_loss\") = 'array'", + "name": "teardown_attempt_confirm_data_loss_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "jsonb_typeof(\"targets\") = 'object'", + "name": "teardown_attempt_targets_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "(\n (\"status\" = 'pending' and \"inngest_run_id\" is null\n and \"started_at\" is null and \"terminal_at\" is null\n and \"outcome\" is null and \"failure_message\" is null)\n or (\"status\" = 'running' and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is null\n and \"failure_message\" is null)\n or (\"status\" = 'completed' and \"inngest_run_id\" is not null\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"outcome\" is not null and \"failure_message\" is null)\n or (\"status\" = 'partial' and \"inngest_run_id\" is not null\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"outcome\" is not null)\n or (\"status\" in ('failed', 'cancelled')\n and \"inngest_run_id\" is not null\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"failure_message\" is not null\n and length(\"failure_message\") between 1 and 2000)\n )", + "name": "teardown_attempt_status_shape_check", + "entityType": "checks", + "schema": "public", + "table": "teardown_attempt" + }, + { + "value": "\"status\" in ('awaiting_deployment','pending','running','unknown','completed','partial','failed','cancelled')", + "name": "volume_remove_attempt_status_check", + "entityType": "checks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "value": "jsonb_typeof(\"volumes\") = 'array'\n and jsonb_array_length(\"volumes\") >= 1", + "name": "volume_remove_attempt_volumes_check", + "entityType": "checks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "value": "(\n (\"status\" = 'awaiting_deployment'\n and \"environment_deployment_id\" is not null\n and \"inngest_run_id\" is null\n and \"started_at\" is null and \"terminal_at\" is null\n and \"outcome\" is null and \"failure_message\" is null)\n or (\"status\" = 'pending' and \"inngest_run_id\" is null\n and \"started_at\" is null and \"terminal_at\" is null\n and \"outcome\" is null and \"failure_message\" is null)\n or (\"status\" = 'running' and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"terminal_at\" is null\n and \"outcome\" is null and \"failure_message\" is null)\n or (\"status\" = 'unknown' and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"outcome\" is null and \"failure_message\" is not null\n and length(\"failure_message\") between 1 and 2000)\n or (\"status\" = 'completed' and \"inngest_run_id\" is not null\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"outcome\" is not null and \"failure_message\" is null)\n or (\"status\" = 'partial' and \"inngest_run_id\" is not null\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"outcome\" is not null)\n or (\"status\" in ('failed', 'cancelled')\n and \"started_at\" is null and \"terminal_at\" is not null\n and \"outcome\" is null and \"failure_message\" is not null\n and length(\"failure_message\") between 1 and 2000\n and (\n (\"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255)\n or (\"inngest_run_id\" is null\n and \"environment_deployment_id\" is not null)\n ))\n )", + "name": "volume_remove_attempt_status_shape_check", + "entityType": "checks", + "schema": "public", + "table": "volume_remove_attempt" + }, + { + "value": "\"cluster_key\" ~ '^[0-9a-f]{64}$'", + "name": "enrollment_allocation_cluster_key_check", + "entityType": "checks", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "value": "jsonb_typeof(\"assignments\") = 'array'", + "name": "enrollment_allocation_assignments_check", + "entityType": "checks", + "schema": "public", + "table": "enrollment_allocation" + }, + { + "value": "\"token_hash\" ~ '^[0-9a-f]{64}$'", + "name": "machine_enrollment_token_hash_check", + "entityType": "checks", + "schema": "public", + "table": "machine_enrollment_token" + }, + { + "value": "length(\"machine_id\") between 1 and 64 and \"machine_id\" !~ '[[:cntrl:]]'", + "name": "machine_remove_attempt_machine_id_check", + "entityType": "checks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "value": "jsonb_typeof(\"confirm_data_loss\") = 'array'", + "name": "machine_remove_attempt_confirm_data_loss_check", + "entityType": "checks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "value": "\"state\" in ('pending','running','succeeded','failed','cancelled','missing_identities')", + "name": "machine_remove_attempt_state_check", + "entityType": "checks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "value": "(\n (\"state\" = 'pending' and \"inngest_run_id\" is null\n and \"started_at\" is null and \"terminal_at\" is null\n and \"failure_code\" is null and \"failure_message\" is null\n and \"missing_identities\" is null)\n or (\"state\" = 'running' and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is null\n and \"failure_code\" is null and \"failure_message\" is null\n and \"missing_identities\" is null)\n or (\"state\" = 'succeeded' and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"failure_code\" is null and \"failure_message\" is null\n and \"missing_identities\" is null)\n or (\"state\" in ('failed','cancelled')\n and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"failure_code\" is not null and \"failure_message\" is not null\n and \"failure_code\" ~ '^[a-z][a-z0-9_]{0,63}$'\n and length(\"failure_message\") between 1 and 1024\n and \"missing_identities\" is null)\n or (\"state\" = 'missing_identities'\n and \"inngest_run_id\" is not null\n and length(\"inngest_run_id\") between 1 and 255\n and \"started_at\" is not null and \"terminal_at\" is not null\n and \"failure_code\" is null and \"failure_message\" is null\n and jsonb_typeof(\"missing_identities\") = 'array'\n and jsonb_array_length(\"missing_identities\") > 0)\n )", + "name": "machine_remove_attempt_state_shape_check", + "entityType": "checks", + "schema": "public", + "table": "machine_remove_attempt" + }, + { + "value": "\"cluster_key\" ~ '^[0-9a-f]{64}$'", + "name": "organization_machine_cluster_key_check", + "entityType": "checks", + "schema": "public", + "table": "organization_machine" + }, + { + "value": "\"machine_id\" ~ '^[0-9a-f]{32}$'", + "name": "organization_machine_id_format_check", + "entityType": "checks", + "schema": "public", + "table": "organization_machine" + }, + { + "value": "\"installation_id\" > 0 and \"repository_id\" > 0 and \"last_receipt_sequence\" > 0 and \"evaluation_revision\" > 0", + "name": "github_branch_projection_identity_check", + "entityType": "checks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "value": "\"ref\" like 'refs/heads/%' and length(\"ref\") > length('refs/heads/')", + "name": "github_branch_projection_ref_check", + "entityType": "checks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "value": "\"state\" in ('active','deleted')", + "name": "github_branch_projection_state_check", + "entityType": "checks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "value": "\"evaluation_reason\" in ('first_observation','changed_paths','rebaseline_all_services','branch_deleted')", + "name": "github_branch_projection_evaluation_reason_check", + "entityType": "checks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "value": "(\n (\"state\" = 'active' and \"evaluated_head_sha\" ~ '^[0-9a-f]{40}$' and \"evaluation_reason\" != 'branch_deleted')\n or (\"state\" = 'deleted' and \"evaluated_head_sha\" is null and \"evaluation_reason\" = 'branch_deleted')\n )", + "name": "github_branch_projection_head_check", + "entityType": "checks", + "schema": "public", + "table": "github_branch_projection" + }, + { + "value": "\"installation_id\" > 0 and \"repository_id\" > 0 and \"check_suite_id\" > 0 and \"last_receipt_sequence\" > 0", + "name": "github_check_suite_projection_identity_check", + "entityType": "checks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "value": "\"head_sha\" ~ '^[0-9a-f]{40}$'", + "name": "github_check_suite_projection_head_sha_check", + "entityType": "checks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "value": "\"status\" in ('queued','in_progress','completed','pending','waiting','requested')", + "name": "github_check_suite_projection_status_check", + "entityType": "checks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "value": "\"conclusion\" is null or \"conclusion\" in ('action_required','cancelled','failure','neutral','success','skipped','stale','timed_out','startup_failure')", + "name": "github_check_suite_projection_conclusion_check", + "entityType": "checks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "value": "\"transition_revision\" >= 1 and \"published_revision\" >= 0 and \"published_revision\" <= \"transition_revision\"", + "name": "github_check_suite_projection_revision_check", + "entityType": "checks", + "schema": "public", + "table": "github_check_suite_projection" + }, + { + "value": "\"installation_id\" > 0 and \"repository_id\" > 0 and \"source_receipt_sequence\" > 0 and \"branch_evaluation_revision\" > 0", + "name": "github_environment_trigger_identity_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "\"ref\" like 'refs/heads/%' and length(\"ref\") > length('refs/heads/')", + "name": "github_environment_trigger_ref_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "\"head_sha\" ~ '^[0-9a-f]{40}$'", + "name": "github_environment_trigger_head_sha_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "cardinality(\"service_ids\") > 0 and array_position(\"service_ids\", null) is null", + "name": "github_environment_trigger_service_ids_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "\"selection_mode\" in ('paths','all_services')", + "name": "github_environment_trigger_selection_mode_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "\"reason\" in ('first_observation','changed_paths','force_rebaseline','non_ancestor_rebaseline','changed_paths_incomplete_rebaseline')", + "name": "github_environment_trigger_reason_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "(\n (\"selection_mode\" = 'paths' and \"reason\" = 'changed_paths')\n or (\"selection_mode\" = 'all_services' and \"reason\" in ('first_observation','force_rebaseline','non_ancestor_rebaseline','changed_paths_incomplete_rebaseline'))\n )", + "name": "github_environment_trigger_selection_reason_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "\"trigger_revision\" = \"branch_evaluation_revision\" and \"published_revision\" >= 0 and \"published_revision\" <= \"trigger_revision\"", + "name": "github_environment_trigger_publish_revision_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "(\n (\"publish_state\" = 'pending' and \"published_revision\" < \"trigger_revision\" and \"published_at\" is null)\n or (\"publish_state\" = 'published' and \"published_revision\" = \"trigger_revision\" and \"published_at\" is not null)\n )", + "name": "github_environment_trigger_publish_state_check", + "entityType": "checks", + "schema": "public", + "table": "github_environment_trigger" + }, + { + "value": "length(trim(\"delivery_id\")) > 0 and \"receipt_sequence\" > 0 and (\"installation_id\" is null or \"installation_id\" > 0) and (\"repository_id\" is null or \"repository_id\" > 0) and (\"check_suite_id\" is null or \"check_suite_id\" > 0)", + "name": "github_webhook_delivery_identity_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"event_kind\" in ('push','check_suite')", + "name": "github_webhook_delivery_event_kind_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"processing_state\" in ('received','processing','processed','rejected','failed','cancelled')", + "name": "github_webhook_delivery_processing_state_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"outcome\" is null or \"outcome\" in ('branch_projected','branch_deleted','branch_rebased_all_services','check_suite_projected','check_suite_unchanged','ignored_stale','ignored_unconfigured_repository','ignored_no_matching_service','malformed','identity_unresolved','unsupported_action','processing_failed','cancelled')", + "name": "github_webhook_delivery_outcome_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"branch_state\" is null or \"branch_state\" in ('active','deleted')", + "name": "github_webhook_delivery_branch_state_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"failure_code\" is null or \"failure_code\" in ('malformed_payload','identity_unresolved','unsupported_action','observation_failed','persistence_failed','publication_failed','retry_exhausted','unexpected_error','inngest_cancelled')", + "name": "github_webhook_delivery_failure_code_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"check_suite_action\" is null or \"check_suite_action\" in ('requested','rerequested','completed')", + "name": "github_webhook_delivery_check_suite_action_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"check_suite_status\" is null or \"check_suite_status\" in ('queued','in_progress','completed','pending','waiting','requested')", + "name": "github_webhook_delivery_check_suite_status_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"check_suite_conclusion\" is null or \"check_suite_conclusion\" in ('action_required','cancelled','failure','neutral','success','skipped','stale','timed_out','startup_failure')", + "name": "github_webhook_delivery_check_suite_conclusion_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "\"head_sha\" is null or \"head_sha\" ~ '^[0-9a-f]{40}$'", + "name": "github_webhook_delivery_head_sha_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "(\n (\"processing_state\" = 'received' and \"processing_run_id\" is null and \"processing_started_at\" is null and \"outcome\" is null and \"failure_code\" is null and \"processed_at\" is null)\n or\n (\"processing_state\" = 'processing' and \"processing_run_id\" is not null and \"processing_started_at\" is not null and \"outcome\" is null and \"failure_code\" is null and \"processed_at\" is null)\n or\n (\"processing_state\" = 'processed' and \"processing_run_id\" is not null and \"processing_started_at\" is not null and \"outcome\" in ('branch_projected','branch_deleted','branch_rebased_all_services','check_suite_projected','check_suite_unchanged','ignored_stale','ignored_unconfigured_repository','ignored_no_matching_service') and \"failure_code\" is null and \"processed_at\" is not null)\n or\n (\"processing_state\" = 'rejected' and (\n (\"outcome\" = 'malformed' and \"failure_code\" = 'malformed_payload')\n or (\"outcome\" = 'identity_unresolved' and \"failure_code\" = 'identity_unresolved')\n or (\"outcome\" = 'unsupported_action' and \"failure_code\" = 'unsupported_action')\n ) and \"processing_run_id\" is null and \"processing_started_at\" is null and \"processed_at\" is not null)\n or\n (\"processing_state\" = 'failed' and \"processing_run_id\" is not null and \"processing_started_at\" is not null and \"outcome\" = 'processing_failed' and \"failure_code\" in ('observation_failed','persistence_failed','publication_failed','retry_exhausted','unexpected_error') and \"processed_at\" is not null)\n or\n (\"processing_state\" = 'cancelled' and \"processing_run_id\" is not null and \"processing_started_at\" is not null and \"outcome\" = 'cancelled' and \"failure_code\" = 'inngest_cancelled' and \"processed_at\" is not null)\n )", + "name": "github_webhook_delivery_processing_evidence_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "(\n \"processing_state\" not in ('processing','processed','failed','cancelled')\n or (\n \"installation_id\" is not null\n and \"repository_id\" is not null\n and (\n (\n \"event_kind\" = 'push'\n and \"ref\" is not null\n and \"ref\" like 'refs/heads/%'\n and \"branch_state\" is not null\n and \"check_suite_id\" is null\n and \"check_suite_action\" is null\n and \"check_suite_status\" is null\n and \"check_suite_conclusion\" is null\n and (\n (\"branch_state\" = 'active' and \"head_sha\" is not null)\n or (\"branch_state\" = 'deleted' and \"head_sha\" is null)\n )\n )\n or (\n \"event_kind\" = 'check_suite'\n and \"branch_state\" is null\n and \"head_sha\" is not null\n and \"check_suite_id\" is not null\n and \"check_suite_action\" is not null\n and \"check_suite_status\" is not null\n )\n )\n )\n )", + "name": "github_webhook_delivery_processed_summary_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "(\n \"outcome\" not in ('branch_projected','branch_deleted','branch_rebased_all_services','check_suite_projected','check_suite_unchanged')\n or (\"outcome\" in ('branch_projected','branch_deleted','branch_rebased_all_services') and \"event_kind\" = 'push')\n or (\"outcome\" in ('check_suite_projected','check_suite_unchanged') and \"event_kind\" = 'check_suite')\n )", + "name": "github_webhook_delivery_outcome_kind_check", + "entityType": "checks", + "schema": "public", + "table": "github_webhook_delivery" + }, + { + "value": "(\n \"has_active_subscription\" = false\n OR (\n \"active_subscription_id\" IS NOT NULL\n AND \"current_period_end\" IS NOT NULL\n )\n )", + "name": "organization_billing_state_active_fields_check", + "entityType": "checks", + "schema": "public", + "table": "organization_billing_state" + }, + { + "value": "\"traffic\" is null or \"traffic\"->>'kind' in ('no_servers', 'no_public_ip', 'probed')", + "name": "organization_cluster_domain_traffic_check", + "entityType": "checks", + "schema": "public", + "table": "organization_cluster_domain" + }, + { + "value": "num_nulls(\"encrypted_certificate_private_key\", \"certificate_chain\", \"certificate_not_after\") in (0, 3)", + "name": "organization_cluster_domain_certificate_check", + "entityType": "checks", + "schema": "public", + "table": "organization_cluster_domain" + } + ], + "renames": [] +} \ No newline at end of file diff --git a/dashboard/src/components/deployment-logs.test.tsx b/dashboard/src/components/deployment-logs.test.tsx index 69fda2a45b..58c84f7d99 100644 --- a/dashboard/src/components/deployment-logs.test.tsx +++ b/dashboard/src/components/deployment-logs.test.tsx @@ -10,7 +10,7 @@ const deploymentId = "8f79e99b-cd08-4e9c-af96-f3fed313acc5"; const organizationId = "6c0b2f4e-7a1d-4f3e-9b8a-2d5c1e0f9a7b"; const at = (seconds: number) => new Date(Date.UTC(2026, 8, 22, 21, 9, seconds)); const step = (id: number, name: string, extra: Partial = {}): BuildStepRow => ({ - id, organizationId, deploymentId, image: null, build: 1, key: `sha256:${id}`, name, startedAt: at(id), completedAt: null, cached: false, error: null, createdAt: at(id), updatedAt: at(id), ...extra, + id, organizationId, deploymentId, image: null, attempt: 0, build: 1, key: `sha256:${id}`, name, startedAt: at(id), completedAt: null, cached: false, error: null, createdAt: at(id), updatedAt: at(id), ...extra, }); const line = (id: number, stepId: number, text: string, stderr = false): BuildOutputRow => ({ id, organizationId, deploymentId, stepId, stderr, text, createdAt: at(id) }); @@ -93,6 +93,23 @@ it("keeps one Image Build's runs, not other images or the attempt-wide cleanup a expect(imageBuildSteps([step(1, "Uploading source", { build: 0, key: "stage:Upload", error: "upload failed" }), ...steps.slice(1)], "worker").map((row) => row.id)).toEqual([1, 4, 5]); }); +it("tells each Builder's go as a plain line above its steps", () => { + const html = renderToStaticMarkup(createElement(BuildLogs, { timeZone: "UTC", + finished: false, output: [], now: at(9).getTime(), + steps: [ + step(2, "Waiting for a runner", { image: "web", key: "runner", completedAt: at(4) }), + step(6, "Uploading source", { image: "web", attempt: 1, key: "stage:Upload" }), + ], + evidence: { image: "web", serverChoice: { machineName: "hel-1", reason: { kind: "spread" } }, github: null, skips: [{ builder: "github", kind: "not_started", minutes: 3 }] }, + })); + expect(html).toContain("Building on GitHub Actions"); + expect(html).toContain("No GitHub runner started within 3 min. Building on hel-1 instead."); + // Routine choices ("spread") never show; the moved-on run's link is gone with it. + expect(html).not.toContain("spread"); + expect(html).not.toContain("View run"); + expect(html.indexOf("Waiting for a runner")).toBeLessThan(html.indexOf("Building on hel-1")); +}); + it("splits BuildKit step names, rounds durations like Railway, and strips terminal sequences", () => { expect(splitStepName("[sdk 4/6] COPY core/ core/")).toEqual({ stage: "sdk", title: "COPY core/ core/" }); expect(splitStepName("[internal] load build definition from Dockerfile")).toEqual({ stage: "internal", title: "load build definition from Dockerfile" }); diff --git a/dashboard/src/components/deployment-logs.tsx b/dashboard/src/components/deployment-logs.tsx index 89e4b1da4e..b8a5f32463 100644 --- a/dashboard/src/components/deployment-logs.tsx +++ b/dashboard/src/components/deployment-logs.tsx @@ -4,12 +4,11 @@ import { useCollectionScope } from "#/collections/use-collection-scope"; import { getDeploymentLogsCollection, useDeploymentLogsReadState } from "#/modules/deployments/deployment-log.collection"; import { progressRowLabel, type DeploymentProgress } from "#/modules/deployments/deployment-progress"; import { Button } from "#/components/ui/button"; -import { Item, ItemActions, ItemContent, ItemDescription } from "#/components/ui/item"; import { Spinner } from "#/components/ui/spinner"; import { CheckIcon, TriangleAlertIcon } from "lucide-react"; import { useBuildLog, type BuildOutputRow, type BuildStepRow } from "#/modules/deployments/deployment-build-log.queries"; import { BUILDING_KEY, CLEANUP_KEY } from "#/modules/deployments/preparation-progress"; -import { builtOn, builtOnLine, imageBuildSteps, stripAnsi } from "#/modules/deployments/deployment-view"; +import { buildLogSections, imageBuildSteps, stripAnsi, type ImageBuildEvidence } from "#/modules/deployments/deployment-view"; import { ContainerLogs } from "./container-logs"; import type { ContainerLogRow } from "#/modules/runtime/container-log.collection"; import { BuildLogViewer, LOG_TIME_COLUMN, LogEmpty, LogSkeleton } from "./log-scroll"; @@ -44,13 +43,15 @@ const lastLine = (rows: readonly BuildOutputRow[]) => { return lines.at(-1) ?? null; }; -export function BuildLogs({ steps, output, finished, timeZone, now = Date.now() }: { - steps: readonly BuildStepRow[]; output: readonly BuildOutputRow[]; finished: boolean; timeZone: string; now?: number; +/** One Image Build's log: a section per Builder's go, each a plain line and then its steps. */ +export function BuildLogs({ steps, output, finished, evidence, timeZone, now = Date.now() }: { + steps: readonly BuildStepRow[]; output: readonly BuildOutputRow[]; finished: boolean; evidence?: ImageBuildEvidence; timeZone: string; now?: number; }) { // Rows the user toggled; failed rows open by default until toggled. const [toggled, setToggled] = useState>(new Map()); + const sections = buildLogSections(steps, evidence); const started = steps.filter((step) => step.startedAt !== null); - if (!started.length) { + if (!sections.some((section) => section.title !== null) && !started.length) { return finished ? This image's build output is no longer kept. : ; } const outputByStep = new Map(); @@ -62,12 +63,21 @@ export function BuildLogs({ steps, output, finished, timeZone, now = Date.now() const runs = new Set(started.map((step) => step.build).filter((build) => build > 0)).size; const failedRuns = new Set(steps.filter((step) => step.error !== null).map((step) => step.build)); const time = clock(timeZone); - const shown = started.filter((step) => step.error !== null || (step.key !== CLEANUP_KEY && (step.key !== BUILDING_KEY || runs > 1 || failedRuns.has(step.build)))); + const shown = (section: readonly BuildStepRow[]) => section.filter((step) => step.startedAt !== null + && (step.error !== null || (step.key !== CLEANUP_KEY && (step.key !== BUILDING_KEY || runs > 1 || failedRuns.has(step.build))))); + const heading = "mt-2 flex items-center gap-3 px-1 font-medium"; return
    - {shown.map((step) => step.key === BUILDING_KEY && step.error === null - ?
  1. Building {step.name}
  2. - : setToggled((previous) => previous.get(step.id) === open ? previous : new Map(previous).set(step.id, open))} />)} + {sections.flatMap((section, index) => [ + section.title === null ? [] : [
  3. + + {section.title} + {section.runUrl ? : null} +
  4. ], + shown(section.steps).map((step) => step.key === BUILDING_KEY && step.error === null + ?
  5. Building {step.name}
  6. + : setToggled((previous) => previous.get(step.id) === open ? previous : new Map(previous).set(step.id, open))} />), + ].flat())}
; } @@ -108,6 +118,7 @@ function StepRow({ step, time, lines, now, open: toggledOpen, onToggle }: { function lifecycleLogs(events: readonly { id: number; createdAt: Date; progress: DeploymentProgress }[], serviceId: string): ContainerLogRow[] { const previous = new Map(); const logs: ContainerLogRow[] = []; + let sending: string | null = null; for (const event of events) { for (const row of event.progress.rows) { if (row.serviceId !== serviceId && row.serviceId !== null) continue; @@ -117,6 +128,12 @@ function lifecycleLogs(events: readonly { id: number; createdAt: Date; progress: previous.set(row.index, label); logs.push({ id: `lifecycle:${event.id}:${row.index}`, timestamp: String(BigInt(event.createdAt.getTime()) * 1_000_000n), channel: "lifecycle", machineId: row.machineId, machineName: row.machineName ?? row.machineId, containerId: row.target ?? "", serviceName: row.serviceName ?? "Environment", message: label }); } + // Sending the image to the Machines that run it happens at deploy time, so it reads here. + const preparation = event.progress.preparation; + if (preparation?.phase === "transfer" && preparation.serviceId === serviceId && preparation.message && sending !== preparation.message) { + sending = preparation.message; + logs.push({ id: `lifecycle:${event.id}:transfer`, timestamp: String(BigInt(event.createdAt.getTime()) * 1_000_000n), channel: "lifecycle", machineId: "", machineName: "", containerId: "", serviceName: "Deployment", message: preparation.message }); + } event.progress.compensation.forEach((message, i) => logs.push({ id: `lifecycle:${event.id}:recovery:${i}`, timestamp: String(BigInt(event.createdAt.getTime()) * 1_000_000n), channel: "lifecycle", machineId: "", machineName: "", containerId: "", serviceName: "Deployment", message })); } return logs; @@ -129,17 +146,11 @@ export function ServiceBuildLogs({ organizationSlug, deploymentId, image }: { or const now = useNow(build.data?.finished === false); const steps = imageBuildSteps(build.data?.steps ?? [], image); const ids = new Set(steps.map((step) => step.id)); - const server = builtOn(build.data, image); return <> {build.isError ?

Could not load build logs.

: null} - {server ? - {builtOnLine(server)} - {server.server !== null && server.runUrl ? - - : null} - : null} - {build.isPending ? : ids.has(row.stepId))} finished={build.data?.finished ?? true} timeZone={timeZone} now={now} />} + {build.isPending ? : ids.has(row.stepId))} + finished={build.data?.finished ?? true} evidence={build.data?.imageBuilds.find((row) => row.image === image)} timeZone={timeZone} now={now} />} ; } diff --git a/dashboard/src/modules/deployments/build-order.server.ts b/dashboard/src/modules/deployments/build-order.server.ts index d7aab8108e..213aba3cab 100644 --- a/dashboard/src/modules/deployments/build-order.server.ts +++ b/dashboard/src/modules/deployments/build-order.server.ts @@ -64,14 +64,16 @@ export const planImageBuildWalk = Effect.fn("Deployments.planImageBuildWalk")(fu yield* Effect.logWarning("A Service's policy does not decode; its build follows the Build Order.", { serviceId: build.serviceId }); } let preferred = Option.isSome(policy) ? policy.value.preferredBuilder : undefined; + let skipped = 0; if (preferred !== undefined && preferred !== "github") { const unavailable = yield* preferredServerUnavailable(row.organizationId, preferred); if (unavailable) { yield* skipUnstarted(build, unavailable); preferred = undefined; + skipped = 1; } } - return imageBuildWalk(yield* loadBuildOrder(row.organizationId), preferred); + return imageBuildWalk(yield* loadBuildOrder(row.organizationId), preferred, skipped); }); export const setBuildOrder = Effect.fn("Deployments.setBuildOrder")(function* ( diff --git a/dashboard/src/modules/deployments/build-order.ts b/dashboard/src/modules/deployments/build-order.ts index 2c47525815..b6e8b4d300 100644 --- a/dashboard/src/modules/deployments/build-order.ts +++ b/dashboard/src/modules/deployments/build-order.ts @@ -28,9 +28,10 @@ export const defaultBuildOrder = (githubSetUp: boolean): BuildOrder => githubSet /** * One Builder an Image Build may try, and why it is in the walk. `machineId` is a Preferred Server: - * the Cluster's first choice. + * the Cluster's first choice. `attempt` is its go's place in the Image Build's log: the skip trail's + * length when it starts, as each go before it adds one skip. */ -export type BuildCandidate = { builder: "servers" | "github"; reason: CandidateReason; machineId?: MachineId }; +export type BuildCandidate = { builder: "servers" | "github"; reason: CandidateReason; attempt: number; machineId?: MachineId }; /** The Builders a Build Order tries, in turn. */ const ORDERED_BUILDERS = { @@ -42,14 +43,16 @@ const ORDERED_BUILDERS = { /** * The Builders one Image Build walks: the Service's Preferred Builder, then the Build Order without - * that Builder. A Preferred Server stands in for "your servers", with it first. + * that Builder. A Preferred Server stands in for "your servers", with it first. `skipped`: skips + * already on the trail before the walk starts. */ -export const imageBuildWalk = (order: BuildOrder, preferred: "github" | MachineId | undefined): BuildCandidate[] => { - const walk: BuildCandidate[] = []; +export const imageBuildWalk = (order: BuildOrder, preferred: "github" | MachineId | undefined, skipped = 0): BuildCandidate[] => { + const walk: Omit[] = []; if (preferred === "github") walk.push({ builder: "github", reason: "preferred" }); else if (preferred !== undefined) walk.push({ builder: "servers", reason: "preferred", machineId: preferred }); const rest = ORDERED_BUILDERS[order].filter((builder) => !walk.some((first) => first.builder === builder)); - return [...walk, ...rest.map((builder, index): BuildCandidate => ({ builder, reason: index === 0 ? "first_in_build_order" : "next_in_build_order" }))]; + return [...walk, ...rest.map((builder, index) => ({ builder, reason: index === 0 ? "first_in_build_order" as const : "next_in_build_order" as const }))] + .map((candidate, index) => ({ ...candidate, attempt: skipped + index })); }; export const buildOrderEditSchema = Schema.Struct({ diff --git a/dashboard/src/modules/deployments/deployment-events.server.ts b/dashboard/src/modules/deployments/deployment-events.server.ts index 1b0b0c84ee..1014305e23 100644 --- a/dashboard/src/modules/deployments/deployment-events.server.ts +++ b/dashboard/src/modules/deployments/deployment-events.server.ts @@ -7,7 +7,6 @@ import { NotFound } from "#/server/public-error"; import { environmentDeployment, environmentDeploymentBuildOutput, environmentDeploymentBuildStep, environmentDeploymentEvent, environmentDeploymentImageBuild } from "./tables"; import type { BuildOutputWrite, BuildStepWrite } from "./preparation-progress"; import type { ImageBuildEvidence } from "./deployment-view"; -import type { CandidateReason } from "./image-build"; /** Logs are fetched only when opened. Live progress is the latest event; terminal progress lives on the deployment. */ export const loadDeploymentEvents = Effect.fn("Deployments.events")(function* (input: { @@ -48,34 +47,34 @@ export const loadDeploymentBuildLog = Effect.fn("Deployments.buildLog")(function drizzle.select({ id: table.id, rank: sql`row_number() over (partition by ${table.stepId} order by ${table.id} desc)`.as("rank") }) .from(table).where(eq(table.deploymentId, input.deploymentId)).as("ranked"), ).where(sql`ranked.rank <= ${input.tail}`))).orderBy(asc(table.id)); - // Which Server (or GitHub run) each image builds on, why, and what it skipped; never the receipt, grant or run state. + // Which Server (or GitHub run) each image builds on and what it skipped; never the receipt, grant or run state. const builds = environmentDeploymentImageBuild; const imageBuilds: ImageBuildEvidence[] = yield* drizzle.select({ image: builds.image, serverChoice: builds.serverChoice, skips: builds.skips, - runUrl: sql`${builds.github} ->> 'runUrl'`, reason: sql`${builds.github} ->> 'reason'`, - }).from(builds).where(eq(builds.deploymentId, input.deploymentId)).pipe(Effect.map((rows) => rows.map(({ runUrl, reason, ...row }) => - ({ ...row, github: runUrl && reason ? { runUrl, reason } : null })))); + runUrl: sql`${builds.github} ->> 'runUrl'`, + }).from(builds).where(eq(builds.deploymentId, input.deploymentId)).pipe(Effect.map((rows) => rows.map(({ runUrl, ...row }) => + ({ ...row, github: runUrl ? { runUrl } : null })))); const last = output.at(-1); return { steps, output, imageBuilds, finished: deployment.finishedAt !== null, nextSequence: input.tail === undefined && output.length === input.limit && last ? String(last.id) : null }; }); -/** - * Upsert steps by key and append output. Output may precede its step; a placeholder holds its place. - * Each Image Build files its steps under its image; the deploy step's own preparation under none. - */ -export const persistBuildLog = Effect.fn("Deployments.persistBuildLog")(function* (deploymentId: string, writes: { steps: readonly BuildStepWrite[]; output: readonly BuildOutputWrite[] }, image: string | null = null) { +/** Whose Build Steps a write files: one Builder's go (`attempt`) at one Image Build (`image`); null is the deploy step's own. */ +export type BuildStepOwner = { image: string; attempt: number } | null; + +/** Upsert steps by key and append output. Output may precede its step; a placeholder holds its place. */ +export const persistBuildLog = Effect.fn("Deployments.persistBuildLog")(function* (deploymentId: string, writes: { steps: readonly BuildStepWrite[]; output: readonly BuildOutputWrite[] }, owner: BuildStepOwner = null) { if (!writes.steps.length && !writes.output.length) return; const database = yield* Database; + const filed = { organizationId: organizationIdForDeployment(deploymentId), deploymentId, image: owner?.image ?? null, attempt: owner?.attempt ?? 0 }; yield* database.transaction(Effect.gen(function* () { const { drizzle } = yield* Database; const table = environmentDeploymentBuildStep; - const target = [table.deploymentId, table.image, table.build, table.key]; - const organizationId = organizationIdForDeployment(deploymentId); + const target = [table.deploymentId, table.image, table.attempt, table.build, table.key]; const ids = new Map(); if (writes.steps.length) { const excluded = (column: { name: string }) => sql.raw(`excluded."${column.name}"`); const steps = new Map(writes.steps.map((step) => [`${step.build}:${step.key}`, step])); - const upserted = yield* drizzle.insert(table).values([...steps.values()].map((step) => ({ organizationId, deploymentId, image, ...step }))) + const upserted = yield* drizzle.insert(table).values([...steps.values()].map((step) => ({ ...filed, ...step }))) .onConflictDoUpdate({ target, set: { name: excluded(table.name), startedAt: excluded(table.startedAt), completedAt: excluded(table.completedAt), cached: excluded(table.cached), error: excluded(table.error), updatedAt: new Date() } }) .returning({ id: table.id, build: table.build, key: table.key }); for (const step of upserted) ids.set(`${step.build}:${step.key}`, step.id); @@ -83,18 +82,25 @@ export const persistBuildLog = Effect.fn("Deployments.persistBuildLog")(function if (!writes.output.length) return; const unknown = new Map(writes.output.filter((row) => !ids.has(`${row.build}:${row.step}`)).map((row) => [`${row.build}:${row.step}`, row])); if (unknown.size) { - const found = yield* drizzle.insert(table).values([...unknown.values()].map((row) => ({ organizationId, deploymentId, image, build: row.build, key: row.step, name: row.step }))) + const found = yield* drizzle.insert(table).values([...unknown.values()].map((row) => ({ ...filed, build: row.build, key: row.step, name: row.step }))) .onConflictDoUpdate({ target, set: { key: table.key } }) .returning({ id: table.id, build: table.build, key: table.key }); for (const step of found) ids.set(`${step.build}:${step.key}`, step.id); } yield* drizzle.insert(environmentDeploymentBuildOutput).values(writes.output.flatMap((row) => { const stepId = ids.get(`${row.build}:${row.step}`); - return stepId === undefined ? [] : [{ organizationId, deploymentId, stepId, stderr: row.stderr, text: row.text }]; + return stepId === undefined ? [] : [{ organizationId: filed.organizationId, deploymentId, stepId, stderr: row.stderr, text: row.text }]; })); })); }); +/** Opens a step once: a retried write leaves it as it is, even closed since. */ +export const openBuildStep = Effect.fn("Deployments.openBuildStep")(function* (deploymentId: string, owner: NonNullable, step: BuildStepWrite) { + const { drizzle } = yield* Database; + yield* drizzle.insert(environmentDeploymentBuildStep) + .values({ organizationId: organizationIdForDeployment(deploymentId), deploymentId, ...owner, ...step }).onConflictDoNothing(); +}); + export const persistDeploymentProgress = Effect.fn("Deployments.persistProgress")(function* (deploymentId: string, progress: typeof environmentDeploymentEvent.$inferInsert.progress) { const { drizzle } = yield* Database; yield* drizzle.insert(environmentDeploymentEvent).values({ organizationId: organizationIdForDeployment(deploymentId), deploymentId, progress }); diff --git a/dashboard/src/modules/deployments/deployment-view.test.ts b/dashboard/src/modules/deployments/deployment-view.test.ts index ae47e4c84f..53cb95a5eb 100644 --- a/dashboard/src/modules/deployments/deployment-view.test.ts +++ b/dashboard/src/modules/deployments/deployment-view.test.ts @@ -3,7 +3,7 @@ import type { ContainerId, DeployOperation, MachineId, OperationRow } from "@plo import { resolvedServiceSpecFixture } from "#/modules/runtime/runtime-watch-frame.test-fixture"; import { canonicalJson } from "#/modules/environment-design/canonical-json"; import { parseServiceConfig } from "@ployz/sdk/config"; -import { builtOnLine, deploymentProgressForEvent, deploymentStatusLabel, deploymentView, type AttemptTargetNode, type DeploymentViewInput } from "./deployment-view"; +import { buildLogSections, deploymentProgressForEvent, deploymentStatusLabel, deploymentView, type AttemptTargetNode, type DeploymentViewInput } from "./deployment-view"; function row(index: number, operation?: DeployOperation): OperationRow { const spec = resolvedServiceSpecFixture(); @@ -14,8 +14,8 @@ function row(index: number, operation?: DeployOperation): OperationRow { /** The Engine serializes keys alphabetically, unlike the planned rows. */ const engineOrdered = (value: T): T => JSON.parse(canonicalJson(value)) as T; const context = { serviceIdFor: (name: string | null) => name }; -const step = (id: number, build: number, key: string, name: string, start: number, end: number | null, error: string | null = null, image: string | null = null) => - ({ id, image, build, key, name, startedAt: new Date(start * 1000), completedAt: end === null ? null : new Date(end * 1000), error }); +const step = (id: number, build: number, key: string, name: string, start: number, end: number | null, error: string | null = null, image: string | null = null, attempt = 0) => + ({ id, image, attempt, build, key, name, startedAt: new Date(start * 1000), completedAt: end === null ? null : new Date(end * 1000), error }); const deployment = (status: DeploymentViewInput["deployment"]["status"], extra: Partial = {}): DeploymentViewInput["deployment"] => ({ status, failureMessage: null, deployPreview: null, ...extra }); /** A service in the Attempt Target; `image` makes it a built one. */ @@ -97,43 +97,52 @@ describe("deployment view projection", () => { expect(deploymentStatusLabel(view)).toBe("Failed ยท 0 of 4 deployed"); }); - it("says which Server each image builds on and why, only once the Engine chose", () => { + it("names only the Builder that holds each image's build, never why it was chosen", () => { const view = deploymentView({ deployment: deployment("queued"), progress: null, - nodes: ["api", "web", "docs", "worker", "site", "blog", "wiki", "shop", "mail", "cron"].map((image) => node({ nodeId: image, changed: true, image })), + nodes: ["api", "site", "worker"].map((image) => node({ nodeId: image, changed: true, image })), buildLog: { steps: [], output: [], imageBuilds: [ - { image: "site", serverChoice: null, github: { runUrl: "https://github.com/o/r/actions/runs/1", reason: "first_in_build_order" }, skips: [] }, + { image: "site", serverChoice: null, github: { runUrl: "https://github.com/o/r/actions/runs/1" }, skips: [] }, { image: "api", serverChoice: { machineName: "nuc", reason: { kind: "had_cache" } }, github: null, skips: [] }, - { image: "web", serverChoice: { machineName: "hel-1", reason: { kind: "spread" } }, github: null, skips: [] }, - { image: "docs", serverChoice: { machineName: "hel-1", reason: { kind: "cache_holder_unavailable", holder: "c".repeat(32) as MachineId, name: "nuc" } }, github: null, skips: [] }, - { image: "worker", serverChoice: null, github: null, skips: [] }, - { image: "blog", serverChoice: null, github: { runUrl: "https://github.com/o/r/actions/runs/2", reason: "next_in_build_order" }, skips: [{ builder: "servers", kind: "not_started", minutes: 3 }] }, - { image: "wiki", serverChoice: null, github: null, skips: [{ builder: "github", kind: "no_workflow", repository: "o/r" }, { builder: "servers", kind: "preferred_unavailable", machineId: "e".repeat(32) as MachineId, name: null }] }, - { image: "shop", serverChoice: { machineName: "fast", reason: { kind: "preferred" } }, github: null, skips: [] }, - { image: "mail", serverChoice: null, github: { runUrl: "https://github.com/o/r/actions/runs/3", reason: "preferred" }, skips: [] }, - { image: "cron", serverChoice: { machineName: "hel-1", reason: { kind: "preferred_unavailable", preferred: "d".repeat(32) as MachineId, name: null } }, github: null, skips: [] }, + { image: "worker", serverChoice: null, github: null, skips: [{ builder: "github", kind: "no_workflow", repository: "o/r" }] }, ], }, }); - expect(view.nodes.map((n) => n.builtOn)).toEqual([ - { server: "nuc", reason: "had this Service's build cache", skipped: [] }, - { server: "hel-1", reason: "spread across Servers", skipped: [] }, - { server: "hel-1", reason: "nuc has the cache but is offline or no longer builds", skipped: [] }, - null, - { server: "GitHub Actions", reason: "first in the build order", runUrl: "https://github.com/o/r/actions/runs/1", skipped: [] }, - { server: "GitHub Actions", reason: "next in the build order", runUrl: "https://github.com/o/r/actions/runs/2", skipped: ["Your servers: none started it in 3 min"] }, - { server: null, reason: null, skipped: ["GitHub: no workflow in o/r", "Preferred server: no longer in the Cluster"] }, - { server: "fast", reason: "preferred builder", skipped: [] }, - { server: "GitHub Actions", reason: "preferred builder", runUrl: "https://github.com/o/r/actions/runs/3", skipped: [] }, - { server: "hel-1", reason: "Preferred server: no longer in the Cluster", skipped: [] }, - ]); - // The skip trail reads after the Builder that took the build, or alone before one did. - expect(view.nodes.slice(5, 7).map((n) => n.builtOn && builtOnLine(n.builtOn))).toEqual([ - "Built on GitHub Actions ยท next in the build order ยท skipped Your servers: none started it in 3 min", - "Skipped GitHub: no workflow in o/r ยท skipped Preferred server: no longer in the Cluster", + expect(view.nodes.map((n) => n.builtOn)).toEqual(["nuc", "GitHub Actions", null]); + }); + + it("tells one timeline per Image Build: a section per Builder, each move one sentence", () => { + const github = [step(2, 0, "runner", "Waiting for a runner", 0, 20, null, "web", 1), step(3, 1, "stage:Building", "web", 20, 60, null, "web", 1)]; + const servers = [step(5, 1, "stage:Building", "web", 62, null, null, "web", 2)]; + const steps = [...github, ...servers]; + const evidence = { image: "web", github: null, serverChoice: { machineName: "hel-1", reason: { kind: "spread" as const } }, skips: [ + { builder: "servers" as const, kind: "preferred_unavailable" as const, machineId: "e".repeat(32) as MachineId, name: "hel-2" }, + { builder: "github" as const, kind: "runner_stopped" as const }, + ] }; + // Each go's Builder comes from its skip, or the holder for the last; the planning skip wrote no step. + expect(buildLogSections(steps, evidence).map(({ title, steps: own }) => [title, own.map((row) => row.id)])).toEqual([ + ["Your preferred server hel-2 is offline or no longer builds. Building on GitHub Actions instead.", [2, 3]], + ["GitHub couldn't finish this build: its runner stopped. Building on hel-1 instead.", [5]], ]); + // A Builder skipped before it wrote a step leaves its sentence alone; the first section names its Builder plainly. + expect(buildLogSections([step(1, 1, "stage:Building", "web", 0, null, null, "web", 1)], { ...evidence, skips: [{ builder: "github", kind: "no_workflow", repository: "o/r" }] }) + .map((section) => section.title)).toEqual(["o/r has no Ployz build workflow. Building on hel-1 instead."]); + expect(buildLogSections([step(1, 0, "runner", "Waiting for a runner", 0, null, null, "web")], { ...evidence, serverChoice: null, github: { runUrl: "u" }, skips: [] }) + .map((section) => section.title)).toEqual(["Building on GitHub Actions"]); + // A Server go that moved on keeps its Server's name on its skip; before the Engine chose one, it is "your servers". + const queued = [step(1, 0, "stage:Queued", "Waiting for a free build slot", 0, 180, null, "web")]; + expect(buildLogSections(queued, { ...evidence, skips: [{ builder: "servers", kind: "not_started", minutes: 3, machineName: "hel-1" }] }) + .map((section) => section.title)).toEqual(["Building on hel-1", "No server started the build within 3 min."]); + expect(buildLogSections(queued, { ...evidence, skips: [{ builder: "servers", kind: "not_started", minutes: 3 }] }) + .map((section) => section.title)).toEqual(["Building on your servers", "No server started the build within 3 min."]); + // Only the last Builder's go decides the node: GitHub's earlier failure moved on, hel-1 still builds. + const view = deploymentView({ + deployment: deployment("queued"), progress: null, nodes: [node({ nodeId: "web", changed: true, image: "web" })], + buildLog: { steps: [...github, step(6, 0, "install", "Installing ployz", 1, 2, "no such version", "web", 1), ...servers], output: [], imageBuilds: [evidence] }, + }); + expect(view.nodes[0]).toMatchObject({ outcome: "building", build: { state: "running" }, builtOn: "hel-1" }); }); it("tails the image building now while the next image waits its turn", () => { diff --git a/dashboard/src/modules/deployments/deployment-view.ts b/dashboard/src/modules/deployments/deployment-view.ts index 85a92b4a86..6f22fd2ef8 100644 --- a/dashboard/src/modules/deployments/deployment-view.ts +++ b/dashboard/src/modules/deployments/deployment-view.ts @@ -4,7 +4,7 @@ import { canonicalJson } from "#/modules/environment-design/canonical-json"; import { decodeStrict } from "#/modules/environment-design/schema"; import { persistedVolumeConfigSchema, type VolumeConfig } from "#/modules/environment-design/volume-config"; import type { EnvironmentDeploymentStatus, ServerChoice } from "./tables"; -import { preferredServerUnavailableText, skipReasonText, type CandidateReason, type SkipReason } from "./image-build"; +import { preferredServerUnavailableText, skipReasonText, type SkipReason } from "./image-build"; import { BUILDING_KEY, CLEANUP_KEY, TRANSFER_KEY } from "./preparation-progress"; import { executionErrorLabel, progressRowLabel, type DeploymentProgress, type DeploymentProgressRow } from "./deployment-progress"; import { isActiveDeployment } from "./runtime-contract"; @@ -26,13 +26,9 @@ export type DeploymentNodeView = { deploy: Stage; failure: { message: string; containerId: string | null } | null; tail: string[]; - /** The Server the Engine chose for this image and why, once it chose. */ - builtOn: BuiltOn | null; + /** The Builder that holds this image's build: "GitHub Actions" or a Server, once one took it. */ + builtOn: string | null; }; -/** `runUrl` links a build that ran on GitHub Actions; `skipped` is its skip trail, in order. */ -export type BuiltOn = - | { server: string; reason: string; runUrl?: string; skipped: readonly string[] } - | { server: null; reason: null; skipped: readonly string[] }; export type DeploymentViewStatus = "queued" | "building" | "deploying" | "deployed" | "failed" | "cancelled"; export type DeploymentView = { status: DeploymentViewStatus; @@ -40,12 +36,12 @@ export type DeploymentView = { nodes: DeploymentNodeView[]; }; /** The attempt's Build Steps and their output, as the build log read returns them. `image` is null for the deploy step's own. */ -type BuildStep = { id: number; image: string | null; build: number; key: string; name: string; startedAt: Date | null; completedAt: Date | null; error: string | null }; +type BuildStep = { id: number; image: string | null; attempt: number; build: number; key: string; name: string; startedAt: Date | null; completedAt: Date | null; error: string | null }; /** What an Image Build recorded about its Builders: the Server choice or GitHub run, and the skip trail. */ export type ImageBuildEvidence = { image: string; serverChoice: ServerChoice | null; - github: { runUrl: string; reason: CandidateReason } | null; + github: { runUrl: string } | null; skips: readonly SkipReason[]; }; export type BuildLog = { @@ -54,43 +50,53 @@ export type BuildLog = { imageBuilds?: readonly ImageBuildEvidence[]; }; -/** Why GitHub Actions took an Image Build, as recorded when it did. */ -const githubReasonText = { - preferred: "preferred builder", - first_in_build_order: "first in the build order", - next_in_build_order: "next in the build order", -} satisfies Record; - -/** Why the Engine chose a Server: recorded evidence, never a prediction. */ -function builderReason(reason: ServerChoice["reason"]): string { - switch (reason.kind) { - case "preferred": return "preferred builder"; - case "had_cache": return "had this Service's build cache"; - case "spread": return "spread across Servers"; - case "cache_holder_unavailable": return `${reason.name ?? "the Server with the cache"} has the cache but is offline or no longer builds`; - case "preferred_unavailable": return preferredServerUnavailableText(reason.name); - case "reused": return "reused the build of this commit"; - } -} - /** - * Where an image builds and why, from what its Image Build recorded: the Server choice or GitHub - * run, and the Builders it skipped on the way. Before a Builder takes it, only the skips are known. + * The Builder that holds an image's build now, from what its Image Build recorded. Why it was + * chosen stays in the data: routine choices are nothing the user acts on. */ -export function builtOn(log: Pick | null | undefined, image: string | null): BuiltOn | null { +export function builtOn(log: Pick | null | undefined, image: string | null): string | null { const row = image ? log?.imageBuilds?.find((candidate) => candidate.image === image) : undefined; - const skipped = (row?.skips ?? []).map(skipReasonText); - if (row?.github) return { server: "GitHub Actions", reason: githubReasonText[row.github.reason], runUrl: row.github.runUrl, skipped }; - if (row?.serverChoice) return { server: row.serverChoice.machineName, reason: builderReason(row.serverChoice.reason), skipped }; - return skipped.length ? { server: null, reason: null, skipped } : null; + if (row?.github) return "GitHub Actions"; + return row?.serverChoice?.machineName ?? null; +} + +/** Who took one go at an Image Build: the Builder its skip names, or the one that holds the build now. Null for a reused image. */ +function goBuilder(skipped: SkipReason | undefined, evidence: ImageBuildEvidence | undefined): string | null { + if (skipped?.builder === "github") return "GitHub Actions"; + if (skipped) return skipped.kind === "not_started" && skipped.machineName !== undefined ? skipped.machineName : "your servers"; + if (evidence?.github) return "GitHub Actions"; + const choice = evidence?.serverChoice; + return choice && choice.reason.kind !== "reused" ? choice.machineName : null; } -/** "Built on ยท ยท skipped ", as the canvas and build log say it. */ -export function builtOnLine({ server, reason, skipped }: BuiltOn) { - const line = [server ? `Built on ${server} ยท ${reason}` : null, ...skipped.map((skip) => `skipped ${skip}`)] - .filter((part) => part !== null).join(" ยท "); - return line.charAt(0).toUpperCase() + line.slice(1); +/** One Builder's go at an Image Build, as its log tells it: one plain line, then its steps. */ +export type BuildLogSection = { title: string | null; runUrl: string | null; steps: Step[] }; + +/** + * An Image Build's log as one timeline: a section per Builder's go, in order. The first says where it + * builds; each later one first says, from the skip trail, why the build moved: "GitHub couldn't + * finish this build: its runner stopped. Building on hel-1 instead." A go's Builder is the one its + * skip names, or the current holder for the last. A Builder skipped before it wrote a step leaves only that sentence. The deploy step's own + * rows happened after every go, so they join the last. + */ +export function buildLogSections(steps: readonly Step[], evidence: ImageBuildEvidence | undefined): BuildLogSection[] { + const skips = evidence?.skips ?? []; + const last = Math.max(skips.length, ...steps.map((step) => step.image === null ? 0 : step.attempt)); + const sections = Array.from({ length: last + 1 }, (_, attempt): BuildLogSection => { + const own = steps.filter((step) => (step.image === null ? last : step.attempt) === attempt); + const builder = own.length ? goBuilder(attempt < skips.length ? skips[attempt] : undefined, evidence) : null; + const skipped = attempt > 0 ? skips[attempt - 1] : undefined; + const lead = skipped ? [skipReasonText(skipped)] : []; + const choice = attempt === last ? evidence?.serverChoice?.reason : undefined; + // The Engine found the Preferred Server unavailable itself: the same move, one step later. + if (choice?.kind === "preferred_unavailable") lead.push(preferredServerUnavailableText(choice.name)); + const moved = lead.join(" "); + const title = builder === null ? moved || null : moved ? `${moved} Building on ${builder} instead.` : `Building on ${builder}`; + return { title, runUrl: attempt === last ? evidence?.github?.runUrl ?? null : null, steps: own }; + }); + return sections.filter((section) => section.title !== null || section.steps.length > 0); } + export type DeploymentViewInput = { deployment: { status: EnvironmentDeploymentStatus; @@ -204,16 +210,19 @@ export function imageBuildSteps(steps: readonly Step[], type ImageBuild = { failed: boolean; open: boolean; durationMs: number | undefined; lines: string[]; errorLines: string[] }; +/** An image's build as a node reads it: its latest Builder's go decides how it stands; an earlier one only moved on. */ function imageBuild(log: BuildLog, image: string): ImageBuild | null { const steps = imageBuildSteps(log.steps, image); if (!steps.length) return null; - const failed = steps.filter((step) => step.error !== null); + const current = buildLogSections(steps, log.imageBuilds?.find((row) => row.image === image)).at(-1)?.steps ?? []; + const failed = current.filter((step) => step.error !== null); const output = (ids: ReadonlySet) => logLines(log.output.filter((row) => ids.has(row.stepId)).map((row) => row.text).join("")); const starts = steps.flatMap((step) => step.startedAt ? [step.startedAt.getTime()] : []); const ends = steps.flatMap((step) => step.completedAt ? [step.completedAt.getTime()] : []); return { failed: failed.length > 0, - open: steps.some((step) => step.startedAt && !step.completedAt), + // A Builder that took it but reported nothing yet, or the walk between two, is still at it. + open: !current.length || current.some((step) => step.startedAt && !step.completedAt), durationMs: starts.length && ends.length ? Math.max(...ends) - Math.min(...starts) : undefined, lines: output(new Set(steps.map((step) => step.id))), errorLines: [...output(new Set(failed.map((step) => step.id))), ...failed.flatMap((step) => logLines(step.error ?? ""))], @@ -241,8 +250,8 @@ type AttemptFacts = { function attemptBuildStage({ deployment, progress, nodes }: DeploymentViewInput, succeeded: boolean, building: boolean): StageState { // Prebuilt images only: nothing to build. if (!nodes.some((node) => node.image)) return "none"; - // Preparation said ready, the Engine planned the rollout, or the attempt succeeded: every image exists. - if (progress?.preparation?.phase === "ready" || deployment.deployPreview || succeeded) return "done"; + // Preparation said ready or is delivering images, the Engine planned the rollout, or the attempt succeeded: every image exists. + if (progress?.preparation?.phase === "ready" || progress?.preparation?.phase === "transfer" || deployment.deployPreview || succeeded) return "done"; if (deployment.status === "failed") return "failed"; if (deployment.status === "cancelled") return "skipped"; // Image Builds report steps from admission, and preparation reports progress once deploy starts; until then the attempt waits. diff --git a/dashboard/src/modules/deployments/environment-deployment.build-order.inngest-engine.test.ts b/dashboard/src/modules/deployments/environment-deployment.build-order.inngest-engine.test.ts index 6aa70edbce..f979ea9dae 100644 --- a/dashboard/src/modules/deployments/environment-deployment.build-order.inngest-engine.test.ts +++ b/dashboard/src/modules/deployments/environment-deployment.build-order.inngest-engine.test.ts @@ -8,6 +8,7 @@ import type { MachineId } from "@ployz/sdk"; import { imageBuildWalk, type BuildCandidate } from "#/modules/deployments/build-order"; import type { SkipReason } from "#/modules/deployments/image-build"; import * as buildOrder from "#/modules/deployments/build-order.server"; +import * as deploymentEvents from "#/modules/deployments/deployment-events.server"; import * as githubImageBuilds from "#/modules/deployments/github-image-builds.server"; import * as imageBuilds from "#/modules/deployments/image-builds.server"; import type { ImageBuildAttempt, ImageBuildOutcome, ImageBuildTarget } from "#/modules/deployments/image-builds.server"; @@ -85,6 +86,8 @@ vi.spyOn(githubImageBuilds, "checkGithubImageBuild").mockImplementation((_build, fake.seen.push(seen); return fake.checks.shift() ?? (seen.ended ? settled("built") : { kind: "waiting" }); })); +// The build log is the Postgres tests' concern. +vi.spyOn(deploymentEvents, "persistBuildLog").mockImplementation(() => Effect.void); vi.spyOn(imageBuilds, "settleImageBuild").mockImplementation((build, outcome: ImageBuildOutcome) => Effect.sync(() => { if (outcome.status === "failed") fake.failed.push(outcome.message); return imageBuilds.settled(build, outcome.status); @@ -133,7 +136,7 @@ describe("walking the Build Order", () => { it("tells GitHub why it is in the walk, so it records the reason when it takes the build", async () => { fake.candidates = imageBuildWalk("servers-then-github", "github"); - expect(fake.candidates).toEqual([{ builder: "github", reason: "preferred" }, { builder: "servers", reason: "first_in_build_order" }]); + expect(fake.candidates).toEqual([{ builder: "github", reason: "preferred", attempt: 0 }, { builder: "servers", reason: "first_in_build_order", attempt: 1 }]); fake.runCompletes = [true]; expect(await outcome()).toMatchObject({ deployed: true }); expect(fake.githubReasons).toEqual(["preferred"]); @@ -232,6 +235,6 @@ describe("walking the Build Order", () => { fake.candidates = imageBuildWalk("github-only", undefined); fake.githubStart = skipped({ builder: "github", kind: "no_workflow", repository: "acme/api" }); expect(await outcome()).toMatchObject({ deployed: false, error: expect.objectContaining({ message: "Image Build failed: api." }) }); - expect(fake.failed).toContain("GitHub: no workflow in acme/api"); + expect(fake.failed).toContain("acme/api has no Ployz build workflow."); }); }); diff --git a/dashboard/src/modules/deployments/environment-deployment.inngest.ts b/dashboard/src/modules/deployments/environment-deployment.inngest.ts index 9af777b928..7da4d2de98 100644 --- a/dashboard/src/modules/deployments/environment-deployment.inngest.ts +++ b/dashboard/src/modules/deployments/environment-deployment.inngest.ts @@ -37,6 +37,8 @@ import type { BuildCandidate } from "#/modules/deployments/build-order"; import { planImageBuildWalk } from "#/modules/deployments/build-order.server"; import { skipReasonText, type SkipReason } from "#/modules/deployments/image-build"; import { buildOnServers } from "#/modules/deployments/server-image-builds.server"; +import { persistBuildLog } from "#/modules/deployments/deployment-events.server"; +import { ployzStep } from "#/modules/deployments/preparation-progress"; import { cancelGithubImageBuilds, checkGithubImageBuild, @@ -201,8 +203,12 @@ async function runImageBuild( skipped = attempt.reason; } const message = skipped ? skipReasonText(skipped) : "No Builder can take this build."; - const failed = await step.run(`fail-image-build-${build.serviceId}`, () => - runEffect(settleImageBuild(build, { status: "failed", message, machineId: null }))); + // The trail's last sentence says what happened; this step, that nothing else will take it. + const noBuilder = { ...ployzStep("stage:NoBuilder", "Couldn't start the build"), error: "No other Builder in your Build Order can take it." }; + const attempt = (candidates.at(-1)?.attempt ?? -1) + 1; + const failed = await step.run(`fail-image-build-${build.serviceId}`, () => runEffect( + persistBuildLog(build.deploymentId, { steps: [noBuilder], output: [] }, { image: build.image, attempt }).pipe( + Effect.andThen(settleImageBuild(build, { status: "failed", message, machineId: null }))))); return failed.result; } diff --git a/dashboard/src/modules/deployments/github-image-builds.postgres.test.ts b/dashboard/src/modules/deployments/github-image-builds.postgres.test.ts index 853785129b..b96665c65d 100644 --- a/dashboard/src/modules/deployments/github-image-builds.postgres.test.ts +++ b/dashboard/src/modules/deployments/github-image-builds.postgres.test.ts @@ -23,14 +23,16 @@ import { makeInngestEffectRunner, type runInngestEffect } from "#/server/run.ser import { noPairingChanges } from "#/test/organization-runtime"; import { type PostgresTestHarness, startPostgresTestHarness } from "#/test/postgres"; import { makeSecretEncryption, SecretEncryption } from "#/utils/encrypted-secret.server"; -import { loadDeploymentBuildLog } from "./deployment-events.server"; +import { loadDeploymentBuildLog, openBuildStep } from "./deployment-events.server"; import { createMarkCancelledRowBackedWorkflow, createProcessEnvironmentDeployment } from "./environment-deployment.inngest"; import type { BuildOrder } from "./build-order"; import { skipReasonText, type SkipReason } from "./image-build"; import { planImageBuildWalk } from "./build-order.server"; -import { builtOn, builtOnLine } from "./deployment-view"; +import { buildLogSections, builtOn } from "./deployment-view"; +import { ployzStep } from "./preparation-progress"; import { checkGithubImageBuild, checkInGithubBuild, recordGithubBuildSteps, settleOrMoveReportedGithubBuild } from "./github-image-builds.server"; -import { settleGithubImageBuild } from "./image-builds.server"; +import * as imageBuilds from "./image-builds.server"; +import { loadImageBuild, moveStartedGithubBuild, settleGithubImageBuild } from "./image-builds.server"; import { persistDeploymentSourcePin } from "./source-pins.server"; const organizationId = "00000000-0000-4000-8000-000000000801"; @@ -42,7 +44,8 @@ const deploymentId = "00000000-0000-4000-8000-000000000806"; const serviceId = "00000000-0000-4000-8000-000000000807"; const runId = "github-build-run"; const githubRunId = 9001; -const serversNotStarted: SkipReason = { builder: "servers", kind: "not_started", minutes: 3 }; +// The servers queued it on the Server the Engine chose, which the skip keeps for the log. +const serversNotStarted: SkipReason = { builder: "servers", kind: "not_started", minutes: 3, machineName: "entry" }; const githubNotStarted: SkipReason = { builder: "github", kind: "not_started", minutes: 3 }; const commit = "a".repeat(40); const pushed = `sha256:${"e".repeat(64)}`; @@ -344,7 +347,7 @@ describe("Image Builds on GitHub Actions", () => { const log = await buildLog(); expect(log.steps.filter((step) => step.image === "api").map((step) => step.name)).toEqual(["Reused image"]); // Why nothing built stays on the build, as a Server choice does. - expect(builtOnLine(builtOn(log, "api") ?? { server: null, reason: null, skipped: [] })).toBe("Built on peer ยท reused the build of this commit"); + expect(builtOn(log, "api")).toBe("peer"); }); it("dispatches the build when the receipt can't be checked", async () => { @@ -449,10 +452,14 @@ describe("Image Builds on GitHub Actions", () => { expect(fake.prepared.at(-1)).toEqual({ api: receipt }); const log = await harness.runEffect(loadDeploymentBuildLog({ organizationId, deploymentId, after: 0, limit: 50 })); - expect(log.steps.filter((step) => step.image === "api").map((step) => step.name)).toEqual(["Building", "RUN make"]); + // Cloud times the wait for a runner; the runner reports the rest. + expect(log.steps.filter((step) => step.image === "api").map((step) => [step.name, step.attempt])).toEqual([ + ["Building", 0], ["Waiting for a runner", 0], ["RUN make", 0], + ]); + expect(log.steps.find((step) => step.name === "Waiting for a runner")?.completedAt).not.toBeNull(); expect(log.output.map((line) => line.text)).toEqual(["ok\n"]); - // A GitHub build has no Server choice; the log links its run and says why GitHub took it. - expect(log.imageBuilds).toEqual([{ image: "api", serverChoice: null, github: { runUrl: "https://github.com/owner/repo/actions/runs/9001", reason: "first_in_build_order" }, skips: [] }]); + // A GitHub build has no Server choice; the log links its run. + expect(log.imageBuilds).toEqual([{ image: "api", serverChoice: null, github: { runUrl: "https://github.com/owner/repo/actions/runs/9001" }, skips: [] }]); // The build ended: no more Build Steps are taken. expect(await run(Effect.flip(recordGithubBuildSteps(runnerRequest(oidcToken()), built?.id ?? "", JSON.stringify({ from: 3, events: [] }))))) .toMatchObject({ _tag: "Conflict" }); @@ -461,9 +468,15 @@ describe("Image Builds on GitHub Actions", () => { it("shows the runner's Build Steps as they arrive, once each, and only after check-in", async () => { await dispatch(); expect(await refused({ from: 0, events: runnerEvents.slice(0, 1) })).toMatchObject({ _tag: "Conflict" }); + // Until check-in, the log waits for a runner. + expect((await buildLog()).steps.find((step) => step.name === "Waiting for a runner")?.completedAt).toBeNull(); await checkIn(oidcToken()); + // A retried start never reopens the wait the check-in closed. + await run(openBuildStep(deploymentId, { image: "api", attempt: 0 }, ployzStep("runner", "Waiting for a runner", new Date(), null))); + expect((await buildLog()).steps.find((step) => step.name === "Waiting for a runner")?.completedAt).not.toBeNull(); expect(await post({ from: 0, events: runnerEvents.slice(0, 2) })).toEqual({ received: 2 }); - expect((await buildLog()).steps.filter((step) => step.image === "api").map((step) => step.name)).toEqual(["Building", "RUN make"]); + expect((await buildLog()).steps.filter((step) => step.image === "api" && step.key !== "runner").map((step) => step.name)) + .toEqual(["Building", "RUN make"]); // A retried batch repeats lines already taken; only the new one is filed. expect(await post({ from: 1, events: runnerEvents.slice(1) })).toEqual({ received: 3 }); // A batch that skips lines is refused, naming where to resend from. @@ -504,7 +517,10 @@ describe("Image Builds on GitHub Actions", () => { ["the runner stopped before its final report", async () => { await post({ from: 0, events: runnerEvents }); }, { builder: "github", kind: "runner_stopped" }], ["the runner reported no platforms and no failed step", async () => { await report([]); }, { builder: "github", kind: "no_push" }], ["the Machine recorded no push", async () => { fake.noPush = true; await report(["linux/amd64"]); }, { builder: "github", kind: "no_push" }], - ["the runner couldn't install ployz", async () => { await post({ from: 0, events: [], platforms: [], installFailed: "0.1.0-beta.28" }); }, + ["the runner couldn't install ployz", async () => { + const install = { id: "install", name: "Installing ployz", started: "2026-09-26T00:00:00Z", completed: "2026-09-26T00:00:05Z", cached: false, error: "Could not install ployz 0.1.0-beta.28." }; + await post({ from: 0, events: [{ at: 1_000, event: { Build: { Step: install } } }], platforms: [], installFailed: "0.1.0-beta.28" }); + }, { builder: "github", kind: "install_failed", version: "0.1.0-beta.28" }], ["the run ran out of time", async () => { await harness.db.update(schema.environmentDeploymentImageBuild).set({ checkedInAt: new Date(Date.now() - 3 * 60 * 60_000) }); @@ -523,10 +539,30 @@ describe("Image Builds on GitHub Actions", () => { expect(new Set(fake.ended)).toEqual(new Set([grantId(1)])); const log = await buildLog(); expect(log.imageBuilds).toEqual([expect.objectContaining({ image: "api", skips: [reason] })]); - // GitHub's go shows no failed step: the servers took over. - expect(log.steps.filter((step) => step.error !== null)).toEqual([]); + // One timeline: GitHub's go, then one sentence for the move and the servers' go, which alone decides the build. + const steps = log.steps.filter((step) => step.image === "api"); + expect(buildLogSections(steps, log.imageBuilds[0]).map((section) => section.title)) + .toEqual(["Building on GitHub Actions", `${skipReasonText(reason)} Building on ${machine.name} instead.`]); + expect(steps.filter((step) => step.error !== null && step.key !== "install")).toEqual([]); + expect(steps.filter((step) => step.startedAt !== null && step.completedAt === null && step.attempt === 0)).toEqual([]); }, 30_000); + it("files nothing from a report that loses to a move, so GitHub's section stays closed", async () => { + await buildOrder("github-then-servers"); + await dispatch(); + await checkIn(oidcToken()); + await post({ from: 0, events: runnerEvents.slice(0, 1) }); + // The report loaded the row while GitHub still held it; the walk moves the build before the report lands. + const stale = await run(loadImageBuild(await imageBuildId())); + expect(await run(moveStartedGithubBuild(await target(), githubRunId, { builder: "github", kind: "runner_stopped" }))).toMatchObject({ kind: "skipped" }); + const load = vi.spyOn(imageBuilds, "loadImageBuild").mockReturnValueOnce(Effect.succeed(stale)); + expect(await refused({ from: 1, events: runnerEvents.slice(1) })).toMatchObject({ _tag: "Conflict" }); + load.mockRestore(); + const steps = (await buildLog()).steps.filter((step) => step.image === "api"); + expect(steps.map((step) => step.name)).not.toContain("RUN make"); + expect(steps.filter((step) => step.startedAt !== null && step.completedAt === null)).toEqual([]); + }); + it("leaves a build the walk moved to the servers alone when a late GitHub report or settle arrives", async () => { await buildOrder("github-then-servers"); await dispatch(); @@ -638,13 +674,13 @@ describe("Image Builds on GitHub Actions", () => { it.each([ ["no workflow", () => fake.githubErrors.set("fetch_workflow", githubError("fetch_workflow", 404, "not_found")), - { builder: "github", kind: "no_workflow", repository: "owner/repo" }, "GitHub: no workflow in owner/repo"], + { builder: "github", kind: "no_workflow", repository: "owner/repo" }, "owner/repo has no Ployz build workflow."], ["no permission", () => fake.githubErrors.set("resolve_repository", githubError("resolve_repository", 403, "request_failed")), - { builder: "github", kind: "no_permission", repository: "owner/repo" }, "GitHub: no permission in owner/repo"], + { builder: "github", kind: "no_permission", repository: "owner/repo" }, "GitHub has no permission in owner/repo."], ["multi-platform", () => { fake.platforms = ["linux/amd64", "linux/arm64"]; }, - { builder: "github", kind: "multi_platform", platforms: ["amd64", "arm64"] }, "GitHub: needs amd64+arm64"], + { builder: "github", kind: "multi_platform", platforms: ["amd64", "arm64"] }, "GitHub builds one platform, and this image needs amd64 and arm64."], ["dispatch error", () => fake.githubErrors.set("dispatch_workflow", githubError("dispatch_workflow", 422, "request_failed")), - { builder: "github", kind: "dispatch_failed", message: "GitHub answered 422." }, "GitHub: could not start the build (GitHub answered 422.)"], + { builder: "github", kind: "dispatch_failed", message: "GitHub answered 422." }, "GitHub couldn't start the build (GitHub answered 422.)."], ] satisfies [string, () => void, SkipReason, string][])("skips GitHub at once for %s, and with GitHub only the build fails with that reason", async (_case, arrange, reason, message) => { arrange(); await queued(); @@ -732,7 +768,7 @@ describe("Image Builds on GitHub Actions", () => { expect(output.error).toBeUndefined(); expect(await row()).toMatchObject({ status: "built", builder: "github" }); expect((await buildLog()).imageBuilds).toEqual([{ - image: "api", serverChoice: null, github: { runUrl: "https://github.com/owner/repo/actions/runs/9001", reason: "next_in_build_order" }, skips: [serversNotStarted], + image: "api", serverChoice: null, github: { runUrl: "https://github.com/owner/repo/actions/runs/9001" }, skips: [serversNotStarted], }]); }, 30_000); describe("a Service's Preferred Builder", () => { @@ -748,24 +784,24 @@ describe("Image Builds on GitHub Actions", () => { it("defaults to GitHub first once a repository has the build workflow, and to the servers until then", async () => { await harness.db.delete(schema.organizationBuildOrder); - expect(await plan()).toEqual([{ builder: "servers", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "servers", reason: "first_in_build_order", attempt: 0 }]); // The latest Saved State builds from owner/repo through the GitHub App, whose workflow is ready. await harness.pool.query(`update environment_saved_state_snapshot set intent = jsonb_set(intent, '{services}', '[{"config":{"source":{"type":"git","repository":"owner/repo","repositoryId":42,"access":{"type":"github-installation","installationId":7}}}}]')`); - expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order" }, { builder: "servers", reason: "next_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order", attempt: 0 }, { builder: "servers", reason: "next_in_build_order", attempt: 1 }]); fake.githubErrors.set("fetch_workflow", githubError("fetch_workflow", 404, "not_found")); - expect(await plan()).toEqual([{ builder: "servers", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "servers", reason: "first_in_build_order", attempt: 0 }]); }); it("walks the Build Order alone on Auto", async () => { await buildOrder("github-then-servers"); - expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order" }, { builder: "servers", reason: "next_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order", attempt: 0 }, { builder: "servers", reason: "next_in_build_order", attempt: 1 }]); }); it("tries GitHub first, then the Build Order without it, and records that GitHub was preferred", async () => { await buildOrder("servers-then-github"); await prefer("github"); - expect(await plan()).toEqual([{ builder: "github", reason: "preferred" }, { builder: "servers", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "github", reason: "preferred", attempt: 0 }, { builder: "servers", reason: "first_in_build_order", attempt: 1 }]); await dispatch(); expect(await github()).toMatchObject({ reason: "preferred" }); }); @@ -774,7 +810,7 @@ describe("Image Builds on GitHub Actions", () => { fake.machines = [machine, fast]; await buildOrder("github-only"); await prefer(fast.id); - expect(await plan()).toEqual([{ builder: "servers", reason: "preferred", machineId: fast.id }, { builder: "github", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "servers", reason: "preferred", machineId: fast.id, attempt: 0 }, { builder: "github", reason: "first_in_build_order", attempt: 1 }]); // The whole walk: the preferred Server's go has a start limit, then GitHub gets it. await harness.db.delete(schema.environmentDeploymentImageBuild); await queued(); @@ -789,11 +825,11 @@ describe("Image Builds on GitHub Actions", () => { await buildOrder("github-only"); await prefer(fast.id); fake.machines = [machine, { ...fast, accepts_builds: false }]; - expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order", attempt: 1 }]); expect(await row()).toMatchObject({ skips: [{ builder: "servers", kind: "preferred_unavailable", machineId: fast.id, name: "fast" }] }); fake.machines = [machine]; // GitHub only: a gone preferred Server never puts the build on your servers. - expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order" }]); + expect(await plan()).toEqual([{ builder: "github", reason: "first_in_build_order", attempt: 1 }]); expect(await row()).toMatchObject({ skips: [{ builder: "servers", kind: "preferred_unavailable", machineId: fast.id, name: null }] }); expect((await buildLog()).imageBuilds).toEqual([expect.objectContaining({ skips: [expect.objectContaining({ kind: "preferred_unavailable" })] })]); }); diff --git a/dashboard/src/modules/deployments/github-image-builds.server.ts b/dashboard/src/modules/deployments/github-image-builds.server.ts index 606d0b962f..fd780f683f 100644 --- a/dashboard/src/modules/deployments/github-image-builds.server.ts +++ b/dashboard/src/modules/deployments/github-image-builds.server.ts @@ -7,19 +7,20 @@ import { sendInngestEvent } from "#/modules/inngest/client"; import { createGithubBuildRunCompletedEvent } from "#/modules/inngest/events"; import { buildFingerprints, buildGrantTag, ployzVersion } from "#/modules/runtime/ployz.server"; import { AppConfig } from "#/server/config.server"; +import { Database } from "#/server/database.server"; import { BuildGrantUnavailable, Conflict, Forbidden, NotFound, Unauthorized, Validation } from "#/server/public-error"; import type { BuildCandidate } from "./build-order"; import { githubSkipReason, installFailedSchema, type GithubImageBuild } from "./image-build"; -import { persistBuildLog } from "./deployment-events.server"; +import { openBuildStep, persistBuildLog } from "./deployment-events.server"; import { - awaitsCheckIn, checkInImageBuild, claimForGithub, loadBuildReceipts, loadGithubImageBuilds, imageBuildNow, loadImageBuild, recordGithubReport, recordServerChoice, settleGithubImageBuild, settleImageBuild, + awaitsCheckIn, checkInImageBuild, closeOpenSteps, claimForGithub, loadBuildReceipts, loadGithubImageBuilds, imageBuildNow, loadImageBuild, recordGithubReport, recordServerChoice, settleGithubImageBuild, settleImageBuild, moveStartedGithubBuild, skipImageBuilder, skipUnstarted, START_WITHIN_MINUTES, type ImageBuildAttempt, type ImageBuildRow, type ImageBuildTarget, } from "./image-builds.server"; -import { preparationProgressCollector, type BuildOutputWrite, type BuildStepWrite } from "./preparation-progress"; +import { ployzStep, preparationProgressCollector, type BuildOutputWrite, type BuildStepWrite } from "./preparation-progress"; import { loadDeploymentContext } from "./runtime-hydration.repository.server"; import type { DeploymentContext } from "./runtime-repository.contract"; -import { connectedRuntime, oneServiceDeployment } from "./runtime-session.server"; +import { connectedRuntime, DeploymentRuntimeUnavailable, oneServiceDeployment } from "./runtime-session.server"; import { pinSourceCommit } from "./runtime-sources.server"; import { reusedImageStep } from "./server-image-builds.server"; @@ -69,7 +70,8 @@ const grantRepository = (image: string) => `ployz-build/${image}`; * through the GitHub App or lacks permission, has no workflow, needs several platforms, or the * dispatch fails. */ -export const startGithubImageBuild = Effect.fn("Deployments.startGithubImageBuild")(function* (build: ImageBuildTarget, candidate: Pick) { +export const startGithubImageBuild = Effect.fn("Deployments.startGithubImageBuild")(function* (build: ImageBuildTarget, candidate: Pick) { + const owner = { image: build.image, attempt: candidate.attempt }; const context = yield* loadDeploymentContext(build.deploymentId); const snapshot = context?.snapshots.find((candidate) => candidate.serviceId === build.serviceId); const source = installedSource(snapshot); @@ -94,7 +96,7 @@ export const startGithubImageBuild = Effect.fn("Deployments.startGithubImageBuil }).pipe(Effect.scoped); if (outside.kind === "reuse") { yield* recordServerChoice(build.id, outside.receipt.machine_id, { machineName: outside.machine_name, reason: { kind: "reused" } }); - yield* persistBuildLog(build.deploymentId, { steps: [reusedImageStep()], output: [] }, build.image); + yield* persistBuildLog(build.deploymentId, { steps: [reusedImageStep()], output: [] }, owner); return yield* settleImageBuild(build, { status: "built", receipt: outside.receipt }); } const { platforms } = outside; @@ -104,6 +106,9 @@ export const startGithubImageBuild = Effect.fn("Deployments.startGithubImageBuil // With no visible placement, deploy's coverage check decides, as it does after a server build. const runner = platforms[0] === "linux/arm64" ? "ubuntu-24.04-arm" : "ubuntu-latest"; const config = yield* AppConfig; + // Cloud sees both ends of the wait for a runner. It opens before the dispatch, so even the fastest + // check-in finds it to close, and only once, so a retried start never reopens a closed wait. + yield* openBuildStep(build.deploymentId, owner, ployzStep("runner", "Waiting for a runner", new Date(), null)); const run = yield* dispatchGithubBuildWorkflow({ installationId: source.installationId, fullName: workflow.fullName, defaultBranch: workflow.defaultBranch, inputs: { build: build.id, cloud: config.app.url.origin, runner }, @@ -114,6 +119,8 @@ export const startGithubImageBuild = Effect.fn("Deployments.startGithubImageBuil if (claim.kind === "settled") { // Settled (cancelled) while dispatching: the run must not build. yield* cancelGithubRun({ installationId: source.installationId, fullName: workflow.fullName, runId: run.runId }).pipe(Effect.ignore); + // It settled before the wait opened: nothing else closes it. + yield* closeOpenSteps(build.id); return claim satisfies GithubBuildStart; } return { kind: "dispatched", runId: run.runId } satisfies GithubBuildStart; @@ -231,9 +238,10 @@ export const checkInGithubBuild = Effect.fn("Deployments.checkInGithubBuild")(fu Effect.mapError((cause) => new BuildGrantUnavailable({ cause })), ); return { minted, machine }; - }).pipe(Effect.scoped); + }).pipe(Effect.scoped, Effect.tapError((error) => checkInFailed(row, error))); const grant = { id: minted.id, fingerprint }; - if (!(yield* checkInImageBuild({ imageBuildId: row.id, runId: row.githubRunId, machineId: machine.id, grant }))) { + const checkedIn = yield* checkInImageBuild({ imageBuildId: row.id, runId: row.githubRunId, machineId: machine.id, grant }); + if (!checkedIn) { // Lost to a second check-in or to the start-within skip during a slow mint (rare). The grant's // secret never left Cloud, so a grant that fails to end is unusable anyway. yield* endGrant(row.organizationId, machine.id, minted.id).pipe( @@ -241,10 +249,28 @@ export const checkInGithubBuild = Effect.fn("Deployments.checkInGithubBuild")(fu ); return yield* refused; } + // The runner arrived: its wait ends. + yield* closeOpenSteps(row.id); // The runner installs this version: the process that computed the fingerprint names it, even mid-rollout. return { grant: minted.grant, commit, fingerprint, ployzVersion: ployzVersion(), deployment }; }); +/** Why Cloud couldn't start a build its runner checked in for, in the words the log shows. */ +const checkInFailure = (error: Error) => error instanceof BuildGrantUnavailable ? "Your Machine couldn't issue a grant to receive the image." + : error instanceof DeploymentRuntimeUnavailable ? "Cloud couldn't reach your Machine to receive the image." + : "Cloud couldn't start the build on GitHub."; + +/** + * A check-in the runner arrived for but Cloud couldn't start: the one internal GitHub step the log + * shows, and only failed. Best effort; the run then ends and the walk moves on or fails. While + * GitHub holds the build, its go is the skip trail's length. + */ +const checkInFailed = (row: GithubRow, error: Error) => Effect.gen(function* () { + yield* closeOpenSteps(row.id); + yield* persistBuildLog(row.deploymentId, { steps: [{ ...ployzStep("check-in", "Starting the build"), error: checkInFailure(error) }], output: [] }, + { image: row.image, attempt: row.skips.length }); +}).pipe(Effect.catch((error) => Effect.logWarning("Could not log a failed GitHub check-in.", error))); + const buildStepSchema = Schema.Struct({ id: Schema.String, name: Schema.String, started: Schema.NullOr(Schema.String), completed: Schema.NullOr(Schema.String), cached: Schema.Boolean, error: Schema.NullOr(Schema.String), @@ -300,13 +326,19 @@ export const recordGithubBuildSteps = Effect.fn("Deployments.recordGithubBuildSt const platforms = report.platforms ?? null; // A failed Build Step already shows in its row; a build GitHub failed moves on without one. if (platforms) steps.push(...collector.finish()); - yield* persistBuildLog(row.deploymentId, { steps, output }, row.image); const taken = Math.max(received, report.from + report.events.length); const recorded: Types.Mutable> = { received: taken, collector: collector.checkpoint(), platforms: platforms && [...platforms] }; if (platforms && report.installFailed !== undefined) recorded.installFailed = report.installFailed; - if (!(yield* recordGithubReport(row.id, received, recorded))) { - return yield* new Conflict({ message: "Another report of this build was taken first." }); - } + // The steps land with the report that takes them, in one transaction: a report that lost to a move + // (or another report) files nothing, so none reopens in GitHub's section after the move closed it. + // While GitHub holds the build, its go is the skip trail's length. + const database = yield* Database; + const accepted = yield* database.transaction(Effect.gen(function* () { + if (!(yield* recordGithubReport(row.id, received, recorded))) return false; + yield* persistBuildLog(row.deploymentId, { steps, output }, { image: row.image, attempt: row.skips.length }); + return true; + })); + if (!accepted) return yield* new Conflict({ message: "Another report of this build was taken first." }); if (platforms) { // The runner reports its end once the image is pushed, before its run completes (it still // uploads build cache), so the report settles the build and wakes the waiting walk. A build @@ -334,14 +366,7 @@ const finishGithubImageBuild = Effect.fn("Deployments.finishGithubImageBuild")(f } const ended = yield* endGithubBuild(build, row, timedOut); if (ended.kind !== "move") return ended; - const moved = yield* moveStartedGithubBuild(build, row.githubRunId, ended.reason); - const report = row.github.report; - if (moved.kind === "skipped" && report && !report.platforms) { - // No final report closed the runner's open steps: close them, so they don't dangle beside the - // next Builder's. Only once moved: a final report that settled it first keeps its own steps. - yield* persistBuildLog(row.deploymentId, { steps: preparationProgressCollector(undefined, report.collector).finish(), output: [] }, row.image); - } - return moved; + return yield* moveStartedGithubBuild(build, row.githubRunId, ended.reason); }); /** diff --git a/dashboard/src/modules/deployments/image-build.ts b/dashboard/src/modules/deployments/image-build.ts index 8b2fbee6db..ef2265f66b 100644 --- a/dashboard/src/modules/deployments/image-build.ts +++ b/dashboard/src/modules/deployments/image-build.ts @@ -27,7 +27,9 @@ export const skipReasonSchema = Schema.Union([ /** The Service's Preferred Server is gone (`name` null) or no longer accepts builds: the walk went back to Auto. */ Schema.Struct({ builder: Schema.Literal("servers"), kind: Schema.Literal("preferred_unavailable"), machineId: rustMachineIdSchema, name: Schema.NullOr(Schema.String) }), /** It hadn't started the build within its "start within" limit. */ - Schema.Struct({ builder: Schema.Literals(["github", "servers"]), kind: Schema.Literal("not_started"), minutes: Schema.Number }), + Schema.Struct({ builder: Schema.Literal("github"), kind: Schema.Literal("not_started"), minutes: Schema.Number }), + /** No Server started it in time; `machineName` is the Server it waited on, once the Engine chose one. */ + Schema.Struct({ builder: Schema.Literal("servers"), kind: Schema.Literal("not_started"), minutes: Schema.Number, machineName: Schema.optionalKey(Schema.String) }), ]); export type SkipReason = typeof skipReasonSchema.Type; @@ -36,26 +38,28 @@ export type SkipReason = typeof skipReasonSchema.Type; * Engine did when choosing (its reason): the same words either way. `name` is null once it left the Cluster. */ export const preferredServerUnavailableText = (name: string | null) => - name === null ? "Preferred server: no longer in the Cluster" : `Preferred server ${name}: offline or no longer builds`; + name === null ? "Your preferred server left the Cluster." : `Your preferred server ${name} is offline or no longer builds.`; -/** Why a Builder didn't take an Image Build, as the canvas, the build log and a failed build say it. */ +/** + * Why a Builder didn't take an Image Build, as one plain sentence: the build log says it before + * "Building on instead.", and a build no Builder took fails with it. + */ export function skipReasonText(reason: SkipReason): string { - const builder = reason.builder === "github" ? "GitHub" : "Your servers"; switch (reason.kind) { - case "not_connected": return `${builder}: the repository isn't connected through the GitHub App`; - case "no_permission": return `${builder}: no permission in ${reason.repository}`; - case "no_workflow": return `${builder}: no workflow in ${reason.repository}`; - case "multi_platform": return `${builder}: needs ${reason.platforms.join("+")}`; - case "dispatch_failed": return `${builder}: could not start the build (${reason.message})`; - case "ended_before_start": return `${builder}: the run ended before it started`; - case "runner_stopped": return `${builder}: the runner stopped before finishing`; - case "no_push": return `${builder}: the run didn't push an image`; - case "out_of_time": return `${builder}: ran out of time`; - case "install_failed": return `${builder}: couldn't install ployz ${reason.version}`; + case "not_connected": return "GitHub can't reach this repository: it isn't connected through the GitHub App."; + case "no_permission": return `GitHub has no permission in ${reason.repository}.`; + case "no_workflow": return `${reason.repository} has no Ployz build workflow.`; + case "multi_platform": return `GitHub builds one platform, and this image needs ${reason.platforms.join(" and ")}.`; + case "dispatch_failed": return `GitHub couldn't start the build (${reason.message}).`; + case "ended_before_start": return "The GitHub run ended before the build started."; + case "runner_stopped": return "GitHub couldn't finish this build: its runner stopped."; + case "no_push": return "GitHub couldn't finish this build: it pushed no image."; + case "out_of_time": return "GitHub couldn't finish this build in time."; + case "install_failed": return `GitHub couldn't install ployz ${reason.version}.`; case "preferred_unavailable": return preferredServerUnavailableText(reason.name); case "not_started": return reason.builder === "github" - ? `${builder}: no runner in ${reason.minutes} min` - : `${builder}: none started it in ${reason.minutes} min`; + ? `No GitHub runner started within ${reason.minutes} min.` + : `No server started the build within ${reason.minutes} min.`; } } @@ -100,8 +104,9 @@ export type GithubImageBuild = typeof githubImageBuildSchema.Type; * not the build's. Null when a Build Step failed, in any batch: that is final. */ export function githubSkipReason(report: GithubImageBuild["report"], timedOut: boolean): SkipReason | null { - if (report?.collector.stepFailed) return null; + // Before any Build Step ran: its failed "Installing ployz" step is GitHub's, not the build's. if (report?.installFailed !== undefined) return { builder: "github", kind: "install_failed", version: report.installFailed }; + if (report?.collector.stepFailed) return null; if (timedOut) return { builder: "github", kind: "out_of_time" }; return report?.platforms ? { builder: "github", kind: "no_push" } : { builder: "github", kind: "runner_stopped" }; } diff --git a/dashboard/src/modules/deployments/image-builds.server.ts b/dashboard/src/modules/deployments/image-builds.server.ts index f61247c59a..96787b8f68 100644 --- a/dashboard/src/modules/deployments/image-builds.server.ts +++ b/dashboard/src/modules/deployments/image-builds.server.ts @@ -1,6 +1,6 @@ import "@tanstack/react-start/server-only"; import type { BuildGrantId, BuildReceipt, BuildReceipts, MachineId } from "@ployz/sdk"; -import { and, desc, eq, inArray, isNull, sql, type SQL } from "drizzle-orm"; +import { and, desc, eq, inArray, isNotNull, isNull, sql, type SQL } from "drizzle-orm"; import { Effect, Option, Schema } from "effect"; import { organizationIdForDeployment } from "#/db/scope-values.server"; import { rustMachineIdSchema } from "#/modules/machines/enrollment"; @@ -9,7 +9,7 @@ import { SecretEncryption } from "#/utils/encrypted-secret.server"; import { githubImageBuildSchema, type GithubImageBuild, type SkipReason } from "./image-build"; import { ACTIVE_ENVIRONMENT_DEPLOYMENT_STATUSES } from "./runtime-contract"; import type { DeploymentContext } from "./runtime-repository.contract"; -import { environmentDeployment, environmentDeploymentImageBuild as table, type ImageBuildStatus, type ServerChoice } from "./tables"; +import { environmentDeployment, environmentDeploymentBuildStep, environmentDeploymentImageBuild as table, type ImageBuildStatus, type ServerChoice } from "./tables"; /** * Image Build rows and every transition they make. Each transition is one guarded update and @@ -141,6 +141,20 @@ export const claimForGithub = Effect.fn("Deployments.claimImageBuildForGithub")( return claimed ? { kind: "claimed" as const } : settled(build, yield* statusNow(build.id)); }); +/** + * Closes the steps a Builder left open when it stopped holding the build (moved on or settled), so + * none spins beside the next Builder's or after the build ended. Only the holder's steps can be open: + * each go closes its own before the next starts. + */ +export const closeOpenSteps = Effect.fn("Deployments.closeOpenBuildSteps")(function* (imageBuildId: string) { + const { drizzle } = yield* Database; + const steps = environmentDeploymentBuildStep; + yield* drizzle.update(steps).set({ completedAt: sql`now()`, updatedAt: new Date() }).where(and( + sql`(${steps.deploymentId}, ${steps.image}) = (select ${table.deploymentId}, ${table.image} from ${table} where ${table.id} = ${imageBuildId})`, + isNull(steps.completedAt), isNotNull(steps.startedAt), + )); +}); + /** Adds `reason` to the skip trail and clears what the Builder left, so the next one starts clean. */ const skipPatch = (reason: SkipReason) => ({ skips: sql`${table.skips} || ${JSON.stringify([reason])}::jsonb`, @@ -155,7 +169,10 @@ export const skipImageBuilder = Effect.fn("Deployments.skipImageBuilder")(functi const { drizzle } = yield* Database; const [skipped] = yield* drizzle.update(table).set(skipPatch(reason)) .where(and(eq(table.id, build.id), eq(table.status, "building"), isNull(table.checkedInAt))).returning({ id: table.id }); - if (skipped) return { kind: "skipped", reason } satisfies ImageBuildAttempt; + if (skipped) { + yield* closeOpenSteps(build.id); + return { kind: "skipped", reason } satisfies ImageBuildAttempt; + } const status = yield* statusNow(build.id); return status === "building" ? { kind: "started" as const } : settled(build, status); }); @@ -169,7 +186,10 @@ export const moveStartedGithubBuild = Effect.fn("Deployments.moveStartedGithubBu const [moved] = yield* drizzle.update(table).set(skipPatch(reason)) .where(and(eq(table.id, build.id), eq(table.status, "building"), eq(table.githubRunId, runId))).returning({ id: table.id }); const skipped = { kind: "skipped", reason } satisfies ImageBuildAttempt; - if (moved) return skipped; + if (moved) { + yield* closeOpenSteps(build.id); + return skipped; + } const status = yield* statusNow(build.id); // Still building without this run: a retry of this move already moved it. return status === "building" ? skipped : settled(build, status); @@ -250,6 +270,7 @@ const settleWhere = Effect.fn("Deployments.settleImageBuild")(function* (build: : { status: "cancelled" as const }; const [updated] = yield* drizzle.update(table).set({ ...patch, finishedAt: now, updatedAt: now }) .where(and(eq(table.id, build.id), eq(table.status, "building"), holder)).returning({ status: table.status }); + if (updated) yield* closeOpenSteps(build.id); return updated?.status ?? (yield* statusNow(build.id)); }); diff --git a/dashboard/src/modules/deployments/preparation-progress.test.ts b/dashboard/src/modules/deployments/preparation-progress.test.ts index 2b96cbe677..9c15530f56 100644 --- a/dashboard/src/modules/deployments/preparation-progress.test.ts +++ b/dashboard/src/modules/deployments/preparation-progress.test.ts @@ -1,5 +1,6 @@ import type { MachineId } from "@ployz/sdk"; import { expect, it } from "vitest"; +import { runtimeWatchMachineFixture } from "#/modules/runtime/runtime-watch-frame.test-fixture"; import { preparationProgressCollector } from "./preparation-progress"; const keys = (steps: readonly { build: number; key: string; error: string | null }[]) => steps.map((step) => [step.build, step.key, step.error]); @@ -28,11 +29,36 @@ it("turns phases and BuildKit steps into one step tree with attributed output", expect(progress.event({ Build: { StepOutput: { step: "sha256:a", stderr: false, text: "cached\n" } } }).output.map((row) => row.build)).toEqual([2]); expect(keys(progress.event({ Build: { Stage: "Cleanup" } }).steps)).toEqual([[2, "stage:Building", null], [2, "stage:Cleanup", null]]); expect(keys(progress.event("Transfer").steps)).toEqual([[2, "stage:Cleanup", null], [2, "transfer", null]]); - expect(progress.event({ Delivered: { image: "web:1", machine_id: "m1" as MachineId } }).output).toEqual([{ build: 2, step: "transfer", stderr: false, text: "Delivered web:1 to m1\n" }]); + const delivered = progress.event({ Delivered: { image: "web:1", service: "web", machine_id: "m1" as MachineId } }); + expect(delivered.output).toEqual([{ build: 2, step: "transfer", stderr: false, text: "Delivered web:1 to m1\n" }]); expect(keys(progress.finish())).toEqual([[2, "transfer", null]]); expect(progress.finish()).toEqual([]); }); +it("says a waited-for build slot plainly and files the push's lines under Pushing image", () => { + const progress = preparationProgressCollector(() => new Date(5_000)); + expect(progress.event({ Selected: { machine: runtimeWatchMachineFixture("m1", "hel-1"), reason: { kind: "spread" }, rejections: [] } }).steps).toEqual([]); + expect(progress.event({ Build: { Stage: "Queued" } }).steps.map((row) => row.name)).toEqual(["Waiting for a free build slot"]); + progress.event({ Build: { Stage: "Building" } }); + expect(progress.event({ Build: { Stage: "Push" } }).steps.map((row) => row.name)).toEqual(["Building", "Pushing image"]); + expect(progress.event({ Build: { Output: Array.from(Buffer.from("5f70bf18a086: Pushed\n")) } })).toMatchObject({ + steps: [], output: [{ build: 1, step: "stage:Push", text: "5f70bf18a086: Pushed\n" }], + }); +}); + +it("tells the deploy log, not the build, which Machines each image goes to", () => { + const progress = preparationProgressCollector(() => new Date(5_000), undefined, (name) => name === "web" ? "service-web" : null); + progress.event("Transfer"); + expect(progress.event({ Sending: { service: "web", machines: ["hel-2", "hel-3"] } })).toMatchObject({ + steps: [], progress: { phase: "transfer", serviceId: "service-web", message: "Sending image to hel-2, hel-3" }, + }); + expect(progress.event({ Delivered: { image: "web:1", service: "web", machine_id: "m1" as MachineId } }).progress).toMatchObject({ serviceId: "service-web", message: "Image sent" }); + // One line per image, however many Machines received it. + expect(progress.event({ Delivered: { image: "web:1", service: "web", machine_id: "m2" as MachineId } }).progress).toBeNull(); + // The Service stays out of whatever phase comes next. + expect(progress.current().serviceId).toBeNull(); +}); + it("keeps builder messages in their own row, which fails when the engine blames the build", () => { const progress = preparationProgressCollector(() => new Date(5_000)); progress.event({ Build: { Stage: "Building" } }); diff --git a/dashboard/src/modules/deployments/preparation-progress.ts b/dashboard/src/modules/deployments/preparation-progress.ts index 3c5ac9d5e5..271bcddab9 100644 --- a/dashboard/src/modules/deployments/preparation-progress.ts +++ b/dashboard/src/modules/deployments/preparation-progress.ts @@ -27,14 +27,17 @@ export type CollectorCheckpoint = typeof collectorCheckpointSchema.Type; export const BUILD_OUTPUT_KEY = "build-output"; const stageNames = new Map([ - ["Admission", "Waiting for the builder"], ["Queued", "Queued"], ["Upload", "Uploading source"], ["Preparation", "Preparing the builder"], - ["Building", "Building"], ["Output", "Loading images"], ["Cleanup", "Cleaning up"], + ["Admission", "Starting the build"], ["Queued", "Waiting for a free build slot"], ["Upload", "Uploading source"], ["Preparation", "Preparing the builder"], + ["Building", "Building"], ["Output", "Exporting image"], ["Cleanup", "Cleaning up"], ["Push", "Pushing image"], ]); const stageName = (stage: string) => stageNames.get(stage) ?? stage; export const BUILDING_KEY = "stage:Building"; /** Attempt-wide rows the engine files under the last build run: image cleanup and delivery. */ export const CLEANUP_KEY = "stage:Cleanup"; export const TRANSFER_KEY = "transfer"; +/** A Ployz-owned step starting at `at`; it ends at once unless `completedAt` is null (open). */ +export const ployzStep = (key: string, name: string, at = new Date(), completedAt: Date | null = at): BuildStepWrite => + ({ build: 0, key, name, startedAt: at, completedAt, cached: false, error: null }); /** * Which step a failed attempt is pinned on: the failed BuildKit step already @@ -60,7 +63,7 @@ const rowId = (build: number, key: string) => `${build}:${key}`; * image, attributing the run's steps and output to that Image Build. * Provider errors and rejection dumps are never logs. */ -export function preparationProgressCollector(now: () => Date = () => new Date(), resume?: CollectorCheckpoint) { +export function preparationProgressCollector(now: () => Date = () => new Date(), resume?: CollectorCheckpoint, serviceIdFor: (name: string) => string | null = () => null) { // ponytail: a multibyte character split across two resumed batches decodes as replacement characters. const decoder = new TextDecoder(); let current: PreparationProgress = { phase: "selection", serviceId: null, machineId: null, machineName: null, message: null }; @@ -71,6 +74,8 @@ export function preparationProgressCollector(now: () => Date = () => new Date(), let open: string | null = resume?.open ?? null; let build = resume?.build ?? 0; let stepFailed = resume?.stepFailed ?? false; + /** The Service whose image is on its way; only its own progress names it, never a later phase. */ + let sending: string | null = null; let finished = false; const create = (key: string, name: string): BuildStepWrite => { const row = { build, key, name, startedAt: now(), completedAt: null, cached: false, error: null }; @@ -110,9 +115,24 @@ export function preparationProgressCollector(now: () => Date = () => new Date(), current = { ...current, machineId: event.Selected.machine.id, machineName: event.Selected.machine.name, message: "Builder selected" }; return { progress: current, steps: [], output: [] }; } + // Sending an image is the deploy's, not its build's: it shows in that Service's deploy log. + if ("Sending" in event) { + const { service, machines } = event.Sending; + sending = serviceIdFor(service); + current = { ...current, phase: "transfer", message: `Sending image to ${machines.join(", ")}` }; + return { progress: { ...current, serviceId: sending }, steps: [], output: [] }; + } if ("Delivered" in event) { const row = open === null ? undefined : rows.get(open); - return { progress: null, steps: [], output: row ? [{ build: row.build, step: row.key, stderr: false, text: `Delivered ${event.Delivered.image} to ${event.Delivered.machine_id}\n` }] : [] }; + const sent = sending !== null && sending === serviceIdFor(event.Delivered.service) ? sending : null; + if (sent !== null) { + sending = null; + current = { ...current, message: "Image sent" }; + } + return { + progress: sent === null ? null : { ...current, serviceId: sent }, steps: [], + output: row ? [{ build: row.build, step: row.key, stderr: false, text: `Delivered ${event.Delivered.image} to ${event.Delivered.machine_id}\n` }] : [], + }; } if ("Platforms" in event) return none(); const build_ = event.Build; @@ -130,7 +150,12 @@ export function preparationProgressCollector(now: () => Date = () => new Date(), heading.name = build_.Target.name; return { progress: null, steps: [{ ...heading }], output: [] }; } - if ("Output" in build_) return builderLine(decoder.decode(Uint8Array.from(build_.Output), { stream: true })); + if ("Output" in build_) { + const text = decoder.decode(Uint8Array.from(build_.Output), { stream: true }); + // The push reports its own lines, outside any BuildKit step. + const pushing = open === rowId(build, stageKey("Push")) ? rows.get(open) : undefined; + return pushing ? { progress: null, steps: [], output: [{ build, step: pushing.key, stderr: false, text }] } : builderLine(text); + } if ("Step" in build_) { const step = build_.Step; stepFailed ||= step.error !== null; diff --git a/dashboard/src/modules/deployments/runtime-activities.server.ts b/dashboard/src/modules/deployments/runtime-activities.server.ts index a5eea7a593..8f21a24978 100644 --- a/dashboard/src/modules/deployments/runtime-activities.server.ts +++ b/dashboard/src/modules/deployments/runtime-activities.server.ts @@ -131,7 +131,8 @@ export const executeEnvironmentDeployment = Effect.fn( const progressContext = yield* Effect.context(); const runReport = Effect.runPromiseWith(progressContext); const persistProgress = (program: Effect.Effect) => runReport(reporting.write(program)); - const collector = preparationProgressCollector(); + const collector = preparationProgressCollector(undefined, undefined, + (name) => context.snapshots.find((snapshot) => snapshot.config.privateDns === name)?.serviceId ?? null); const cancelled = Effect.callback((resume) => { const abort = () => resume(Effect.interrupt); if (cancellation.signal.aborted) abort(); diff --git a/dashboard/src/modules/deployments/server-image-builds.server.ts b/dashboard/src/modules/deployments/server-image-builds.server.ts index 1450ca07fc..b8af437e90 100644 --- a/dashboard/src/modules/deployments/server-image-builds.server.ts +++ b/dashboard/src/modules/deployments/server-image-builds.server.ts @@ -1,6 +1,7 @@ import "@tanstack/react-start/server-only"; import type { BuildReceipt, MachineId } from "@ployz/sdk"; -import { Effect } from "effect"; +import { Effect, type Types } from "effect"; +import type { SkipReason } from "./image-build"; import { errorEvidenceFrom } from "#/lib/error-evidence"; import { PloyzPreparationError } from "#/modules/runtime/ployz.server"; import { Database, ReportingDatabase } from "#/server/database.server"; @@ -11,16 +12,13 @@ import { imageBuildWanted, loadBuildReceipts, recordServerChoice, settleImageBuild, skipUnstarted, START_WITHIN_MINUTES, type ImageBuildTarget, } from "./image-builds.server"; -import { preparationProgressCollector, type BuildStepWrite } from "./preparation-progress"; +import { ployzStep, preparationProgressCollector, type BuildStepWrite } from "./preparation-progress"; import { loadDeploymentContext } from "./runtime-hydration.repository.server"; import { connectedRuntime, oneServiceDeployment, watchDeploymentCancellation } from "./runtime-session.server"; import { acquireDeploymentSources } from "./runtime-sources.server"; /** A build that reused an image still leaves this one Build Step as its evidence. */ -export const reusedImageStep = (): BuildStepWrite => { - const now = new Date(); - return { build: 0, key: "stage:Reused", name: "Reused image", startedAt: now, completedAt: now, cached: true, error: null }; -}; +export const reusedImageStep = (): BuildStepWrite => ({ ...ployzStep("stage:Reused", "Reused image"), cached: true }); /** How one go on the Cluster ended, before the Image Build records it. */ type ClusterBuild = @@ -36,16 +34,17 @@ type ClusterBuild = * row on every exit. It stops when its attempt ends or is cancelled. */ export const buildOnServers = Effect.fn("Deployments.buildOnServers")(function* ( - build: ImageBuildTarget, candidate: Pick, startWithinMs?: number, + build: ImageBuildTarget, candidate: Pick, startWithinMs?: number, ) { const cancellation = new AbortController(); const collector = preparationProgressCollector(); const reporting = deploymentReporting(); let machineId: MachineId | null = null; + let machineName: string | undefined; let logged = false; const log = (writes: { steps: BuildStepWrite[]; output: { build: number; step: string; stderr: boolean; text: string }[] }) => { logged ||= writes.steps.length > 0; - return reporting.write(persistBuildLog(build.deploymentId, writes, build.image)); + return reporting.write(persistBuildLog(build.deploymentId, writes, { image: build.image, attempt: candidate.attempt })); }; const outcome: ClusterBuild = yield* Effect.gen(function* () { const context = yield* loadDeploymentContext(build.deploymentId); @@ -63,6 +62,7 @@ export const buildOnServers = Effect.fn("Deployments.buildOnServers")(function* if (event !== "Transfer" && "Selected" in event) { const { machine, reason } = event.Selected; machineId = machine.id; + machineName = machine.name; await Effect.runPromiseWith(progressContext)(recordServerChoice(build.id, machine.id, { machineName: machine.name, reason })); } const writes = collector.event(event); @@ -88,7 +88,10 @@ export const buildOnServers = Effect.fn("Deployments.buildOnServers")(function* yield* log({ steps, output: [] }); switch (outcome.kind) { case "queued": { - return yield* skipUnstarted(build, { builder: "servers", kind: "not_started", minutes: START_WITHIN_MINUTES }); + // The Server's name leaves the row with the skip; the skip keeps it for the log's heading. + const reason: Types.Mutable = { builder: "servers", kind: "not_started", minutes: START_WITHIN_MINUTES }; + if (machineName !== undefined) reason.machineName = machineName; + return yield* skipUnstarted(build, reason); } case "built": return yield* settleImageBuild(build, { status: "built", receipt: outcome.receipt }); case "failed": return yield* settleImageBuild(build, { status: "failed", message: outcome.message, machineId }); diff --git a/dashboard/src/modules/deployments/tables.ts b/dashboard/src/modules/deployments/tables.ts index 3d06c6dde8..f90a403f49 100644 --- a/dashboard/src/modules/deployments/tables.ts +++ b/dashboard/src/modules/deployments/tables.ts @@ -228,6 +228,11 @@ export const environmentDeploymentBuildStep = pgTable("environment_deployment_bu deploymentId: uuid("deployment_id").notNull().references(() => environmentDeployment.id, { onDelete: "cascade" }), /** The Image Build that reported the step, by image name; null for the deploy step's own preparation. */ image: text("image"), + /** + * Which Builder's go at the Image Build the step belongs to: the length of its skip trail then. + * Each is a section of the build log. 0 for the deploy step's own preparation. + */ + attempt: integer("attempt").notNull().default(0), /** Which BuildKit run of the Image Build the step belongs to; 0 before the first. One build may run several (per platform). */ build: integer("build").notNull().default(0), /** BuildKit digest or `stage:`; stable across repeated reports within one run. */ @@ -239,7 +244,7 @@ export const environmentDeploymentBuildStep = pgTable("environment_deployment_bu error: text("error"), createdAt, updatedAt, -}, (table) => [unique("environment_deployment_build_step_key_unique").on(table.deploymentId, table.image, table.build, table.key).nullsNotDistinct()]); +}, (table) => [unique("environment_deployment_build_step_key_unique").on(table.deploymentId, table.image, table.attempt, table.build, table.key).nullsNotDistinct()]); /** Append-only output attributed to one build step. */ export const environmentDeploymentBuildOutput = pgTable("environment_deployment_build_output", { diff --git a/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/DeploymentServicePanel.tsx b/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/DeploymentServicePanel.tsx index 4d40a1e4de..a2956b2e18 100644 --- a/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/DeploymentServicePanel.tsx +++ b/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/DeploymentServicePanel.tsx @@ -10,7 +10,7 @@ import { Badge } from "#/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "#/components/ui/tabs"; import type { DeploymentAttempt } from "#/modules/deployments/deployment.collection"; import { outcomeBadges } from "#/components/deployment-outcome-badges"; -import { builtOnLine, nodeOutcomeLabels, shortDeploymentId, type DeploymentNodeView } from "#/modules/deployments/deployment-view"; +import { nodeOutcomeLabels, shortDeploymentId, type DeploymentNodeView } from "#/modules/deployments/deployment-view"; import { DEPLOYMENT_SERVICE_PAGES, deploymentServicePageSchema, type DeploymentServicePage, } from "../services/$serviceId/-components/service-pages"; @@ -148,7 +148,7 @@ function DeploymentServiceDetails({ organizationSlug, deployment, serviceId, vie ] : [["Source", "None"]]} /> {source.type === "git" ? : null} diff --git a/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/canvas/DeploymentNode.tsx b/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/canvas/DeploymentNode.tsx index 3ad46aea83..bee27ad8b6 100644 --- a/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/canvas/DeploymentNode.tsx +++ b/dashboard/src/routes/_protected/cloud/$organizationSlug/_project/$projectSlug/$environmentSlug/-components/canvas/DeploymentNode.tsx @@ -11,7 +11,7 @@ import { Spinner } from "#/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger } from "#/components/ui/tooltip"; import { cn } from "#/lib/utils"; import { outcomeBadges } from "#/components/deployment-outcome-badges"; -import { builtOnLine, nodeOutcomeLabels, type Stage } from "#/modules/deployments/deployment-view"; +import { nodeOutcomeLabels, type Stage } from "#/modules/deployments/deployment-view"; import { canvasNodeTransition } from "./constants"; import { getServiceIcon, getServiceSubtitle } from "./service-node-helpers"; import type { CanvasDeploymentNodeData } from "./types"; @@ -78,10 +78,10 @@ export function DeploymentNodeCard({ data, className }: { data: CanvasDeployment {view.builtOn ? ( - }> + }> - {builtOnLine(view.builtOn)} + Built on {view.builtOn} ) : null}