The database surface the two consuming services need, and nothing else.
Split by direction on purpose: ferrite calls only the read methods, cobalt only insertAll. Keeping them in one trait rather than two is a bet that the split is a fact about callers and not about the schema — both halves talk to the same table and any divergence between how a row is written and how it is read is a bug this interface should make obvious rather than hide behind two files.
No Magnum type appears in any signature (ADR §5). Callers see domain values and Future, so the ADR's budgeted Magnum 2.0 migration rewrites implementations and touches nothing above them.
Every method returns Future because the implementation is blocking JDBC on a bounded dispatcher (ADR §0, decision 8): the pool, not the caller, is where load is shed.
An exact total over a partitioned fact table is a full scan, and nobody reads past "10,000+" (ADR §6.3). A caller that gets cap + 1 back renders the cap with a plus sign.
Returns the number of rows actually written, which for a replayed batch is less than events.size — that difference is the consume.records.duplicate metric of ADR §7 and the direct evidence that at-least-once delivery is being absorbed rather than duplicated.
Long rather than Int because that is what JDBC's large-batch update count is, and narrowing it here would put a silent truncation on the one number that proves deduplication works.