Skip to content

feat(trigger-service): store adapters + provider wiring (TS-IMPL-008)#661

Merged
toddysm merged 2 commits into
mainfrom
ts-impl-008-store-adapters
Jun 5, 2026
Merged

feat(trigger-service): store adapters + provider wiring (TS-IMPL-008)#661
toddysm merged 2 commits into
mainfrom
ts-impl-008-store-adapters

Conversation

@toddysm
Copy link
Copy Markdown
Owner

@toddysm toddysm commented Jun 5, 2026

What

Implements TS-IMPL-008 — the persistence seam for Trigger Service: thin store adapters over the SPL MetadataStoreProvider plus the provider-selection wiring.

Changes

  • stores/ package
    • base.pyTriggerMetadataStore Protocol: the narrow subset of MetadataStoreProvider Trigger Service writes to (the eight Subscription / SubscriptionSelector / ResumeSubscription / DedupKey / Schedule methods). Both the Postgres adapter and the in-process backend satisfy it structurally.
    • subscriptions.py / resume.py / schedules.pySubscriptionStore, ResumeSubscriptionStore, ScheduleStore: thin async adapters that map the wire/domain models in models.py onto the locked SPL rows (+ their free-form JSON blobs) and delegate to the provider.
  • providers.py
    • InMemoryTriggerMetadataStore — faithful in-process backend (immutable put_subscription, not-found ValueError on state/next-fire updates, TTL-aware reserve-or-read dedup) plus dev/test read accessors.
    • Providers bundle + load_providers() — selects in-memory by default (empty/memory sentinel) or custos_pg.PgMetadataAdapter when TRIGGER_METADATA_STORE is a DSN. LazyPool defers connection; the factory opens no socket. No new schema invented.
  • dependencies.pyget_providers / get_metadata_store FastAPI helpers (mirror auth-service).
  • app.py — lifespan binds the providers bundle + store adapters onto app.state; new optional providers= injection point for tests.

Acceptance criteria

  • CRUD round-trips against the in-memory MetadataStoreProvider.
  • Provider selection honors the TRIGGER_METADATA_STORE env knob; no new schema invented.

Quality gates

  • ruff format / ruff check clean
  • mypy src tests (strict) clean
  • pytest — 221 passed, 99.8% coverage (floor 90%)

Closes #638

…oviders wiring

Add the persistence seam for Trigger Service (TS-IMPL-008):

- `stores/` package: the narrow `TriggerMetadataStore` Protocol (the eight
  Subscription/Selector/Resume/Dedup/Schedule write methods Trigger Service
  owns) plus thin domain↔SPL adapters `SubscriptionStore`,
  `ResumeSubscriptionStore`, and `ScheduleStore` that map the wire/domain
  models onto the locked SPL rows and their free-form JSON blobs.
- `providers.py`: `InMemoryTriggerMetadataStore` (faithful in-process backend
  — immutable put, not-found ValueError, TTL-aware reserve-or-read dedup),
  the `Providers` bundle, and `load_providers()` selecting in-memory by
  default or `custos_pg.PgMetadataAdapter` when `TRIGGER_METADATA_STORE` is a
  DSN. No new schema invented.
- `dependencies.py`: `get_providers` / `get_metadata_store` FastAPI helpers.
- `app.py`: lifespan binds the providers bundle + store adapters onto
  `app.state`.

CRUD round-trips covered against the in-memory backend; provider selection
honors the env knob. ruff + mypy strict clean; coverage 99.8%.

Closes #638
Copilot AI review requested due to automatic review settings June 5, 2026 03:04
@toddysm toddysm added type:implementation Implementation work item phase:implementation Implementation phase component:trigger-service Trigger Service component labels Jun 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Trigger Service’s persistence seam (TS-IMPL-008) by introducing thin domain↔SPL store adapters, provider selection/wiring (in-memory default vs Postgres via TRIGGER_METADATA_STORE), and wiring these into FastAPI lifespan/dependencies, with accompanying tests.

Changes:

  • Added custos_trigger.stores/* adapters (SubscriptionStore, ResumeSubscriptionStore, ScheduleStore) over the SPL MetadataStoreProvider write surface.
  • Added custos_trigger.providers with InMemoryTriggerMetadataStore + load_providers() DSN-based selection and a Providers bundle.
  • Wired providers + stores into create_app() lifespan and exposed them via dependency helpers; added tests covering the wiring and CRUD round-trips.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/services/trigger-service/tests/test_stores.py New CRUD round-trip tests for store adapters over the in-memory backend.
src/services/trigger-service/tests/test_providers.py New tests for DSN selection and in-memory backend semantics (dedup, schedule updates, etc.).
src/services/trigger-service/tests/test_dependencies.py New tests validating dependency helpers and lifespan wiring onto app.state.
src/services/trigger-service/tests/conftest.py New shared fixtures (frozen clock + providers bundle).
src/services/trigger-service/src/custos_trigger/stores/subscriptions.py SubscriptionStore adapter mapping domain Subscription ↔ SPL rows/selectors.
src/services/trigger-service/src/custos_trigger/stores/schedules.py ScheduleStore adapter for SPL schedule persistence.
src/services/trigger-service/src/custos_trigger/stores/resume.py ResumeSubscriptionStore adapter for SPL resume subscription persistence.
src/services/trigger-service/src/custos_trigger/stores/base.py TriggerMetadataStore Protocol defining the narrow SPL write surface used by Trigger Service.
src/services/trigger-service/src/custos_trigger/stores/init.py Package exports + documentation for the store adapter layer.
src/services/trigger-service/src/custos_trigger/providers.py In-memory backend + Providers bundle + load_providers() env/DSN selection.
src/services/trigger-service/src/custos_trigger/dependencies.py FastAPI dependencies to retrieve providers bundle / metadata store.
src/services/trigger-service/src/custos_trigger/app.py Lifespan wiring for providers + store adapters; optional providers injection for tests.
design/components/trigger-service/todos.md Marks TS-IMPL-008 as completed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/services/trigger-service/src/custos_trigger/providers.py
Comment thread src/services/trigger-service/src/custos_trigger/providers.py
Comment thread src/services/trigger-service/src/custos_trigger/providers.py
Comment thread src/services/trigger-service/tests/test_stores.py
Comment thread src/services/trigger-service/src/custos_trigger/providers.py Outdated
…ry store

Address Copilot review on #661:
- append_subscription_selector raises on unknown subscription (FK parity)
- put_resume_subscription / put_schedule raise ImmutableViolation on
  duplicate PK, matching the Postgres adapter's 23505 mapping
- fix the default-clock test to assert on the persisted selector's added_at
- correct the load_providers cast rationale (NewType param mismatch, not
  SCHEMA_REVISION)
@toddysm toddysm merged commit f38f75c into main Jun 5, 2026
30 checks passed
@toddysm toddysm deleted the ts-impl-008-store-adapters branch June 5, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:trigger-service Trigger Service component phase:implementation Implementation phase type:implementation Implementation work item

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TS-IMPL-008: Store adapters over MetadataStoreProvider + providers.py

2 participants