You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(downstream): source features from philanthropy.ingest package
Drop the local unischema_features.py shim (and its Python contract tests) in
favor of importing read_constituent_events / constituent_events_to_features
directly from the PhilanthroPy package, the single source of truth for the
feature contract. Update pipelines, docs, and dbt notes to the new column
names (gift_count, event_attendance_count, total_gift_amount,
distinct_source_systems).
- downstream-ml.yml: replace the deleted-pytest gate with a dependency-free
py_compile check; repoint the optional smoke to philanthropy.ingest
- repositoryGuard: skip .venv/venv/__pycache__ in the secret scan
Both reading and aggregation live in PhilanthroPy's `philanthropy.ingest` — the single source of truth. `read_constituent_events` walks UniSchema's date-partitioned egress tree (recursively; skips `.manifest.json` sidecars); `constituent_events_to_features` is **leakage-safe** (recency anchored to the batch, never a moving "now") and **deduplicates** redelivered webhooks by `eventId`.
`examples/downstream/unischema_features.py` aggregates events to one row per `constituent_email`:
43
+
`philanthropy.ingest.constituent_events_to_features` aggregates events to one row per donor, indexed by `constituent_id` (the `externalConstituentId` when present, else `constituentEmail`). This contract is owned and tested in the PhilanthroPy repo (`tests/test_ingest.py`):
42
44
43
45
| Column | Type | Source |
44
46
|--------|------|--------|
45
-
|`constituent_email`| string | Group key |
46
-
|`donation_count`| int |`eventType == DONATION`|
47
-
|`registration_count`| int |`eventType == EVENT_REGISTRATION`|
48
-
|`email_click_count`| int |`eventType == EMAIL_CLICK`|
49
-
|`total_amount`| float | Sum of donation `amount`|
50
-
|`total_gift_amount`| float | Alias of `total_amount` (PhilanthroPy naming) |
51
-
|`event_attendance_count`| int | Alias of `registration_count`|
52
-
|`last_donation_date`| ISO string | Latest donation `createdAt`|
53
-
|`last_event_date`| ISO string | Latest any-event `createdAt`|
54
-
|`first_event_date`| ISO string | Earliest any-event `createdAt`|
55
-
|`years_active`| float | Years from `first_event_date` to reference date |
56
-
|`metadata_key_count`| float | Sum of `normalizedMetadata` key counts |
Copy file name to clipboardExpand all lines: examples/downstream/README.md
+1-2Lines changed: 1 addition & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,7 +33,7 @@ npm run downstream-demo
33
33
34
34
## Feature column contract
35
35
36
-
`unischema_features.py` aggregates egress JSON to a per-constituent DataFrame. Required columns are tested in `tests/test_feature_contract.py`.
36
+
`philanthropy.ingest` is the single source of truth: `read_constituent_events` walks the date-partitioned local egress tree (recursive; skips `.manifest.json`), and `constituent_events_to_features` aggregates it (leakage-safe, dedup by `eventId`). Owned and tested in the PhilanthroPy repo.
37
37
38
38
| Column | PhilanthroPy use |
39
39
|--------|------------------|
@@ -47,7 +47,6 @@ Full contract → [philanthropy-integration.md](../../docs/philanthropy-integrat
0 commit comments