"""folder_summaries.manually_edited: owner-edited descriptions (phase 97, task 01) Revision ID: 0018 Revises: 0017 Create Date: 2026-09-11 Phase 97 (the RAG view shows the catalog as the drill-down tree the agent sees, with editable folder descriptions): the owner can edit — or clear — any directory's description, just like a file's summary (phase 57's affordance). The owner's words are OWNER CONTENT: the sync-time generator must never silently rewrite them. This migration adds the one flag that makes that enforceable — a single additive, fully reversible column (A13), no other schema change: * ``folder_summaries.manually_edited`` — BOOLEAN NOT NULL, server default ``false``: ``true`` only while the row's description was written by the owner (``PATCH /api/folders/summary`` — phase 97, task 03 — the ONLY writer; the generator never sets it). The generator's two rules for a manual row (``app.rag.folder_summaries``): SKIPPED on regeneration (no ``lite`` burn on owner text — counted ``kept_manual`` in the stats) and NEVER pruned (owner content persists until the owner clears it — even a manual row for a folder that dropped below 2 documents). Pre-0018 rows backfill ``false``: an AI-written row stays an AI row. Clearing the description DELETES the row — the next KB-changing sync regenerates an AI description (the reset path; no separate regenerate button in v1). """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "0018" down_revision = "0017" branch_labels = None depends_on = None def upgrade() -> None: op.add_column( "folder_summaries", sa.Column( "manually_edited", sa.Boolean(), server_default=sa.text("false"), nullable=False, ), ) def downgrade() -> None: # The column is the only 0018 artefact — dropping it (the rows and # their summaries survive) leaves 0017's schema byte-identical # (A13, fully reversible). op.drop_column("folder_summaries", "manually_edited")