Skip to content

Comments

send permutive segments to adserver#263

Open
ChristianPavilonis wants to merge 8 commits intomainfrom
feature/send-permutive-segments-to-adserver
Open

send permutive segments to adserver#263
ChristianPavilonis wants to merge 8 commits intomainfrom
feature/send-permutive-segments-to-adserver

Conversation

@ChristianPavilonis
Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis commented Feb 9, 2026

Passes Permutive audience segments from the browser through to the ad server mediation endpoint, enabling segment-targeted ad decisioning.

  • Introduces a context provider registry on the JS side (context.ts) — a generic mechanism for integrations to contribute data to auction requests without core needing integration-specific knowledge.
  • The Permutive integration registers a context provider that reads cohort segments from localStorage (permutive-app key) and injects them as permutive_segments in the request config.
  • On the Rust side, convert_tsjs_to_auction_request now forwards all config entries into the AuctionRequest.context map instead of discarding them.
  • The AdServer Mock provider reads permutive_segments from the context and appends them as a ?permutive=seg1,seg2,... query parameter on the mediation endpoint URL.
    Changes
Layer File What
JS core core/context.ts (new) Context provider registry (registerContextProvider, collectContext)
JS core core/request.ts Calls collectContext() to build config payload
JS integration integrations/permutive/segments.ts (new) Reads segments from localStorage (core.cohorts.all primary, eventUpload fallback)
JS integration integrations/permutive/index.ts Registers context provider with Permutive segments
Rust common auction/formats.rs Forwards config entries into AuctionRequest.context
Rust common integrations/adserver_mock.rs build_endpoint_url() appends ?permutive= query param
Tests context.test.ts, segments.test.ts, Rust unit tests Full coverage for new functionality

Closes #132


How to Manually Test

  1. Verify Permutive segment extraction (JS)
  2. Open a publisher page that has Permutive active (or any page where you can set localStorage manually).
  3. Open DevTools Console and confirm localStorage.getItem('permutive-app') has data — look for core.cohorts.all containing segment IDs.
  4. If testing without a real Permutive install, seed it manually:
      localStorage.setItem('permutive-app', JSON.stringify({
     core: { cohorts: { all: ['10000001', '10000003', 'adv', 'bhgp'] } }
   }));
  1. Load the page with the tsjs tag. In the DevTools Console, filter for context — you should see a log like:
    requestAds: payload { units: N, contextKeys: ["permutive_segments"] }

  2. Verify segments are sent to the server

  3. Open DevTools Network tab and filter for /auction.

  4. Trigger an ad request.

  5. Inspect the /auction POST request body — the config object should contain:

      {
     config: {
       permutive_segments: [10000001, 10000003, adv, bhgp]
     }
   }

@aram356 aram356 assigned aram356 and ChristianPavilonis and unassigned aram356 Feb 11, 2026
@ChristianPavilonis ChristianPavilonis marked this pull request as ready for review February 11, 2026 15:42
@aram356 aram356 requested a review from prk-Jr February 12, 2026 16:37
Copy link
Collaborator

@aram356 aram356 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making changes. Few more things introduced with recent changes that needs addressing.

@ChristianPavilonis ChristianPavilonis force-pushed the feature/send-permutive-segments-to-adserver branch from cdd3763 to 8eed73d Compare February 20, 2026 18:52
@ChristianPavilonis ChristianPavilonis force-pushed the feature/send-permutive-segments-to-adserver branch from 8eed73d to f24ada2 Compare February 20, 2026 19:10
Copy link
Collaborator

@aram356 aram356 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

👍 Well-designed feature that forwards Permutive audience segments from the client through the auction pipeline to the ad server as URL query parameters. The architecture is clean — a generic context provider registry on the JS side and a config-driven allowed_context_keys allowlist on the Rust side prevent tight coupling between integrations and the auction system. Good security posture with server-side allowlisting.

Findings

🔧 High (P1)

  • unwrap() in tests: context.rs:233,239,245 — three deserialization tests use .unwrap() instead of .expect("should ..."). (inline comment)

🤔 Medium (P2)

  • ContextValue::Number(f64) precision: context.rs:24 — works for current string-based segments, but f64 loses precision for integers above 2^53. Low risk now but worth noting.
  • HashSet rebuilt per request: formats.rs:144allowed_context_keys is converted from Vec to HashSet on every auction request. Negligible with a small list, but could be stored as a HashSet in AuctionConfig. (inline comment)
  • Comment names Permutive but code is generic: adserver_mock.rs:286 — the context_query_params mechanism is integration-agnostic, but the comment says "Permutive segments". (inline comment)
  • Bare catch swallows all errors: segments.ts:58 — catches everything including unexpected errors, logs a misleading message. (inline comment)

⛏ Low (P3)

  • Test names use test_ prefix: context.rs, adserver_mock.rs, settings.rs — consistent with existing codebase style.
  • No end-to-end test for context provider registration: segments.test.ts covers getPermutiveSegments() but the registerContextProvider call in index.ts isn't tested e2e (registry itself is tested in context.test.ts).

CI Status

  • cargo fmt: PASS
  • cargo test: PASS
  • vitest: PASS
  • CodeQL: PASS


#[test]
fn test_context_value_deserialize_array() {
let v: ContextValue = serde_json::from_str(r#"["a","b"]"#).unwrap();
Copy link
Collaborator

@aram356 aram356 Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 unwrap() in tests: These three deserialization tests (lines 233, 239, 245) use .unwrap() instead of .expect("should ...") per project conventions.

Fix:

let v: ContextValue = serde_json::from_str(r#"["a","b"]"#).expect("should deserialize string list");
// ...
let v: ContextValue = serde_json::from_str(r#""hello""#).expect("should deserialize text");
// ...
let v: ContextValue = serde_json::from_str("42").expect("should deserialize number");

// arbitrary data by a malicious client payload.
let allowed: HashSet<&str> = settings
.auction
.allowed_context_keys
Copy link
Collaborator

@aram356 aram356 Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 HashSet rebuilt per request: allowed_context_keys is converted from Vec<String> to HashSet<&str> on every auction request. With a small allowlist this is negligible, but could be avoided by storing the allowlist as a HashSet<String> in AuctionConfig at deserialization time.


log::debug!("AdServer Mock: mediation request: {:?}", mediation_req);

// Build endpoint URL with optional Permutive segments query string
Copy link
Collaborator

@aram356 aram356 Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Comment names Permutive but code is generic: The context_query_params mechanism is integration-agnostic, but this comment says "Permutive segments query string". Future integrations using the same mechanism would make this misleading.

Fix:

// Build endpoint URL with context-driven query parameters

}
}
}
} catch {
Copy link
Collaborator

@aram356 aram356 Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Bare catch swallows all errors: This catches everything (JSON parse failures, property access errors, out-of-memory) and logs "failed to read from localStorage" which isn't accurate for all error types.

Fix: Consider logging the error object for debuggability:

} catch (err) {
  log.debug('getPermutiveSegments: failed to read segments', err);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

As publisher I want to see Permutive segment propagate to ad server

2 participants