refactor(scribe): retire calendar/events + person/place/list entities (backend)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 11s
CI & Build / integration (push) Successful in 30s
CI & Build / Python tests (push) Failing after 31s
CI & Build / Build & push image (push) Has been skipped

Narrow Scribe to a Claude-Code work system-of-record (milestone #194,
decision note #1759). Wholesale removal per rule #22 — backend + schema half.

Calendar/events + CalDAV: delete models/event, services/{events,caldav,
caldav_sync}, routes/events, mcp/tools/events; strip event branches from
backup (bump v3->v4), dashboard (upcoming_events), trash, recent, and the
mcp server read-only allowlist + instructions.

Typed entities (person/place/list): delete mcp/tools/entities; drop the
notes.metadata (entity_meta) column from model/service/routes and the
knowledge browse service. note_type STAYS — it also marks 'process' notes.

Scheduler: event_scheduler -> recurrence_scheduler, keeping only the
recurring-task spawn job (drops event reminders + CalDAV sync).

Schema: migration 0069 drops the events table + notes.metadata column +
orphan caldav settings rows (faithful downgrade recreates them).

KEEP: recurrence.py (task recurrence), notifications task reminders, graph
view, and every work surface. Frontend + plugin/docs true-up follow next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPtbSzA4JLMAKgFZ8VTg7Q
This commit is contained in:
2026-07-19 13:29:14 -04:00
parent f6629d4bcf
commit b49efdcb11
33 changed files with 194 additions and 3453 deletions
+3 -24
View File
@@ -14,7 +14,6 @@ from sqlalchemy import or_, select, update
from scribe.models import async_session
from scribe.models.note import Note
from scribe.models.event import Event
from scribe.models.project import Project
from scribe.models.milestone import Milestone
from scribe.models.rulebook import Rulebook, RulebookTopic, Rule
@@ -23,7 +22,6 @@ from scribe.models.rulebook import Rulebook, RulebookTopic, Rule
_MODEL_FOR = {
"note": Note,
"task": Note,
"event": Event,
"project": Project,
"milestone": Milestone,
"rulebook": Rulebook,
@@ -59,7 +57,7 @@ def _owner_clause(model, user_id: int):
select(Project.id).where(Project.user_id == user_id)
),
)
# Note, Event, Project, Milestone all carry user_id directly.
# Note, Project, Milestone all carry user_id directly.
return model.user_id == user_id
@@ -121,8 +119,6 @@ async def _cascade(session, user_id: int, etype: str, eid: int, batch: str, now)
frontier = [c for c in children if c not in ids]
ids.extend(frontier)
await _set(session, Note, [Note.user_id == user_id, Note.id.in_(ids)], batch, now)
elif etype == "event":
await _set(session, Event, [Event.user_id == user_id, Event.id == eid], batch, now)
elif etype == "rulebook":
topic_ids = (await session.execute(
select(RulebookTopic.id)
@@ -149,35 +145,18 @@ async def delete(user_id: int, entity_type: str, entity_id: int) -> str | None:
"""
batch = str(uuid.uuid4())
now = datetime.now(timezone.utc)
caldav_event: tuple[str, str] | None = None
async with async_session() as session:
if not await _exists_alive(session, user_id, entity_type, entity_id):
return None
# Capture CalDAV linkage before soft-deleting so we can propagate the
# deletion to the external server (the row stays present locally).
if entity_type == "event":
row = (await session.execute(
select(Event.caldav_uid, Event.title).where(
Event.id == entity_id, Event.user_id == user_id
)
)).first()
if row and row[0]:
caldav_event = (row[0], row[1])
await _cascade(session, user_id, entity_type, entity_id, batch, now)
await session.commit()
# Without this the soft-delete only hides the event locally and the remote
# copy lingers forever (and re-appears on any client syncing that server).
if caldav_event:
import asyncio
from scribe.services.events import _push_delete
asyncio.create_task(_push_delete(caldav_event[0], caldav_event[1], user_id))
return batch
# All soft-deletable models, and their trash-listing type label.
_ALL = [Note, Event, Project, Milestone, Rulebook, RulebookTopic, Rule]
_ALL = [Note, Project, Milestone, Rulebook, RulebookTopic, Rule]
_TYPE = {
Note: "note", Event: "event", Project: "project", Milestone: "milestone",
Note: "note", Project: "project", Milestone: "milestone",
Rulebook: "rulebook", RulebookTopic: "topic", Rule: "rule",
}