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

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:
2026-08-19 19:25:25 -04:00
co-authored by Claude Fable 5
parent 1faf8f3ece
commit 19fdc9aa89
6 changed files with 282 additions and 9 deletions
+9 -7
View File
@@ -13,17 +13,19 @@ import pytest
from scribe.services import backup
def test_backup_version_is_v6():
"""v6 added note_supersessions (#278). The bump is the point of the test —
def test_backup_version_is_v7():
"""v7 added code_shapes (#2787). The bump is the point of the test —
a payload section added without moving the version produces backups that
are structurally different and indistinguishable by inspection."""
assert backup.BACKUP_VERSION == 6
assert backup.BACKUP_VERSION == 7
def test_not_included_lists_the_known_gaps():
# The deferred tables must be surfaced explicitly, not silently dropped.
# forge_connections is excluded as CREDENTIALS (api_keys reasoning): a
# backup that carries forge tokens is a token-exfiltration file (#2778).
for table in ("groups", "project_shares", "note_shares", "api_keys",
"note_embeddings", "retrieval_logs"):
"note_embeddings", "retrieval_logs", "forge_connections"):
assert table in backup._NOT_INCLUDED
@@ -105,14 +107,14 @@ async def test_export_full_backup_contains_every_declared_section():
assert out["version"] == backup.BACKUP_VERSION
assert out["scope"] == "full"
assert "api_keys" in out["_not_included"]
# The sections v2 silently dropped, the six v5 added, and v6's
# note_supersessions (all empty here).
# The sections v2 silently dropped, the six v5 added, v6's
# note_supersessions, and v7's code_shapes (all empty here).
for key in ("rulebooks", "rulebook_topics", "rules",
"rulebook_subscriptions", "rule_suppressions",
"topic_suppressions",
"systems", "record_systems", "design_systems",
"design_tokens", "note_usage_events", "repo_bindings",
"note_supersessions"):
"note_supersessions", "code_shapes"):
assert key in out, f"missing export section: {key}"
assert out[key] == []