feat(ledger): code_shapes — the shape ledger schema (#2787, milestone 294 step 1)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 13s
CI & Build / integration (push) Successful in 25s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 45s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 13s
CI & Build / integration (push) Successful in 25s
CI & Build / Python tests (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 45s
The accounting half of the pattern system (governing note 2786): the snippet library records canon (small), this table accounts for EVERY extracted shape (total). Identity is (project, repo_key, path, symbol, kind) — kind included because one file can define '.foo' (css) and 'foo' (sym) as distinct shapes. Status vocabulary: canonical / instance / variant / exempt / unclassified, with unclassified as the default and THE todo state; classifications carry who judged (agent|audit|hook|mechanical|import), when, and the why for variants/exemptions. first/last-seen commits + vanished_at keep history instead of deleting it; a rename reads as vanish+new (accepted for v1). snippet_id is SET NULL on snippet deletion so accounting rows outlive their target and rejoin the todo via the step-2 sync, never dangle silently. Backups: v7 carries code_shapes (judgment data, worth moving) — full and per-user export sections, and a restore that keeps a judgment only when its snippet survives the id re-mapping, downgrading to unclassified otherwise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""The shape ledger: code_shapes (#2787, milestone 294)
|
||||
|
||||
Revision ID: 0079
|
||||
Revises: 0078
|
||||
Create Date: 2026-08-19
|
||||
|
||||
The accounting half of the pattern system (governing note 2786): the snippet
|
||||
library records canon (small); this table accounts for EVERY shape the
|
||||
coverage extractor finds in a bound repo (total). Rows arrive `unclassified`
|
||||
from the coverage sync (step 2) and gain judgments — canonical / instance /
|
||||
variant / exempt — from audits, hooks, and the mechanical proposer.
|
||||
Unclassified IS the todo list.
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = "0079"
|
||||
down_revision = "0078"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"code_shapes",
|
||||
sa.Column("id", sa.Integer(), primary_key=True),
|
||||
sa.Column(
|
||||
"project_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("projects.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column("repo_key", sa.Text(), nullable=False),
|
||||
sa.Column("path", sa.Text(), nullable=False),
|
||||
sa.Column("symbol", sa.Text(), nullable=False),
|
||||
sa.Column("kind", sa.Text(), nullable=False),
|
||||
sa.Column("status", sa.Text(), nullable=False, server_default="unclassified"),
|
||||
sa.Column(
|
||||
"snippet_id",
|
||||
sa.BigInteger(),
|
||||
sa.ForeignKey("notes.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("reason", sa.Text(), nullable=True),
|
||||
sa.Column("classified_by", sa.Text(), nullable=True),
|
||||
sa.Column("classified_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("first_seen_commit", sa.Text(), nullable=False, server_default=""),
|
||||
sa.Column("last_seen_commit", sa.Text(), nullable=False, server_default=""),
|
||||
sa.Column("vanished_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.UniqueConstraint(
|
||||
"project_id", "repo_key", "path", "symbol", "kind",
|
||||
name="uq_code_shapes_identity",
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
"ix_code_shapes_project_status", "code_shapes", ["project_id", "status"]
|
||||
)
|
||||
op.create_index("ix_code_shapes_snippet", "code_shapes", ["snippet_id"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index("ix_code_shapes_snippet", table_name="code_shapes")
|
||||
op.drop_index("ix_code_shapes_project_status", table_name="code_shapes")
|
||||
op.drop_table("code_shapes")
|
||||
Reference in New Issue
Block a user