소스 정보
- 저장소
- lukemcqueen/hermes-cortex
- 최근 소스 활동
- 2026년 8월 22일 20:24
- 감지된 SKILL.md 언어
- 영어
- 스타
- 4
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/lukemcqueen/hermes-cortex --skill alembic-postgres-migrations명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | alembic-postgres-migrations |
| description | Use when debugging Alembic Postgres migration failures. |
| version | 1.1.0 |
| category | devops |
| author | Hermes Cortex |
| license | MIT |
| platforms | ["linux","macos"] |
| metadata | {"hermes":{"tags":["alembic","sqlalchemy","postgres","migrations","schema","enums","ddl"],"category":"devops","related_skills":["dockerized-stack-recovery","root-cause-debugging"],"aliases":["alembic-enum-double-create"]}} |
Author, review, and debug Alembic migrations for SQLAlchemy + PostgreSQL backends.
DuplicateObject, type "X" already exists, relation "X" already existsalembic upgrade head stepOne enum creation path per migration. A PostgreSQL enum type can be created two ways in SQLAlchemy:
sa.Enum("a","b", name="my_enum").create(op.get_bind())sa.Enum(..., name="my_enum", create_constraint=True) — the create_constraint=True flag ALSO emits CREATE TYPE during op.create_table (via the table's _on_table_create → CreateEnumType event).
Doing BOTH in one migration fails on a fresh DB with psycopg2.errors.DuplicateObject: type "my_enum" already exists — the explicit create succeeds, then the table creation tries to create the type a second time. Pick one path. Prefer the column definitions (drop the explicit .create() calls). If you keep explicit creates, the columns must not re-create the type.Fresh-DB failures roll back the WHOLE chain. Alembic assumes transactional DDL on Postgres: if migration m15 fails, the DDL from m10–m14 in that run is UNDONE and alembic_version stays at the last committed revision (e.g. m10). Never trust partial "Running upgrade …" log lines as progress — the whole batch rolled back. Tables and enums created earlier in the same failed run will NOT exist afterward.
Verify DB state with psql before theorizing. The api's own error message can mislead (it re-runs the chain every restart, so logs interleave multiple attempts):
SELECT version_num FROM alembic_version; — where the chain actually stoppedSELECT typname FROM pg_type WHERE typname LIKE '<prefix>%'; — whether enum types exist (absent after rollback)\dt — which tables exist
Get the container name right first (docker ps — compose names aren't project-service-1 if container_name: is set).Fix the migration file, never hand-stamp the DB. INSERT INTO alembic_version or dropping types manually only defers the failure to the next fresh checkout/volume/CI run. The migration must be idempotent enough to run clean on an empty database — that's the contract.
Test through the real entrypoint. alembic upgrade from the repo isn't the shipping path; the container entrypoint that runs alembic upgrade head on every start is. Restart that container and watch its logs. For speed on a baked image, hot-fix via (see ); for durability, rebuild the image.
A column named text on any model shadows sqlalchemy.sql.text() — the
aliased from sqlalchemy.sql import text in the module is inaccessible because
the column binding wins. This surfaces as a TypeError: 'Column' object is not callable at import time (since SQLAlchemy eagerly evaluates class bodies).
Pattern:
from sqlalchemy import Column, Text
from sqlalchemy.sql import func, text # ← text() is available here
class Translation(Base):
text = Column(Text, nullable=False) # ← shadows text() above
canonical = Column(Boolean, server_default=text("false")) # TypeError!
Fix: import with an alias that won't collide:
from sqlalchemy.sql import func, text as sql_text
canonical = Column(Boolean, server_default=sql_text("false"))
Scope: Any column name that matches a commonly-imported sqlalchemy.sql
function — func, text, literal, case, cast, type_, select —
could shadow the utility. The text collision is the most frequent because
text (data) and text() (SQL expression) are both ubiquitous.
Detection: The API container crash-loops on startup with TypeError: 'Column' object is not callable pointed at the model line. The migration
env.py won't even import. Check the model file for column names matching
SQLAlchemy function imports.
When two migrations share the same down_revision, alembic detects multiple
heads and alembic upgrade head refuses to proceed. To find the actual DB
head and relinearize:
for f in migrations/versions/*.py; do
r=$(grep -E '^revision' "$f" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
d=$(grep -E '^down_revision' "$f" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
echo "$r <- $d ($(basename $f))"
done
alembic current from the running
container — note the database may be behind the repo).down_revision must point to the DB's actual
current revision, not the repo's newest head. This creates a single linear
chain.alembic heads returns exactly one revision, and alembic upgrade head from a fresh DB applies all migrations.sa.Enum(...).create() that duplicates a column-level enum with create_constraint=True?downgrade() drop every enum/table the upgrade creates (and in dependency-safe order)?alembic heads returns exactly one revision; two devs branching = merge revision neededcheck-heads.py-style gate in CI/Dockerfile catches fork-merge issues before runtimereferences/fresh-db-migration-recovery.md — worked example: the notification_type DuplicateObject crash-loop, full diagnosis sequence, and the fix patterndocker cpdockerized-stack-recoveryEnums named in column types must match the model. The migration's column Enum (name="notification_type") and the ORM model's Enum(NotificationType, name="notification_type") must agree on values — drift surfaces as opaque failures at query time, not at migration time.