rudder-profiles-update — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited rudder-profiles-update (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Modify an existing Profiles project carefully. Always understand the current state first, classify risk, and validate after each change.
pb show models, run pb compile.pb compile. Do not batch multiple changes before validating.| Change Type | Risk | Key Concern |
|---|---|---|
| Add new entity_var | Safe | Must aggregate if has from |
| Add new input source | Safe | Verify table/columns exist via describe_table() |
| Add new id_type | Moderate | Affects identity resolution graph |
Add feature view (using_ids) | Safe | Re-keys existing output; needs an id_type already on the entity |
| Add entity cohort | Moderate | Filter features must exist in the parent var_group; re-run to materialize |
| Add/modify sql_template model | Moderate | Pongo2 + DeRef dependencies; single_sql can't take a top-level WITH; materialization choice affects cost |
| Add optimizations.yaml flag | Safe | Enable one at a time and confirm output is unchanged |
| Modify existing entity_var | Moderate | Downstream refs may break; invalidates incremental checkpoints |
| Add propensity model | Moderate | Date handling rules change completely (see below) |
| Add attribution model | Moderate | Needs a separate campaign entity + campaign id_stitcher first (see below) |
| Remove entity_var or input | Breaking | Must scan all refs first; warn about downstream consumers |
| Change entity or id_stitcher | Breaking | Full re-run required; all checkpoints invalidated |
Before writing any change:
describe_table() before using it.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).'{{<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).from: are a path to a model — inputs/<name>, models/<name>, or packages/<pkg>/... — pb has no dbt-style ref('...').Before writing models/profiles-ml.yaml, confirm all four items with the user:
Then:
model_type: propensity in the model definition.python_requirements: - profiles_mlcorelib>=0.8.1 to pb_project.yaml if not already present.validate_propensity_model_config() and evaluate_eligible_user_filters() before compile.Never use these in entity vars that feed propensity models:
current_date(), current_timestamp(), datediff(), sysdate, getdate(), now()Always use the conventional project-defined macros instead (confirm they exist in models/macros.yaml — they are NOT pb built-ins):
{{macro_datediff('column')}} — days between column and the project's end_time{{macro_datediff_n('column', N)}} — boolean predicate "within N days"; the second arg is an integer day count, not a unit string like 'months'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).
See references/propensity-yaml-template.md.
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:
pb_project.yaml with its own id_types,python_requirements: - profiles_mlcorelib>=0.8.1.Confirm conversions, conversion timing/value, attribution window, touchpoints, and campaign data with the user first. Note the schema is additionalProperties: False; conversion_vars[*].timestamp is a user.Var('...') reference (not a column); campaign_start_date/campaign_end_date are campaign entity_var names (not literals); conversion_window is a string like "30d". See references/attribution-yaml-template.md.
When a transform can't be an entity_var (multi-step SQL, joins, a filtered/reshaped source), add a sql_template model (single_sql/multi_sql, this.DeRef(...), materialization, optional ids/contract/features). Reference it from entity_vars with from: models/<name>. Keep it run_type: discrete unless it's a real bottleneck. See references/sql-template-models.md.
For large projects, models/optimizations.yaml (var bundling, input-column filtering, case_based_join) cuts compile/run cost — enable one flag at a time and confirm output is unchanged. Reusable SQL lives in models/macros.yaml. See references/optimizations-and-macros.md.
These are how features reach destinations. A feature view re-keys the entity output on another id_type (e.g. email) so a destination can join on the id it knows; an entity cohort is a filtered subset of the entity that the dashboard syncs as an audience.
Before adding either, confirm with the user:
entity_key) var_group? They must be.Key rules: cohort filter values are SQL booleans over {{ <entity>.<var_name> }}; cohort-scoped var_groups use entity_cohort: instead of entity_key:; activation itself is wired in the RudderStack dashboard, not in pb. See references/cohorts-and-feature-views.md.
Treat incremental as a controlled migration, not a small edit.
schema_version, run pb migrate auto --inplace on the copy first.contract: { is_event_stream: true, is_append_only: true } plus occurred_at_col, and the source must really be append-only — verify with SQL (duplicate row identifiers mean it isn't). Never mark a mutable input append-only; it silently corrupts results. The discrete project must already compile and run cleanly.count/sum/min/max are directly mergeable (merge: is a SQL expression over {{rowset.<var>}}; COUNT merges as sum(...)). avg decomposes into sum/count; min_by/max_by need a _by_param helper; median, count distinct, ranking/window functions, and rolling windows are NOT mergeable via merge:. ID stitchers are already incremental — leave them alone.merge: expression, compile, then validate with a cutoff-replay comparison (full-rebase run vs checkpoint-then-delta run) — a single run can't exercise the merge path. Require a zero diff before moving on; never relax the diff to make it pass.pb run --seq_no N for a mid-run crash; pb run --rebase_incremental for state drift. They are not interchangeable.See references/incremental-migration.md for the full decision tree, merge syntax, and validation protocol, plus the cookbook, warehouse-shim, approximate-aggregator, and gotcha references it links.
references/change-risk-classification.md for risk classes and warnings.references/cohorts-and-feature-views.md for cohorts, feature views, and cohort-scoped var_groups (the activation path).references/sql-template-models.md for authoring sql_template models (single_sql/multi_sql, DeRef, materialization, contract).references/optimizations-and-macros.md for optimizations.yaml flags and macros.yaml authoring.references/propensity-yaml-template.md for ML-specific structure and macro rules.references/attribution-yaml-template.md for attribution models, the campaign-entity prerequisites, and the conversion/campaign schema.references/incremental-migration.md — the incremental hub: readiness, feature decision tree, merge syntax, cutoff-replay validation, recovery.references/compound-aggregator-cookbook.md — recipes for AVG, min_by/max_by, distinct, ratios, merge_where.references/warehouse-shims.md — per-warehouse min_by/max_by macros.references/approximate-aggregators.md — HLL / approximate percentiles for otherwise-unmergeable distinct/percentile features.references/known-gotchas.md — silent incremental failure modes (symptom/cause/detection/fix).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.