Skip to content

fix: DeploymentStatus ORM binds by member name, Postgres enum expects .value#204

Draft
shehabyasser-scale wants to merge 1 commit intomainfrom
fix/deploymentstatus-enum-values-callable
Draft

fix: DeploymentStatus ORM binds by member name, Postgres enum expects .value#204
shehabyasser-scale wants to merge 1 commit intomainfrom
fix/deploymentstatus-enum-values-callable

Conversation

@shehabyasser-scale
Copy link
Copy Markdown

Summary

One-line fix to the DeploymentORM.status column — pass values_callable= so SQLAlchemy serializes by the enum's .value instead of its member name, matching the Postgres enum created by the companion migration.

Why

Migration agentex/database/migrations/alembic/versions/2026_03_30_1900_deployments_4a9b7787ccd7.py:29 creates the deploymentstatus enum with 'Pending', 'Ready', 'Failed'. The Python enum uses the same strings as .values: PENDING = "Pending", etc.

But the ORM column at agentex/src/adapters/orm.py:241 was declared as plain SQLAlchemyEnum(DeploymentStatus), and SQLAlchemy's default is to serialize Enum members by name. So every INSERT tried to write "READY" / "PENDING" / "FAILED" into a column that only accepts "Ready" / "Pending" / "Failed", and failed with:

asyncpg.exceptions.InvalidTextRepresentationError:
  invalid input value for enum deploymentstatus: "READY"

Introduced in #181. Any agent pod that registers with AGENTEX_DEPLOYMENT_ID (SGP's versioned-deployment flow) crash-loops on startup because register_agent gets a 500, Uvicorn exits with Application startup failed, and k8s restarts the pod forever. Observed on sgp-dev today hitting every agent on the new registration path.

Fix

     status = Column(
-        SQLAlchemyEnum(DeploymentStatus),
+        SQLAlchemyEnum(
+            DeploymentStatus,
+            values_callable=lambda enum_cls: [e.value for e in enum_cls],
+        ),
         nullable=False,
         default=DeploymentStatus.PENDING,
     )

Added a code comment calling out the coupling to the migration so future readers don't re-break this.

Test plan

  • Unit tests in agentex/tests/ still green locally (make test or equivalent)
  • Fresh agent deploy on sgp-dev with AGENTEX_DEPLOYMENT_ID set — pod registers cleanly, deployment row lands with status = 'Ready', SGP rollout reaches healthy
  • Existing agents using the legacy agent.acp_url registration path (no deployment_id) continue to work unchanged
  • Promote flow still works — DeploymentStatus.READY comparisons in deployment_repository.py:96-99 still match DB values round-tripped through this binding

Linked

🤖 Generated with Claude Code

Migration 2026_03_30_1900_deployments_4a9b7787ccd7 creates the Postgres
deploymentstatus enum with the string values (Pending/Ready/Failed), but
the ORM column was declared as SQLAlchemyEnum(DeploymentStatus) without
values_callable=. SQLAlchemy's default behavior serializes enum members by
NAME (PENDING/READY/FAILED), so every INSERT into deployments failed with:

    asyncpg.exceptions.InvalidTextRepresentationError:
      invalid input value for enum deploymentstatus: "READY"

This hit every agent registered after PR #181 landed (the versioned-
deployment rollout that introduced the deployments table). Agent pods
crash-looped on startup because Application startup failed after the
registration 500, and SGP deploys reported unhealthy.

Passing values_callable=lambda enum_cls: [e.value for e in enum_cls]
makes SQLAlchemy emit .value ("Ready") to match the migration's enum.
Added a code comment pointing at the migration file to make the coupling
obvious to future readers.

Linear: EE-45

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant