$npx -y skills add rudderlabs/rudder-agent-skills --skill rudder-profiles-updateModifies an existing RudderStack Profiles project: features, inputs, id_types, cohorts, feature views, SQL models, optimizations, macros, propensity/attribution, or incremental migration. Use when updating Profiles YAML, adding features/audiences/models or changing incremental be
| 1 | # RudderStack Profiles Project Update |
| 2 | |
| 3 | Modify an existing Profiles project carefully. Always understand the current state first, classify risk, and validate after each change. |
| 4 | |
| 5 | ## Workflow |
| 6 | |
| 7 | 1. **Read current state** — Read all YAML files, run `pb show models`, run `pb compile`. |
| 8 | 2. **Fix first** — If compile already fails, fix the existing project before introducing new changes. |
| 9 | 3. **Classify the change** — Determine risk level before making edits (see table below). |
| 10 | 4. **Make one change at a time** — Edit, then `pb compile`. Do not batch multiple changes before validating. |
| 11 | 5. **Offer a run** — Only after compile is green and user confirms. |
| 12 | |
| 13 | ## Change Risk Classification |
| 14 | |
| 15 | | Change Type | Risk | Key Concern | |
| 16 | |-------------|------|-------------| |
| 17 | | Add new entity_var | Safe | Must aggregate if has `from` | |
| 18 | | Add new input source | Safe | Verify table/columns exist via `describe_table()` | |
| 19 | | Add new id_type | Moderate | Affects identity resolution graph | |
| 20 | | Add feature view (`using_ids`) | Safe | Re-keys existing output; needs an id_type already on the entity | |
| 21 | | Add entity cohort | Moderate | Filter features must exist in the parent var_group; re-run to materialize | |
| 22 | | Add/modify sql_template model | Moderate | Pongo2 + `DeRef` dependencies; `single_sql` can't take a top-level `WITH`; materialization choice affects cost | |
| 23 | | Add optimizations.yaml flag | Safe | Enable one at a time and confirm output is unchanged | |
| 24 | | Modify existing entity_var | Moderate | Downstream refs may break; invalidates incremental checkpoints | |
| 25 | | Add propensity model | Moderate | Date handling rules change completely (see below) | |
| 26 | | Add attribution model | Moderate | Needs a separate campaign entity + campaign id_stitcher first (see below) | |
| 27 | | Remove entity_var or input | Breaking | Must scan all refs first; warn about downstream consumers | |
| 28 | | Change entity or id_stitcher | Breaking | Full re-run required; all checkpoints invalidated | |
| 29 | |
| 30 | Before writing any change: |
| 31 | 1. Name the risk class. |
| 32 | 2. Name the expected blast radius. |
| 33 | 3. Tell the user what validation will prove the change is safe. |
| 34 | |
| 35 | ## Standard Update Rules |
| 36 | |
| 37 | - Verify every new table or column with `describe_table()` before using it. |
| 38 | - If an entity var has a `from` key, its `select` MUST use an aggregation: `count`, `sum`, `max`, `min`, `avg`, `first_value`, or `last_value` (order-dependent ones need a `window:` with `order_by`). |
| 39 | - Entity var reference syntax: dot form `'{{<entity_name>.var_name}}'` — e.g. `'{{user.order_count}}'` (the first segment is the entity's name, not the literal word `entity`; the `.Var("...")` function form also works but dot is preferred). |
| 40 | - Model paths in `from:` are a path to a model — `inputs/<name>`, `models/<name>`, or `packages/<pkg>/...` — pb has no dbt-style `ref('...')`. |
| 41 | - For removals or renames, scan all files for downstream references first and warn the user explicitly before proceeding. |
| 42 | |
| 43 | ## Propensity Models |
| 44 | |
| 45 | Before writing `models/profiles-ml.yaml`, confirm all four items with the user: |
| 46 | |
| 47 | 1. Label definition (what binary outcome to predict). |
| 48 | 2. Prediction window (how far ahead to predict). |
| 49 | 3. Eligible-user filter (which users qualify for scoring). |
| 50 | 4. Output model names. |
| 51 | |
| 52 | Then: |
| 53 | |
| 54 | - Use `model_type: propensity` in the model definition. |
| 55 | - Convert ALL date-based entity vars to macros. |
| 56 | - Add `python_requirements: - profiles_mlcorelib>=0.8.1` to `pb_project.yaml` if not already present. |
| 57 | - Validate with `validate_propensity_model_config()` and `evaluate_eligible_user_filters()` before compile. |
| 58 | |
| 59 | ### Banned date functions for propensity features |
| 60 | |
| 61 | Never use these in entity vars that feed propensity models: |
| 62 | |
| 63 | - `current_date()`, `current_timestamp()`, `datediff()`, `sysdate`, `getdate()`, `now()` |
| 64 | |
| 65 | Always use the conventional project-defined macros instead (confirm they exist in `models/macros.yaml` — they are NOT pb built-ins): |
| 66 | |
| 67 | - `{{macro_datediff('column')}}` — days between `column` and the project's `end_time` |
| 68 | - `{{macro_datediff_n('column', N)}}` — boolean predicate "within N days"; the second arg is an **integer day count**, not a unit string like `'months'` |
| 69 | |
| 70 | Why: macros expand to use the project's `end_time` so they stay anchored to each training snapshot's reference date. Direct date functions evaluate at query time and corrupt historical training data (label leak). |
| 71 | |
| 72 | See `references/propensity-yaml-template.md`. |
| 73 | |
| 74 | ## Attribution Models |
| 75 | |
| 76 | Attribution computes first-touch and last-touch credit for conversions across user→campaign journeys (`model_type: attribution`, a PyNative model in `profiles_mlcorelib`). It has real prerequisites — do not start the model until they exist: |