Skip to content

Differential transformer: migration output must match live ingestion #6

Description

@ar2rsawseen

Problem

The migration tool's transform (src/transform/normalize.ts) and the live ingestion path in countly-platform (api/ingestor/requestProcessor.ts / event-sink normalization) are two independent implementations of the same conversion. After a customer is migrated, their historical data (produced by this tool) and their live data (produced by the platform) must be identical in shape for the same input — any drift means a customer's history disagrees with their new data, per key, silently.

Today nothing enforces this. A change to either side lands green and the divergence is only discovered in customer data.

Proposal — a two-sided contract test

This is a contract between two codebases, so drift can originate from either side; enforcement must exist on both:

  1. countly-platform CI gains a small job that generates golden fixtures: (input doc) → (ClickHouse row produced by the live ingestion normalization). A platform PR that changes normalization produces a visible, reviewable diff in the goldens — the change is signed, not silent.
  2. This repo's CI asserts transformBatch() reproduces the goldens exactly.

Fixture corpus

  • Harvested real-world oddities: dry-run report findings and DLQ contents from actual migrations (every value class that has actually occurred).
  • Property-based hostile values: integers beyond Int64, NaN/Infinity, mixed types per key, deep nesting, hostile strings, missing/blank required fields.

Coercion policy alignment

The transform's rules must be the answer to "what would live ingestion do":

  • Countly-owned fields (c, s, dur, timestamps): clamp to column range.
  • Customer-owned keys (sg.*, custom.*, cmp.*): never guess — values that don't fit numeric representation are stringified losslessly.
    Every rule promoted here should carry a golden fixture proving both sides agree.

Acceptance

  • A normalization change in either repo fails the other repo's CI (or produces a reviewed golden diff) — verified by deliberately introducing a divergence in a test branch.
  • Corpus covers all currently-known rejection classes (incl. the empirically verified ones: oversized ints, unparseable DateTime — CH error codes 41/117 family).

Corresponds to item D4 of the internal drill-migration overhaul plan (companion items: D1 sampled dry run, D2 coercion policy, B2 DLQ).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions