Files
FabledCurator/backend/app/models/__init__.py
T
bvandeusenandClaude Opus 5 4fe792b61c
CI / extension-version (push) Successful in 3s
CI / lint (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 8s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 39s
Build images / build-web (push) Successful in 1m14s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 2m18s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m21s
feat: platform_membership — the learned roster of what the account pays for (milestone 387 step C1)
FC knows which creators it was TOLD to follow and nothing about which
ones the operator is subscribed to. Those two sets drift both ways and
neither drift is currently visible: a subscription FC doesn't track is
content the operator believes they're archiving and aren't, and a
source walked after the subscription lapsed is requests spent on a wall
reported as a creator gone quiet.

Sibling of service_seen (milestone 365) and the same insight — an
absence is only observable against a record of presence. touch_membership
reuses the recorded touch_service shape (snippet 3447): upsert rather
than read-modify-write, first_seen_at deliberately outside the update
set because it's the one field that makes a later DISAPPEARANCE
readable as a lapse rather than as a creator we never knew.

Nothing populates it yet, and that's the intended intermediate state.
The sweep (C3) needs a client seam (C2) that needs Patreon's real
response characterised from a captured sample (C0), which needs the
operator's browser session. The table's SHAPE doesn't wait on that,
because it's deliberately free-form exactly where C0's findings would
otherwise dictate a column.

status is an unconstrained String holding the PLATFORM's own word, not
a normalised FC value. Rule 36 considered and declined, same reasoning
service_seen.kind records: the vocabulary isn't ours to invent, and
picking a lowest-common-denominator enum before any platform has been
characterised would bake a guess into the schema. The service owns the
whitelist and the mapping; the column owns the evidence.

MEMBERSHIP_STATUS ships EMPTY, guarded by a test that fails if anyone
adds an entry — every one must come from a characterised response, not
from API docs. That's rule 130 at the one place it's easiest to break,
and the failure message says so.

has_paid_access returns None, never False, for a word it hasn't been
taught. The difference is load-bearing: False means the operator lost
access, which C4 turns into an offer to disable the source, so
asserting it from an unrecognised word would tell them to cancel a
subscription they're still paying for.

Retention decided here rather than deferred (rule 89): a membership
that stops appearing is aged out on time, never deleted on absence —
deleting would destroy the signal at the moment it became interesting.

Rule 90 check, done on the right thing this time: the per-test TRUNCATE
teardown derives its table list from Base.metadata.sorted_tables, so
the new table is picked up automatically; test_models asserts a subset,
so it doesn't break. 0091 follows 0090 on the collapsed baseline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LNXXULQDjVZmbuNa2G9mD9
2026-09-10 10:58:25 -04:00

96 lines
2.9 KiB
Python

"""All ORM models. Import this module to make every model visible to Alembic."""
from .app_setting import AppSetting
from .artist import Artist
from .artist_visit import ArtistVisit
from .backup_run import BackupRun
from .base import Base
from .character_prototype import CcipPrototypeState, CharacterPrototype
from .credential import Credential
from .download_event import DownloadEvent
from .external_link import ExternalLink
from .gpu_job import GpuJob
from .head_auto_apply_run import HeadAutoApplyRun
from .head_metric import HeadMetric
from .head_metrics_snapshot import HeadMetricsSnapshot
from .head_training_run import HeadTrainingRun
from .image_provenance import ImageProvenance
from .image_record import ImageRecord
from .image_region import ImageRegion
from .import_batch import ImportBatch
from .import_settings import ImportSettings
from .import_task import ImportTask
from .library_audit_run import LibraryAuditRun
from .ml_settings import MLSettings
from .patreon_failed_media import PatreonFailedMedia
from .patreon_seen_media import PatreonSeenMedia
from .pixiv_failed_media import PixivFailedMedia
from .pixiv_seen_media import PixivSeenMedia
from .platform_membership import PlatformMembership
from .post import Post
from .post_attachment import PostAttachment, attachment_download_url
from .presentation_review import PresentationReview
from .series_chapter import SeriesChapter
from .series_page import SeriesPage
from .series_suggestion import SeriesSuggestion
from .service_seen import ServiceSeen
from .source import Source
from .subscribestar_failed_media import SubscribeStarFailedMedia
from .subscribestar_seen_media import SubscribeStarSeenMedia
from .tag import Tag, TagKind, image_tag
from .tag_alias import TagAlias
from .tag_head import TagHead
from .tag_positive_confirmation import TagPositiveConfirmation
from .tag_suggestion_rejection import TagSuggestionRejection
from .task_run import TaskRun
__all__ = [
"Base",
"AppSetting",
"Artist",
"ArtistVisit",
"BackupRun",
"Source",
"Credential",
"PatreonFailedMedia",
"PatreonSeenMedia",
"PixivFailedMedia",
"PixivSeenMedia",
"SubscribeStarFailedMedia",
"SubscribeStarSeenMedia",
"Post",
"PostAttachment",
"attachment_download_url",
"PresentationReview",
"SeriesChapter",
"SeriesPage",
"SeriesSuggestion",
"PlatformMembership",
"ServiceSeen",
"ImageRecord",
"ImageProvenance",
"ImageRegion",
"Tag",
"TagKind",
"image_tag",
"DownloadEvent",
"ExternalLink",
"GpuJob",
"ImportBatch",
"ImportTask",
"ImportSettings",
"LibraryAuditRun",
"MLSettings",
"HeadAutoApplyRun",
"HeadMetric",
"HeadMetricsSnapshot",
"HeadTrainingRun",
"TagAlias",
"TagHead",
"CharacterPrototype",
"CcipPrototypeState",
"TagPositiveConfirmation",
"TagSuggestionRejection",
"TaskRun",
]