fix(invariants): align InvariantModel with codebase ULID and timestamp standards
CI / push-validation (pull_request) Successful in 32s
CI / helm (pull_request) Successful in 43s
CI / build (pull_request) Successful in 1m8s
CI / lint (pull_request) Failing after 1m26s
CI / quality (pull_request) Successful in 1m39s
CI / typecheck (pull_request) Successful in 1m49s
CI / security (pull_request) Successful in 2m2s
CI / integration_tests (pull_request) Failing after 3m43s
CI / unit_tests (pull_request) Failing after 5m7s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 8s

InvariantModel used String(36) UUID-style PK instead of the codebase-
standard ULID (String(26)), and was missing the required updated_at
column present on all peer entity models.  Updated both the ORM class
and the migration DDL to match conventions:

- PK: String(36) → String(26) for ULID compatibility with resource_id,
  decision_id, checkpoint_id, job_id, etc.
- Added updated_at column (String(30)) matching NamespacedProjectModel,
  ResourceLinkModel and other entity tables
- Updated migration `m3_001_invariants_table` DDL to mirror ORM model
- Added index on updated_at for audit-query performance
This commit is contained in:
2026-05-15 04:47:31 +00:00
committed by Forgejo
parent 41523fad9d
commit 4cd5a7fec7
2 changed files with 18 additions and 5 deletions
@@ -22,12 +22,17 @@ depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Create the invariants table with index on is_active."""
"""Create the invariants table with indexes on is_active and updated_at.
The ``id`` column uses ULID (26-char string) for consistency with all
other models in the codebase (resource_id, decision_id, etc.).
"""
op.create_table(
"invariants",
sa.Column("id", sa.String(36), nullable=False),
sa.Column("id", sa.String(26), nullable=False),
sa.Column("description", sa.Text, nullable=False),
sa.Column("created_at", sa.String(30), nullable=False),
sa.Column("updated_at", sa.String(30), nullable=False),
sa.Column(
"is_active",
sa.Boolean,
@@ -38,9 +43,11 @@ def upgrade() -> None:
sa.CheckConstraint("description != ''"),
)
op.create_index("ix_invariants_is_active", "invariants", ["is_active"])
op.create_index("ix_invariants_updated_at", "invariants", ["updated_at"])
def downgrade() -> None:
"""Drop the invariants table."""
op.drop_index("ix_invariants_updated_at", table_name="invariants")
op.drop_index("ix_invariants_is_active", table_name="invariants")
op.drop_table("invariants")
@@ -1315,8 +1315,9 @@ class InvariantModel(Base): # type: ignore[misc]
"""SQLAlchemy database model for global invariants.
Stores user-defined constraint rules that must hold true across all
planning sessions. Each invariant carries a UUID identifier, a human-
readable description, and an active flag for soft-deletion (is_active).
planning sessions. Each invariant carries a ULID identifier, a human-
readable description, an active flag for soft-deletion (is_active), and
audit timestamps.
Mapped to table ``invariants`` (migration ``m3_001_invariants_table``).
"""
@@ -1324,9 +1325,12 @@ class InvariantModel(Base): # type: ignore[misc]
__allow_unmapped__ = True
__tablename__ = "invariants"
id = Column(String(36), primary_key=True)
# PK: ULID (26-char string) — consistent with all other models in the
# codebase (resource_id, decision_id, checkpoint_id, job_id, etc.).
id = Column(String(26), primary_key=True)
description = Column(Text, nullable=False)
created_at = Column(String(30), nullable=False)
updated_at = Column(String(30), nullable=False)
is_active = Column(
Boolean,
nullable=False,
@@ -1340,6 +1344,8 @@ class InvariantModel(Base): # type: ignore[misc]
return (
f"InvariantModel(id={self.id!r}, "
f"description={self.description!r}, "
f"created_at={self.created_at!r}, "
f"updated_at={self.updated_at!r}, "
f"is_active={self.is_active})"
)