S1: iso() datetime helper + one shared colour normalizer (colors.py)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 5s
CI & Build / Python tests (push) Successful in 11s
CI & Build / Build & push image (push) Successful in 29s

M9 section S1, commit 3 — two more shared-toolkit pieces:

- common.iso(dt): the "x.isoformat() if x else None" idiom (repeated 20+ times
  across every serializer) as one helper. Adopted in Note.serialize() and the
  revision serializer; other serializers adopt it in their sections.
- colors.py: NOTE_COLORS (canonical, on the model) + a single normalize_color().
  notes.py now imports the palette + normalizer from here and drops its local
  copy. labels.py's identical LABEL_COLORS/_normalize_label_color fold into this
  in the Organize section (S3); sync in S4.

normalize_color and NOTE_COLORS remain importable from thoughtsync.notes (used by
tests + sync), so nothing downstream breaks. common has no in-app imports, so the
model→common→colors chain has no cycle. Behavior-preserving.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
2026-07-23 19:33:07 -04:00
co-authored by Claude Opus 4.8
parent 6abc82c783
commit 61f7c40db7
4 changed files with 30 additions and 10 deletions
+4 -3
View File
@@ -8,6 +8,7 @@ from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from . import Base
from ..common import iso
# The Keep-style palette. Stored as a key string, so the actual tints live in the
# frontend and can change without a schema migration.
@@ -82,8 +83,8 @@ class Note(Base):
"pinned": self.pinned,
"archived": self.archived,
"trashed": self.deleted_at is not None,
"remind_at": self.remind_at.isoformat() if self.remind_at else None,
"remind_at": iso(self.remind_at),
"recurrence": self.recurrence,
"created_at": self.created_at.isoformat() if self.created_at else None,
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
"created_at": iso(self.created_at),
"updated_at": iso(self.updated_at),
}