feat: Phase 1 Group 9 — enforce NOT NULL on all account_id columns

All previously-nullable account_id columns are now NOT NULL.
tree_embeddings and feedback backfilled before constraint applied.
Global content assigned to platform sentinel account (00000000-...-0001)
in preceding migration.

Tables updated: users, trees, tree_categories, tree_tags,
step_categories, step_library, tree_embeddings, feedback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-04-09 05:34:32 +00:00
parent b4b8c67d3b
commit 42937b24a4
10 changed files with 139 additions and 17 deletions

View File

@@ -7,7 +7,7 @@ real PostgreSQL test DB (same as all other integration tests).
import pytest
import uuid
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy import select, text
from app.models.account import Account
from app.models.user import User
@@ -506,3 +506,40 @@ async def test_platform_steps_table_exists_and_has_no_account_id(test_db: AsyncS
columns = {row[0] for row in result.fetchall()}
assert 'id' in columns, "platform_steps.id must exist"
assert 'account_id' not in columns, "platform_steps must not have account_id (global content)"
# ── Group 9: SET NOT NULL on existing nullable columns ────────────────────────
@pytest.mark.asyncio
async def test_tree_account_id_is_not_null(test_db: AsyncSession):
"""trees.account_id must be NOT NULL after Phase 1 — enforced at DB level."""
from sqlalchemy.exc import IntegrityError
with pytest.raises(IntegrityError):
test_db.add(Tree(
name="Bad tree",
# account_id intentionally omitted
author_id=None,
visibility="private",
tree_type="troubleshooting",
tree_structure={},
is_active=True,
status="draft",
))
await test_db.flush()
@pytest.mark.asyncio
async def test_user_account_id_is_not_null(test_db: AsyncSession):
"""users.account_id must be NOT NULL after Phase 1."""
from sqlalchemy.exc import IntegrityError
with pytest.raises(IntegrityError):
test_db.add(User(
email=f"orphan-{uuid.uuid4().hex[:6]}@example.com",
name="Orphan",
password_hash=get_password_hash("x"),
is_active=True,
role="engineer",
account_role="engineer",
# account_id intentionally omitted
))
await test_db.flush()