Skip to content

fix(cdc): null-key ordering checks, zero stale_after, epoch event times, replay_risk docs - #387

Merged
kevincostner17 merged 1 commit into
mainfrom
fix/cdc-profile
Sep 15, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
fix/cdc-profile

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

Fixes four fd.cdc_profile bugs:

Behaviour changes: numeric event-time columns get a guessed epoch unit instead of always nanoseconds (small integers such as row numbers are read as seconds); key columns with nulls add a missing_key warning (no effect on passed or penalties); negative stale_after raises ValueError.

Tests

New tests/test_cdc_profile_fixes.py covering each issue's repro plus:

  • null keys mixed with other keys, and a null-key row with an explicit watermark
  • zero-age and negative stale_after
  • all four epoch units, both guessed and explicit, plus float and nullable-integer columns
  • invalid event_time_unit
  • a test pinning the late-only replay_risk behaviour

Verification

  • ruff check .: passes
  • mypy src/freshdata: no issues
  • Python 3.12 / pandas 2.3.3: 5061 passed, 6 skipped
  • Python 3.9 / pandas 1.5.3: 5057 passed, 10 skipped

Closes #325
Closes #326
Closes #327
Closes #328

…es, replay_risk docs

- Null CDC keys (#325): the per-key running watermark used
  groupby(key).cummax(), which drops null keys, so rows with a null key
  were never classified as out_of_order or late. Group with
  dropna=False so null-key rows form one group of their own (works on
  pandas 1.5 and 2.x), and report them as a new `missing_key` warning
  (row labels as samples). The trust penalty formula is unchanged.

- Zero stale_after (#326): the freshness penalty divided the age by
  stale_after, raising ZeroDivisionError for "0s". With stale_after == 0
  the penalty is now the limit of age / stale_after: 1.0 for any positive
  age and 0.0 otherwise, matching the `stale` defect (age > stale_after).
  A negative stale_after now raises ValueError.

- Integer epoch event times (#327): numeric event-time columns went
  through pd.to_datetime without a unit and were read as nanoseconds,
  so Debezium ts_ms values landed in 1970. Parse them with the shared
  parse_timestamps helper, which infers the unit from magnitude as
  clean_timeseries does, and add `event_time_unit` ("s", "ms", "us",
  "ns") to set it explicitly. String and datetime columns are unchanged.

- replay_risk (#328): behaviour kept. The replay_threshold docstring now
  says at least one duplicate_key row is required, so a late-only batch
  never raises replay_risk.

Closes #325
Closes #326
Closes #327
Closes #328
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 8e011cff-90c6-46d6-9cab-f3d1d0ce9f8c


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

FreshData benchmark report — performance

  • freshdata: ?
  • python: ?
  • platform: ?
fixture n_rows n_cols p50 s p95 s peak MB repair % false-repair % preserve % trust monotonic export %

Authored-code reduction (Metric 6)

@kevincostner17
kevincostner17 merged commit f81e66a into main Sep 15, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant