Skip to content

Pluggable, competition-neutral modules with a technical permission model #777

Open
0 of 48 issues completed
Open

Description

@jwrosewell

This issue tracks a stack of 55 pull requests that take every vendor integration out of core and add the interfaces that modules build on. The 55 rows are complete and are reviewed in order, bottom first, from the pull request that holds every design document (#1342) at row 1 to the module scripts in their crates (#1423) at row 55. Row 51, ts config migrate (#1409), rewrites a settings document written for main into the shape the stack reads, rows 52 to 54 make the request filters, the Edge Cookie and the asset routes, which ran on the Fastly adapter alone, run on the Axum, Cloudflare and Spin adapters too, and row 55 moves each vendor module's browser script and tests, and the Tinybird project, into the crate that supplies it.

Please make no further changes to main until the stack is processed, because each change to main has to be merged through all 55 rows, and since 13 October six versions of main have each been merged through every row, d2f0d8c from 13 October, fa9837f from 15 October, 5bc3886 from 16 October, a903777 from 17 October, and 7791904 and 6ef07ae from 19 October.

Review one row at a time in the order of the list below, starting with row 1. Row 1 is based on main and every other row on the branch of the row below it, so each pull request's Files changed tab shows that row's own change and nothing else. The tables after the list group the rows by kind of change and link each row's issue and design document.

Review order and CI

  1. Every design document of the stack (Add the integration seam design specs #1342). All 23 checks passed at a854526.
  2. Edge Cookie identity as a module, with the HMAC module built in (Add a pluggable Edge Cookie module seam with the built-in HMAC module #1343). All 29 checks passed at ec6bdab.
  3. Device and geo as selectable modules (Add device and geo module selection with the host-signal Edge Cookie module #1344). All 29 checks passed at 42449d9.
  4. The permission model (Add the permission model with the Privacy Taxonomy vocabulary #1345). All 30 checks passed at db8e1da.
  5. The client-set Edge Cookie value path (Add the client-set Edge Cookie value path #1346). All 30 checks passed at 5744b2e.
  6. The module documentation set (Add the module documentation set and finish the decomposition #1347). All 32 checks passed at 643de85.
  7. The seam opened and every vendor module out of core (Open the integration seam so a vendor module can live outside core #1348). All 32 checks passed at 493119a.
  8. One module context (Add one module context for every kind of module #1349). All 32 checks passed at 6a0561c.
  9. Inspection endpoints (Add inspection endpoints that show what a deployment runs and decides #1350). All 32 checks passed at 246863f.
  10. Page changes as middleware (Add page changes as middleware #1351). All 32 checks passed at 0157d13.
  11. One app-config blob for each host (Add one app-config blob for each host #1352). All 32 checks passed at 08c3339.
  12. Attestation (Add attestation of who operates a deployment and which build it runs #1353). All 32 checks passed at 3774c5d.
  13. Administration leaves the publisher's domain (Remove administration from the publisher's domain #1354). All 32 checks passed at 24a6c79.
  14. robots.txt from modules (Add robots.txt rules from modules #1355). All 32 checks passed at 3427bc6.
  15. Headers that describe the deployment stay off a publisher's pages (Keep headers that describe the deployment off a publisher's pages #1356). All 32 checks passed at 21b0bae.
  16. Auction telemetry is a module [analytics] selects (Make auction telemetry a module that [analytics] selects #1357). All 32 checks passed at 25af766.
  17. The Model Terms cookie name moves to the one implementation that reads it (Declare the Model Terms cookie name in the module that reads it #1358). All 32 checks passed at f702084.
  18. The InMobi Choice consent prompt as a module (Add the InMobi Choice consent prompt as a module #1359). All 32 checks passed at 5810af1.
  19. A middleware may run on a media type other than HTML (Let a middleware run on a media type other than HTML #1360). All 32 checks passed at 18d9ff9.
  20. The sellers a deployment adds to the publisher's ads.txt (Add the sellers a deployment appends to the publisher's ads.txt #1361). All 32 checks passed at d93c843.
  21. A consent prompt runs in the phase the publisher chooses (Let a consent prompt run in the phase the publisher chooses #1362). All 32 checks passed at 45df894.
  22. A file the origin does not have is made by the middleware named for its path (Make a file the origin does not have from the middleware named for its path #1363). All 32 checks passed at 0b7c6a6.
  23. A middleware may prepare with the request's services, and may refuse (Let a middleware prepare with the request's services and refuse a request #1364). All 32 checks passed at 06ca813.
  24. The loading cache core declares, and the module that supplies it (Add the loading cache core declares and the module that supplies it #1365). All 32 checks passed at e66b955.
  25. robots.txt as a middleware (Make robots.txt a middleware core supplies #1366). All 32 checks passed at 95a9634.
  26. A vendor's modules share one table (Add a table that a vendor's modules share #1367). All 32 checks passed at af0e3e8.
  27. A module names the browser's cookies and the shared store keys (Let a module name the browser's cookies and the shared store keys #1368). All 32 checks passed at c3f683b.
  28. A device module may score a person and describe the device (Let a device module score a person and describe the device #1369). All 32 checks passed at c8990bd.
  29. A format can name the viewport widths at which the page asks for it (Let a format name the viewport widths at which the page asks for it #1370). All 32 checks passed at d7ff53b.
  30. A module writes Google's tags on the page from the settings (Add a module that writes Google's tags on the page from the settings #1371). All 32 checks passed at cfdaec1.
  31. The loading cache module reads the released caching crate (Move the loading cache module to the released caching crate #1372). All 32 checks passed at 490a466.
  32. A module declares the caches it loads through (Let a module declare the caches it loads through #1373). All 32 checks passed at 4a1f03c.
  33. A geo module is called with the request, as a device module is (Call a geo module with the request #1374). All 29 checks passed at 79a0421.
  34. The publisher's assets held through the loading cache (Hold the publisher's assets in the loading cache #1375). All 29 checks passed at 2a449ea.
  35. A deployment may address a request by its path before its configuration is chosen (Address requests by path before choosing settings #1376). All 29 checks passed at c61a4f4.
  36. The publisher origin can be a folder of signed object storage (Allow a signed object storage folder as the origin #1377). All 29 checks passed at 5e22174.
  37. A folder origin's URLs in response headers reach the reader without the folder, and a serve middleware may set headers (Map folder origin URLs in headers, add a serve headers step #1378). All 29 checks passed at dbbc8b3.
  38. A middleware reads its settings from a table of its own (Read middleware settings from [middleware.<name>] #1379). All 29 checks passed at f2e82ce.
  39. A source module supplies the publisher's response (Fetch pages and assets through a source module #1380). All 29 checks passed at ade271c.
  40. The Next.js RSC rewriter leaves core for the Next.js crate (Move the Flight rewriter into the Next.js module #1381). All 29 checks passed at 61de267.
  41. The Prebid EID cookie leaves core for the Prebid crate (Read the Prebid EID cookie in the Prebid crate #1382). All 29 checks passed at e3ec48c.
  42. The consent string decoders leave core for the permission signal crates (Move consent decoders into their standards' crates #1383). All 29 checks passed at 6f7b3a1.
  43. No crate holds the list of modules on every adapter's behalf (List linked modules in each adapter #1384). All 26 checks passed at 008f79d.
  44. The 51Degrees client hints middleware, as a module of its own (Request 51Degrees client hints from one middleware #1386). All 26 checks passed at 6fcd32a.
  45. OpenRTB leaves core for the auction protocol crate (Move OpenRTB into an auction protocol module #1388). All 26 checks passed at b0f2346.
  46. The analytics module and the platforms' cache header names leave core (Move analytics and cache header names out of core #1389). All 26 checks passed at 252c068.
  47. Each platform's backend naming leaves core for its adapter (Name backends in each adapter #1390). All 26 checks passed at 3af8768.
  48. AWS request signing leaves core for a shared AWS crate (Move AWS request signing into a shared crate #1391). All 26 checks passed at ad2f25e.
  49. The Fastly names leave core for the Fastly adapter (Move Fastly names out of core #1399). All 27 checks passed at d1aa512.
  50. A publisher's cookies stay under its own path on a shared host (Scope each publisher's cookies to its own path #1400). All 27 checks passed at cdb0a2b.
  51. ts config migrate rewrites a settings document written for main (Add ts config migrate for settings written for main #1409). All 27 checks passed at a71edd1.
  52. Request filters and the device module run on every adapter (Run request filters and the device module on all adapters #1410). All 27 checks passed at 18e8765.
  53. The Edge Cookie is created and written on every adapter (Create and write the Edge Cookie on every adapter #1411). All 27 checks passed at e28df81.
  54. Asset routes are served on every adapter (Serve asset routes on every adapter #1412). All 27 checks passed at 1dde36e.
  55. Each module's browser script and tests in the crate that supplies it (Move module browser scripts and Tinybird into their crates #1423). All 27 checks passed at 5be1147.

What the stack saves core

Every vendor integration in core leaves it. That is 39,035 lines in 24 files (36,394 without comments), 23.7 percent of core on main at 6ef07ae (24.4 percent without comments), and 25.7 percent with the administration routes and version headers that also go (26.3 percent without comments). That quarter of core, nine of its twelve vendor integrations with every line of their tests, goes to crates the vendors maintain. Rows 40, 41, 42, 45, 47, 48 and 49 take 7,285 more lines in 14 files out of core (6,693 without comments), being the code of the standards (OpenRTB and the consent strings), of the platforms (backend naming, AWS signing and the test that keeps the Fastly SDK out of core) and of Prebid and Next.js outside the integrations folder, so 30.1 percent of core leaves it in all (30.8 percent without comments).

Core as a whole then has 3,677 more lines without comments (2.5 percent more) and 10,413 more lines with them (6.3 percent more), while its production code without comments is 1,352 lines smaller (3.9 percent smaller). Core grows because the stack adds the interfaces every module needs (the module context, the middleware, the registry's seam), six features (attestation, the permission model, inspection, robots.txt, the loading and asset caches, request addressing) and the tests of each. Of the 60,035 lines the stack adds to what stays of main, 71 percent are tests. The comment lines grow by 43 percent because every interface is documented where it is declared.

The figures compare main at 6ef07ae with the stack at row 55 (#1423) at 5be1147, counting every text file under crates/trusted-server-core. What stays of main is its core without the 44 files the stack takes out of it. A comment line is one whose first characters are //, /* or * in Rust and JavaScript, or # in TOML. A test line is one of a Rust file's lines from its first #[cfg(test)] to its end, or any line of a file under tests, test_support, migration_guards or fixtures, so all of settings.rs, whose first line is a #[cfg(test)] import, counts as test lines. Both sides are counted the same way.

crates/trusted-server-core main at 6ef07ae Row 55 at 5be1147 Change
Lines 164,652 175,065 10,413 more (6.3 percent)
Lines without comments 149,108 152,785 3,677 more (2.5 percent)
Comment lines 15,544 22,280 6,736 more
Production lines 43,851 46,008 2,157 more (4.9 percent)
Production lines without comments 34,458 33,106 1,352 fewer (3.9 percent)
Test lines 120,801 129,057 8,256 more (6.8 percent)
Test lines without comments 114,650 119,679 5,029 more (4.4 percent)
Vendor integration code inside core 39,035 lines in 24 files (36,394 without comments) none all of it out
Standards', platforms' and other vendor code that leaves core 7,285 lines in 14 files (6,693 without comments) none all of it out

These figures move as the pull requests do.

Of the 39,035 lines of vendor integration code inside core, 23,876 (61 percent) were last changed after 12 June 2026, 23,687 of them in commits by the repository's maintainers. That is git blame -w -M -C on the 24 files at a903777, which 7791904 and 6ef07ae leave unchanged.

How the 55 divide

Apart from row 1 (#1342), which holds every design, the rows fall into three groups. Line counts are each row's own change against the row below, without documentation.

  1. Core keeps the interfaces, and each vendor's features become modules (32 rows): rows 2 to 8, 10, 16, 17, 19, 22, 23, 25 to 28, 31 to 33, 38 to 43, 45 to 49 and 55. They build on Add pluggable Edge Cookie, device, and geo providers gated by a permission model #838 and implement the designs in Add design specs for the provider architecture and permission model epic #986. Each feature a vendor provides is a crate of its own at crates/<feature>/<vendor>/, such as crates/cmp/inmobi, crates/identity/lockr and crates/loading-cache/51degrees. That is one vendor, one feature, one crate, rather than one crate for each vendor or one crate for every vendor.
  2. Functionality the 51Degrees product needs (15 rows): rows 9, 11, 12, 14, 18, 20, 21, 24, 29, 30, 34 to 36, 44 and 51. Rows 11, 18, 20, 21, 30, 44 and 51 change 180 of their 18,324 lines of code inside core, and a deployment that does not select them is unaffected. The other eight add features any deployment can use.
  3. Fixes and wider platform support (7 rows): rows 13, 15, 37, 50 and 52 to 54.

The pull requests, by kind of change

Each row is a pull request here on a feature/ branch based on the branch of the row before it, and row 1 is based on main. Row 1's branch is numbered six because it was cut after the five branches it is read before. #1342 holds every design document of the stack, and the Spec column links each row's document there. The parentheses say where each row came from. Rows 1 and 2 were reviewed here on #1084 and #1043, and rows 3 to 7 were first raised here as #1044 to #1047 and #1094. James Rogers approved rows 8 to 37 on the fork's pull requests 3 to 32, and rows 38 to 50 come from the fork's draft pull requests 33 to 45. Row 37 was reworked after that approval to follow the mapping of origin URLs in response headers that main merged in #1238.

Refactors that take a vendor, standard or platform out of core

Row Change Issue Spec Pull request
7 The seam opened, every vendor module out of core, the Fastly adapter as a library #784, #1100 integration-provider-seam #1348 (first raised as #1094)
16 Auction telemetry is a module [analytics] selects #1274 analytics-module #1357 (approved on fork pull request 11)
17 The Model Terms cookie name moves to the one implementation that reads it #1275 cookie-constant #1358 (approved on fork pull request 12)
40 The Next.js RSC rewriter leaves core for the Next.js crate #1340 rsc-flight-middleware #1381 (from fork pull request 35)
41 The Prebid EID cookie leaves core for the Prebid crate #1337 identifier-modules #1382 (from fork pull request 36)
42 The consent string decoders leave core for the permission signal crates #1335 consent-decoders #1383 (from fork pull request 37)
45 OpenRTB leaves core for the auction protocol crate #1336 auction-protocol #1388 (from fork pull request 40)
46 The analytics module and the platforms' cache header names leave core Part of #1341 last-names-in-core #1389 (from fork pull request 41)
47 Each platform's backend naming leaves core for its adapter #1339 backend-naming #1390 (from fork pull request 42)
48 AWS request signing leaves core for a shared AWS crate #1338 origin-signing #1391 (from fork pull request 43)
49 The Fastly names leave core for the Fastly adapter Part of this issue fastly-names-in-core #1399 (from fork pull request 44)

New features

Row Change Issue Spec Pull request
4 The permission model #779 permission-model #1345 (first raised as #1045)
5 The client-set Edge Cookie value path #778 client-cycle-ec-resolve #1346 (first raised as #1046)
9 Inspection endpoints #1268 inspection-endpoints #1350 (approved on fork pull request 4)
11 One app-config blob for each host #1270 config-by-host, fastly-per-host-selector #1352 (approved on fork pull request 6)
14 robots.txt from modules #1272 robots-txt-from-modules #1355 (approved on fork pull request 9)
20 The sellers a deployment adds to the publisher's ads.txt #1278 ads-txt-sellers #1361 (approved on fork pull request 15)
21 A consent prompt runs in the phase the publisher chooses #1279 consent-prompt-phases #1362 (approved on fork pull request 16)
24 The loading cache core declares, and the module that supplies it #1282 loading-cache #1365 (approved on fork pull request 19)
29 A format can name the viewport widths at which the page asks for it #1287 viewport-sizes #1370 (approved on fork pull request 24)
34 The publisher's assets held through the loading cache #1324 asset-cache #1375 (approved on fork pull request 29)
35 A deployment may address a request by its path before its configuration is chosen #1328 request-addressing #1376 (approved on fork pull request 30)
36 The publisher origin can be a folder of signed object storage #1329 publisher-object-storage-origin #1377 (approved on fork pull request 31)
51 ts config migrate rewrites a settings document written for main into the shape the stack reads Part of this issue config-migrate #1409

New modules

Row Change Issue Spec Pull request
18 The InMobi Choice consent prompt as a module #1276 inmobi-choice-module #1359 (approved on fork pull request 13)
30 A module writes Google's tags on the page from the settings #1288 google-tag-module #1371 (approved on fork pull request 25)
44 The 51Degrees client hints middleware, as a module of its own #1333 51degrees-client-hints #1386 (from fork pull request 39)

The consent prompt rules, with the audit of Didomi, Sourcepoint and Osano, are #1289 and follow the InMobi module.

Interfaces that modules build on

Row Change Issue Spec Pull request
2 Edge Cookie identity as a module, with the HMAC module built in #778 pluggable-providers #1343 (reviewed on #1043)
3 Device and geo as selectable modules #780, #781 pluggable-providers #1344 (first raised as #1044)
8 One module context #1267 module-context #1349 (approved on fork pull request 3)
10 Page changes as middleware #1269 page-middleware #1351 (approved on fork pull request 5)
19 A middleware may run on a media type other than HTML #1277 middleware-media-types #1360 (approved on fork pull request 14)
22 A file the origin does not have is made by the middleware named for its path #1280 middleware-creates-a-missing-file #1363 (approved on fork pull request 17)
23 A middleware may prepare with the request's services, and may refuse #1281 middleware-prepare #1364 (approved on fork pull request 18)
26 A vendor's modules share one table #1284 shared-vendor-tables #1367 (approved on fork pull request 21)
27 A module names the browser's cookies and the shared store keys #1285 prefix-module #1368 (approved on fork pull request 22)
28 A device module may score a person and describe the device #1286 device-signals #1369 (approved on fork pull request 23)
32 A module declares the caches it loads through #1320 module-cache-declarations #1373 (approved on fork pull request 27)
33 A geo module is called with the request, as a device module is #1321 geo-module-request #1374 (approved on fork pull request 28)
38 A middleware reads its settings from a table of its own, [middleware.<name>] #1331 middleware-settings #1379 (from fork pull request 33)
39 A source module supplies the publisher's response, with the origin fetch as the default #1332 source-modules #1380 (from fork pull request 34)

Security

Row Change Issue Spec Pull request
12 Attestation #161 attestation #1353 (approved on fork pull request 7)
13 Administration leaves the publisher's domain #1271 administration-off-the-publisher-domain #1354 (approved on fork pull request 8)
15 Headers that describe the deployment stay off a publisher's pages #1273 diagnostic-headers #1356 (approved on fork pull request 10)
50 A publisher's cookies stay under its own path on a shared host Follows #1328 cookies-by-path #1400 (from fork pull request 45)

Other refactors

Row Change Issue Spec Pull request
25 robots.txt as a middleware #1283 robots-txt-middleware #1366 (approved on fork pull request 20)
31 The loading cache module reads the released caching crate #1282 loading-cache #1372 (approved on fork pull request 26)
43 No crate holds the list of modules on every adapter's behalf #1334 no-modules-crate #1384 (from fork pull request 38)
55 Each module's browser script and tests live in the crate that supplies it, and the Tinybird project in its crate Part of this issue module-scripts-in-crates #1423 (from fork pull request 50)

Fixes

Row Change Issue Spec Pull request
37 A folder origin's URLs in response headers reach the reader without the folder, and a serve middleware may set headers #1330 origin-redirect #1378 (approved on fork pull request 32, then reworked to follow #1238)

Ported to every adapter

Row Change Issue Spec Pull request
52 Request filters and the device module run on every adapter Part of this issue request-filters-on-every-adapter #1410 (from fork pull request 47)
53 The Edge Cookie is created and written on every adapter Part of this issue edge-cookie-on-every-adapter #1411 (from fork pull request 48)
54 Asset routes are served on every adapter Part of this issue asset-routes-on-every-adapter #1412 (from fork pull request 49)

Documentation and design

Row Change Issue Spec Pull request
1 The seam design and every design document of the stack, on the sixth branch but read and merged first, carrying the URL host linter's allowlist for the modules the stack ships This issue integration-provider-seam #1342 (reviewed on #1084, closed when the documents moved here)
6 The module documentation set Part of #782 integration-response-header-hook #1347 (first raised as #1047)

The rule the stack keeps

Core is the interfaces, the routing, the origin fetch, the caches and their tests, and nothing else. Every vendor leaves core, and a standard is a vendor as much as a product is, so OpenRTB, the consent strings and a signing scheme each live in a crate of their own and core offers the neutral interface each implements. Every crate outside core sits at crates/<type>/<vendor>/, names its maintainers in its manifest, and is held to the same contract as a module kept outside this repository. A vendor's crates may depend on one another where the functionality is not a crates.io package, and what a vendor, a platform or a standard offers to every crate goes in crates/shared/<vendor>/. What belongs to the host layer stays in the host layer, so a platform's limits and transport are the adapter's or EdgeZero's, not a crate's under shared.

With every pull request listed above merged, every vendor integration is out of core, and what core keeps is the contract, the seams and the permission model. What core still names is counted in the next section.

What is still named in core

Core depends on no CDN or hosting platform. #496 took the Fastly imports out of core, and row 49 (#1399) takes out of core every word that names Akamai, Axum, Cloudflare, Fastly, Fermyon, Spin or Viceroy, in code, comments, tests, documents and file names, and adds a check to the Run Format workflow that fails when one comes back.

The table counts, at the head of row 55 (#1423) at 5be1147, the lines under crates/trusted-server-core that name a vendor, a standard or a platform. Lines counts every line, comments, documents and tests included. Code lines counts the lines outside test code whose code, rather than a comment on the line, carries the name. A line that names two of these counts under both, and each group's figure counts a line once.

2,234 lines in 75 files name one of these names, and 432 of them are code lines, in 35 files. No line names a platform. On main at 6ef07ae, 9,471 lines in 114 files name one of these names, and 2,394 of them are code lines, in 79 files, and 769 lines in 50 files name a platform, 188 of them code lines. Three file paths still name one of these, ec/eids.rs, request_signing/jwks.rs and tdl.rs.

Name Spellings Lines Code lines Files with code lines
Platforms 0 0
Fastly fastly, viceroy, edgecompute 0 0
Cloudflare cloudflare, wrangler 0 0
Spin spin, fermyon 0 0
Axum axum 0 0
Akamai akamai 0 0
AWS aws, amazonaws, s3, sigv4, cloudfront, x amz 0 0
Vercel vercel 0 0
Vendors 937 81
Google google, googletag, googletagmanager, googlesyndication, googleapis, googleadservices, googletagservices, doubleclick, securepubads, gtag, gtm, gpt, adsense, gam 316 39 creative_opportunities.rs 29, publisher.rs 9, settings.rs 1
Prebid and its targeting keys prebid, pbjs, hb 205 14 publisher.rs 9, creative_opportunities.rs 5
APS aps, apstag, amazon, amzn 94 4 creative_opportunities.rs 4
Next.js nextjs, next js 23 4 settings.rs 4
Tinybird tinybird 2 0
SharedID sharedid, shared id, pubcid 80 21 ec/identifiers.rs 10, ec/finalize.rs 5, cookies/template_cache_policy.rs 2, publisher.rs 2, constants.rs 1, settings.rs 1
Lockr lockr 49 0
Permutive permutive 30 0
DataDome datadome 9 0
Didomi didomi 18 0
Sourcepoint sourcepoint 7 0
Osano osano 4 0
InMobi inmobi 0 0
51Degrees 51degrees, fiftyone 7 0
ID5 id5 72 0
LiveRamp liveramp 31 0
Criteo criteo 1 0
UID2 and The Trade Desk uid2, tradedesk, the trade desk 0 0
LiveIntent liveintent 3 0
AppNexus and Xandr appnexus, xandr 16 0
Rubicon and Magnite rubicon, magnite 6 0
PubMatic pubmatic 10 0
OpenX openx 2 0
TripleLift triplelift 1 0
Kargo kargo 29 0
Standards and laws 1,331 352
OpenRTB openrtb, open rtb, ortb 141 26 auction/formats.rs 10, auction/endpoints.rs 4, settings.rs 4, ec/eids.rs 3, ec/registry.rs 2, Cargo.toml 1, and 2 more files
Extended identifiers (EIDs) eid, eids 685 207 auction/endpoints.rs 42, ec/finalize.rs 39, publisher.rs 25, ec/kv.rs 21, ec/identifiers.rs 20, ec/mod.rs 20, and 6 more files
IAB iab 18 3 publisher.rs 3
TCF tcf, tcfapi, euconsent 38 0
GPP gpp 15 0
US Privacy usprivacy, us privacy, uspapi, usp 17 0
GDPR, and DMA metro codes gdpr, dma 125 17 ec/kv_types.rs 6, auction/telemetry.rs 4, consent/jurisdiction.rs 3, permissions.rs 2, consent/mod.rs 1, ec/mod.rs 1
JWKS and JWK jwks, jwk 131 56 request_signing/rotation.rs 18, request_signing/jwks.rs 12, request_signing/signing.rs 9, request_signing/endpoints.rs 6, request_signing/mod.rs 6, request_signing/discovery.rs 3, and 2 more files
JA4 ja4, ja4h 129 24 ec/device.rs 15, ec/module.rs 3, attestation.rs 1, constants.rs 1, ec/kv_types.rs 1, evidence.rs 1, and 2 more files
Terms Document Locator tdl, terms document locator 52 19 permission_signal/mod.rs 7, tdl.rs 6, permissions.rs 5, lib.rs 1
Any of these 2,234 432

A line names something when one of its spellings appears in the line as whole words. Words are split at every character that is not a letter or a digit, and where a lower case letter meets an upper case one, so FastlyStore, FASTLY_IS_STAGING and edgezero_adapter_spin each name a platform and spinner does not. A spelling of two words, such as us privacy, matches the two words side by side, as in us_privacy and UsPrivacy, and an upper case run that ends in a lower case s is one word, so EIDs is the word eids. Test code is every file under tests, benches or fixtures, every file whose name holds .test., every module file that only test code declares, and every Rust item compiled for tests alone, by #[cfg(test)] or #[cfg(any(test, feature = "test-utils"))], from its attribute to its end. A comment line holds a comment and no code, and every line of a Markdown file is a comment line. EdgeZero, the platform layer core is written against, is not one of the names, and the DMA counted here is the metro code in the Edge Cookie's stored geo record.

#1341 stays open for the JA4 fingerprint class, the JWKS key format and the platforms' store names, as its body says. The identifier modules design asks in its open question 5 whether a later series takes the SharedID cookie out of core. The other names need series that are not yet written.

Open questions

Each design document below has open questions for the reviewers, in a section of their own or at the end of section 2. The Items column counts the numbered items, 107 in all. Item 5 of the client-set value path design is answered and kept for the record.

Row Design and section Items
1 settings-and-consumers, section 5 3
1 and 7 integration-provider-seam, section 10 5
2 and 3 pluggable-providers, section 12 3
5 client-cycle-ec-resolve, section 7 11
6 integration-response-header-hook, section 8 12
8 module-context, section 6 5
11 config-by-host, section 5 8
13 administration-off-the-publisher-domain, section 7 1
16 analytics-module, section 7 4
18 inmobi-choice-module, section 10 6
21 consent-prompt-phases, section 7 4
24 and 31 loading-cache, section 10 2
26 shared-vendor-tables, section 6 5
27 prefix-module, section 5 5
28 device-signals, section 7 2
29 viewport-sizes, section 7 6
32 module-cache-declarations, section 2.10 4
33 geo-module-request, section 2.12 7
41 identifier-modules, section 5 6
42 consent-decoders, section 2 3
52 request-filters-on-every-adapter, section 2 3
54 asset-routes-on-every-adapter, section 2 2

Breaking changes, on purpose

The vendor integrations move out of core inside the stack and keep working, and a deployment's configuration changes with them. The previous auction keys are refused rather than read twice, a module changes no page until an entry places it, [[handlers]] and the administration routes go, and [tinybird] is refused, its settings now being [analytics.tinybird], which [analytics] module = "tinybird" selects. At this pre-production stage the breaks are deliberate and acceptable, the repository has no release and no tag, and ts config migrate (#1409) rewrites a document written for main into the new shape, listing what it changed and what is left for the operator. The pull requests of rows 8 to 13, 15, 16, 23 to 25, 27 and 32 to 49 each say what they break under the heading "What breaks". Rows 52 to 54 bring the Axum, Cloudflare and Spin adapters to what the Fastly adapter already did, and each of their pull requests lists what changes on those adapters. Row 53 changes two things on every adapter, Fastly included. A service with no ec_store now writes a created Edge Cookie, and a crate outside core that never sets device signals gets no created cookie.

The administration user and password go with them, in row 13 (#1354). HTTP Basic authentication is removed together with the [[handlers]] list that configured it, so no request is asked for a password, the handler_password secret is no longer read, and nothing is served beneath /_ts/admin apart from an attestation endpoint that a deployment's own settings put there, which the administration design asks about in its open question 3. A configuration that still carries [[handlers]] is refused with directions when it is validated and when the service starts, so that no deployment believes a path is protected when it is not. The cache purge and the signing key rotation that the shared password guarded move to ts cache purge and ts keys rotate, which ask the hosting platform with an operator's own token. A publisher who wants a password on a path of its own puts it at its origin or in the hosting platform.

The permission model

Trusted Server is technology that is neutral on policy. Core does not encode any jurisdiction's law or any single policy. A module declares the technical permissions its data use requires, named by the IAB Tech Lab Privacy Taxonomy's data uses as identifiers only, and core runs the module, or passes it a value whose use needs a permission, only when those permissions are held. How a permission becomes held is established outside core by the permission signal modules, from the country when known, from an interaction with the reader, or from data another source provides, and the deployer brings the policy that decides.

How the stack comes to this repository

The pull requests above come here as a stack of feature/<name> branches, one for each row and each based on the one before it, so that they are reviewed and merged here in order. Each pull request links the pull request it came from, so no comment or decision is lost. All 55 rows are here, so the stack arrives complete, with every module in a crate of its own.

The design document each row links records two or more review rounds in a "Review log" section at its foot, a deep first round and then rounds that check its fixes and new text, each started afresh.

Related

Activity

  1. jwrosewell commented on Jun 21, 2026

    @jwrosewell
    CollaboratorAuthor

    Provider wiring: dependency injection

    Recording the provider-wiring approach here, as it is part of this rework rather than a separate issue. Delivered by the neutral-providers PR.

    The pluggable providers are wired by dependency injection rather than handed a fixed evidence struct. A provider's constructor takes the services it needs as trait objects, and the adapter, acting as the composition root, supplies concrete instances per request. Core defines the service interfaces and the host-neutral defaults. The interfaces are RequestInfo (the client IP, User-Agent, and headers) and HostSignals (the TLS JA4 and HTTP/2 fingerprints). Host-specific implementations such as FastlyHostSignals live in their own crates and are injected by the adapter, so core never calls a host SDK and the default request path makes no host-specific call. A provider that needs a service the host cannot supply cannot be built, so the request stops rather than minting a degraded identifier.

    As implemented:

    • Core defines the RequestInfo and HostSignals service traits, with an owned default (OwnedRequestInfo).
    • RuntimeServices carries the optional host-signal service, supplied by the adapter composition root.
    • build_provider and build_device_provider inject the services each provider needs.
    • A provider whose required service the host does not supply fails to build, and the request stops.
    • The neutral built-in providers require no host service, so the default path makes no host-specific call.
  2. added theissue type on Oct 1, 2026
  3. changed the title [-]Pluggable, competition-neutral providers with a technical permission model[/-] [+]Pluggable, competition-neutral modules with a technical permission model[/+] on Oct 7, 2026
  4. 22 remaining items

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions