backbone-mailing 0.6.0

Email marketing — mass-mail engine: audiences, subscriptions, hand-set mailing lifecycle, seeded A/B testing, per-recipient traces, cycle-44 bridge targets (Odoo mass_mailing port)
# Codegen policy for mailing.
#
# `user_owned` globs are hand-written files that live inside generator-owned trees but are
# NOT schema-derived. `metaphor schema generate [--force]` skips them wholesale (never reads,
# merges, or deletes them). Everything else in src/ is regenerated from schema/models.
#
# Re-exports/declarations that must sit alongside generated code live inside
# `// <<< CUSTOM ... // END CUSTOM` markers (service/mod.rs, presentation/http/mod.rs, lib.rs)
# and are preserved by the marker mechanism, not listed here.
#
# Declared BEFORE any file lands (the regen-safety contract).

user_owned:
  # Hand-authored validated write paths (services orchestrate, repositories
  # hold SQL — the module rule): the mailing lifecycle + send engine verbs,
  # the trace set_* verbs, and the grouped-query stats read service.
  #
  # The generated per-entity repositories (src/infrastructure/persistence/
  # mailing_repository.rs, mailing_trace_repository.rs) are generator-owned
  # until a seat customizes them: add the matching user_owned entry BEFORE
  # the regen that precedes the customization, or the file gets clobbered.
  - "src/application/service/mailing_write_service.rs"
  - "src/application/service/trace_write_service.rs"
  - "src/application/service/mailing_stats_read_service.rs"
  - "src/application/service/subscription_write_service.rs"
  - "src/application/service/ab_test_write_service.rs"
  # SMS-channel STOP surface (the mass_mailing_sms overlay's STOP legs): the
  # inbound-reply + code-bearing blacklist-add verbs with the Tier B STOP-code
  # floor (MSM-B-10 — the 3-char upstream code shape is refused), and the
  # claim-time phone-blacklist suppression arm that mints pre-canceled visible
  # traces (failure_type='sms_blacklist').
  - "src/application/service/sms_stop_service.rs"
  - "src/application/service/sms_suppression_service.rs"
  # The SMS channel's targeting port: one host-composed resolver per
  # phone-bearing bridge target ('crm_lead'), declaratively keyed by
  # target_model — the phone twin of the TargetRecipientResolver seam, with
  # the visible invalid-phone exclusion count (the strict-equality gate's
  # replacement: eligibility is the sanitizer's verdict, drift is counted,
  # never silently dropped).
  - "src/application/service/sms_targeting_service.rs"

  # The public /r/:code/m/:trace trace-route family (click + pixel +
  # unsubscribe, the deferred MMF-H seam): the cross-module click seam
  # (TraceClickPort — the module owns the trait, the host wires the
  # short-link implementation; deny-by-default) and the route orchestration
  # service that drives the trace state helpers + the subscription opt-out.
  - "src/application/service/trace_click_ports.rs"
  - "src/application/service/trace_route_service.rs"

  # The SMS channel's asynchronous completion clock: advances sms-type
  # traces from delivery-tracker verdicts (read-only cross-schema join by
  # sms_uuid) and infers done for walked-out sms mailings under a FOR
  # UPDATE lock before the remaining-check (the claim precedent applied to
  # the completion edge). Rides the single send job as its last step.
  - "src/application/service/sms_delivery_pump_service.rs"

  # The bridge targets' billing-side seam (the mass_mailing_sale winner
  # metric): a source-keyed invoiced-amount PORT this module owns and the
  # host implements — deny-by-default (the TraceClickPort/PhoneBookPort
  # shape), zero billing Cargo edge.
  - "src/application/service/sale_invoiced_amount_port.rs"

  # The events-registrations bridge target (mass_mailing_event): the typed
  # resolver PORT this module owns and the host implements over the events
  # module's registration read surface — fail-closed (registry parks loudly
  # at the send walk; the Refusing double refuses with the typed error),
  # zero events Cargo edge. The *_sms twin rides the same target value on
  # the existing sms channel (no twin module).
  - "src/application/service/event_registration_target_port.rs"

  # The events bridge target's hand-written migration (one enum value; no
  # statement in it USES the newly added value — the bridge_targets
  # mechanics; the value cannot be dropped in place, so the down file
  # stamps SELECT 1).
  - "migrations/*event_registration_target*"

  # The cycle-44 bridge targets' hand-written migration (enum values +
  # the A/B control's parallel sms winner axis; value-only ALTER TYPEs and
  # a nullable column — no statement USES a newly added value, the
  # sms_channel_overlay mechanics).
  - "migrations/*bridge_targets*"

  # The bridge-target probes: per-target resolution (park-loudly without a
  # composed resolver), the typed default-domain providers, source-keyed
  # winner-metric grouping with the shared-source caveat, the billing
  # seam's refusing default, and the sms winner axis + mixed-channel
  # compare action.
  - "tests/bridge_cases.rs"

  # The public trace-route handlers themselves (bare capability mount, the
  # engagement /r precedent). Declared before the file lands — a landing
  # without the declaration is clobbered on the next regen, a declaration
  # without the file is the dangling class the P2 council removed.
  - "src/presentation/http/trace_routes.rs"

  # Hand-authored SQL holders for the write paths above (separate files, the
  # engagement house pattern — the generated per-entity repositories stay
  # untouched): send-engine claim/suppress/resolve/complete SQL, the trace
  # set_* conditional updates, and the subscription opt-out split.
  - "src/infrastructure/persistence/mailing_send_repository.rs"
  - "src/infrastructure/persistence/trace_repository.rs"
  - "src/infrastructure/persistence/subscription_repository.rs"

  # Hand-written DB hardening: the G-MM1 percentage-band CHECK, the G-MM2
  # email_from CHECK, and any further unique/monotonic-guard constraints the
  # DSL cannot express.
  - "migrations/*mailing*hardening*"

  # The SMS-channel failure-type delta's hand-written migration (the enum
  # variant is declared in schema/models/trace.model.yaml — the SSoT; the
  # ALTER TYPE is its DB expression, up-only like every enum-add).
  - "migrations/*sms_blacklist_failure_type*"

  # The SMS-channel overlay's hand-written migration (columns + enum values;
  # no statement in it USES a newly added value — the sms-usage CHECKs ride
  # the next stamp under the *mailing*hardening* glob above).
  - "migrations/*sms_channel_overlay*"

  # The delivery-tracker pump's scan-arm index stamp (value-free DDL in its
  # own stamp — the composite keeps the mail channel's transient traces off
  # the pump's sms-only scan).
  - "migrations/*sms_pump_scan_index*"

  # The SMS channel's asynchronous done-inference cases: tracker-verdict
  # advancement through the real substrate (enqueue + drainer claim +
  # signed webhook), the last-verdict completion race (two pumps + two
  # webhooks converge; sent_date stamps once), restart durability, and the
  # premature-done guards.
  - "tests/sms_delivery_cases.rs"

  # Behavior tests (the golden cases / oracle) + the concurrency proofs.
  - "tests/features/**"
  - "tests/mailing_cases.rs"
  - "tests/trace_cases.rs"
  - "tests/trace_route_cases.rs"
  - "tests/subscription_cases.rs"
  - "tests/ab_seed_cases.rs"
  - "tests/send_probe_cases.rs"
  - "tests/sms_stop_cases.rs"
  - "tests/behavior/**"

  # Hand-authored module documentation.
  - "docs/**"
  - "README.md"