fix(models): use enum values instead of names for PostgreSQL

Add values_callable to all enum columns so SQLAlchemy serializes using
the enum's .value (lowercase) instead of .name (uppercase). PostgreSQL
enum types defined in migrations use lowercase values.

Fixes: invalid input value for enum autonomy_level: "MILESTONE"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-06 02:53:45 +01:00
parent fcb0a5f86a
commit f9a72fcb34
4 changed files with 48 additions and 10 deletions

View File

@@ -62,7 +62,11 @@ class AgentInstance(Base, UUIDMixin, TimestampMixin):
# Status tracking # Status tracking
status: Column[AgentStatus] = Column( status: Column[AgentStatus] = Column(
Enum(AgentStatus, name="agent_status"), Enum(
AgentStatus,
name="agent_status",
values_callable=lambda x: [e.value for e in x],
),
default=AgentStatus.IDLE, default=AgentStatus.IDLE,
nullable=False, nullable=False,
index=True, index=True,

View File

@@ -59,7 +59,9 @@ class Issue(Base, UUIDMixin, TimestampMixin):
# Issue type (Epic, Story, Task, Bug) # Issue type (Epic, Story, Task, Bug)
type: Column[IssueType] = Column( type: Column[IssueType] = Column(
Enum(IssueType, name="issue_type"), Enum(
IssueType, name="issue_type", values_callable=lambda x: [e.value for e in x]
),
default=IssueType.TASK, default=IssueType.TASK,
nullable=False, nullable=False,
index=True, index=True,
@@ -78,14 +80,22 @@ class Issue(Base, UUIDMixin, TimestampMixin):
# Status and priority # Status and priority
status: Column[IssueStatus] = Column( status: Column[IssueStatus] = Column(
Enum(IssueStatus, name="issue_status"), Enum(
IssueStatus,
name="issue_status",
values_callable=lambda x: [e.value for e in x],
),
default=IssueStatus.OPEN, default=IssueStatus.OPEN,
nullable=False, nullable=False,
index=True, index=True,
) )
priority: Column[IssuePriority] = Column( priority: Column[IssuePriority] = Column(
Enum(IssuePriority, name="issue_priority"), Enum(
IssuePriority,
name="issue_priority",
values_callable=lambda x: [e.value for e in x],
),
default=IssuePriority.MEDIUM, default=IssuePriority.MEDIUM,
nullable=False, nullable=False,
index=True, index=True,
@@ -132,7 +142,11 @@ class Issue(Base, UUIDMixin, TimestampMixin):
# Sync status with external tracker # Sync status with external tracker
sync_status: Column[SyncStatus] = Column( sync_status: Column[SyncStatus] = Column(
Enum(SyncStatus, name="sync_status"), Enum(
SyncStatus,
name="sync_status",
values_callable=lambda x: [e.value for e in x],
),
default=SyncStatus.SYNCED, default=SyncStatus.SYNCED,
nullable=False, nullable=False,
# Note: Index defined in __table_args__ as ix_issues_sync_status # Note: Index defined in __table_args__ as ix_issues_sync_status

View File

@@ -35,28 +35,44 @@ class Project(Base, UUIDMixin, TimestampMixin):
description = Column(Text, nullable=True) description = Column(Text, nullable=True)
autonomy_level: Column[AutonomyLevel] = Column( autonomy_level: Column[AutonomyLevel] = Column(
Enum(AutonomyLevel, name="autonomy_level"), Enum(
AutonomyLevel,
name="autonomy_level",
values_callable=lambda x: [e.value for e in x],
),
default=AutonomyLevel.MILESTONE, default=AutonomyLevel.MILESTONE,
nullable=False, nullable=False,
index=True, index=True,
) )
status: Column[ProjectStatus] = Column( status: Column[ProjectStatus] = Column(
Enum(ProjectStatus, name="project_status"), Enum(
ProjectStatus,
name="project_status",
values_callable=lambda x: [e.value for e in x],
),
default=ProjectStatus.ACTIVE, default=ProjectStatus.ACTIVE,
nullable=False, nullable=False,
index=True, index=True,
) )
complexity: Column[ProjectComplexity] = Column( complexity: Column[ProjectComplexity] = Column(
Enum(ProjectComplexity, name="project_complexity"), Enum(
ProjectComplexity,
name="project_complexity",
values_callable=lambda x: [e.value for e in x],
),
default=ProjectComplexity.MEDIUM, default=ProjectComplexity.MEDIUM,
nullable=False, nullable=False,
index=True, index=True,
) )
client_mode: Column[ClientMode] = Column( client_mode: Column[ClientMode] = Column(
Enum(ClientMode, name="client_mode"), Enum(
ClientMode,
name="client_mode",
values_callable=lambda x: [e.value for e in x],
),
default=ClientMode.AUTO, default=ClientMode.AUTO,
nullable=False, nullable=False,
index=True, index=True,

View File

@@ -57,7 +57,11 @@ class Sprint(Base, UUIDMixin, TimestampMixin):
# Status # Status
status: Column[SprintStatus] = Column( status: Column[SprintStatus] = Column(
Enum(SprintStatus, name="sprint_status"), Enum(
SprintStatus,
name="sprint_status",
values_callable=lambda x: [e.value for e in x],
),
default=SprintStatus.PLANNED, default=SprintStatus.PLANNED,
nullable=False, nullable=False,
index=True, index=True,