Repository navigation
Conversation
…seam-impl Brings main at 7a0ecb4 and the refreshed chain below this branch into the seam implementation. The seam made the Edge Cookie, device and geo traits async with a runtime services argument, so the Edge Cookie files the chain refreshed in their synchronous form (the resolve endpoint, the context, the seam trait file, finalization, the edge cookie helpers, pull sync, batch sync and the admin lookup) are taken as the chain has them and put back in the seam's shape, with the seam's own tests that read the config store through the services restored. Main's changes that the seam had moved out of core are carried into the seam's implementations: a Prebid Server stored request is sent only when the slot's intent allows the fallback, an implementation marks an impression it has no demand for as omitted, the driver leaves those impressions out and makes no request when none is left, and the parse state keeps only the slots that were sent. Main's split between the reader's and the request's origin requirement is carried into the seam's publisher, which keys personalization rather than one vendor's tag. The build script keeps both jobs, the migration guard's generated source list and the manifest's default config store id. The names the lower branches gave their identifiers are applied to the seam's lines, so the seam compiles against the refreshed chain. The seam's own names keep their spelling for its rename commit. Main's new tests that name demand sources with hyphens take the snake_case names the seam requires, and those written against main's plan shape are rewritten onto the seam's demand table.
The lower branches settled the word: what an operator selects in `[ec]`, `[geo]`, `[device]`, `[permission_signal]` and `[integration]` is a module, and `provider` keeps its one meaning in the auction, where `[demand]` and `[adserver]` select the demand sources and the ad server. This applies that to the seam's own lines, which were written before the word was settled. The `[integration]` selector is now `module`, in the settings, the example template, the starter configuration the CLI writes, the audit draft and every fixture. The registry's declared capabilities follow: a module declares a `geo_module`, an `ec_module` or a `device_module`, the registry resolves `resolve_geo_module`, `resolve_ec_module` and `resolve_device_module`, and the reserved selector values are `GEO_MODULE_NONE`, `GEO_MODULE_PLATFORM`, `DEVICE_MODULE_BUILTIN` and `DEVICE_MODULE_FASTLY`. Startup refusals name the `module` key they are about, so an operator reading one is told the key to edit. The generic provider table, the auction plan, the demand and ad server implementations and the CLI's ad template lint keep `provider`, and the configuration rules, the configuration guide, the example template, the CHANGELOG and the agent notes state the convention with both spellings rather than one word for everything.
The pages that still showed `[auction.providers.<id>]`, `mediator` and `[integrations.<id>]`, which this branch refuses at startup, now show the tables it reads. The error reference, the ad serving overview, the auction testing guide, TESTING.md and the CLI's README carry `[demand.<name>]` examples with the implementation named, `[adserver] provider` in place of the mediator, and `[integration] module` as the switch. The API reference's registration predicates say `named`, meaning the id is in `[integration] module`, rather than an `enabled` key that no longer exists. The configuration reference loses its `[integration.adserver_mock]` and `[integration.aps]` sections, because the ad server mock is configured under `[adserver.adserver_mock]`, documented in the ad server section, and APS has no browser table of its own any more. The ad server mock guide is rewritten on the same terms, with the word mediator gone.
The command still parsed `[auction.providers.<id>]` with a `profile` and `[integrations.prebid]` with an `enabled` key, so on a configuration written for this branch it found no Prebid Server demand at all and said so without error. It now reads the `[demand.<name>]` tables, taking those whose implementation is `prebid_server`, whether by an `implementation` line or by the table's name, with `debug`, `test_mode` and the bid parameter override rules flat in the table where they now live, and it reads the browser settings from `[integration.prebid]`. The report says what the configuration selects rather than echoing a flag that is gone. Each demand source carries `selected`, which is whether `[demand] provider` names it, and the report's own `selected` is whether `[integration] module` names `prebid`, in place of `enabled_explicit`. The `source_sections` field names `demand` and `integration.prebid`. The CLI crate does not build on the machine this was written on, so the readers were compiled and run against the branch's core crate in a scratch crate with the same fixture, and the CLI's own tests run in CI.
The merge of the permission model into this branch settled the inspector's `Cargo.lock` through the same rename that turned provider into module in the code, and the crate `icu_provider` became `icu_module`, a package that does not exist. The inspector still built, because its build script runs cargo without `--locked` and cargo re-resolved the crate from the registry each time, so the fault was invisible to CI and visible to anyone reading the file. The three lines name the crate again, and `cargo check --locked` accepts the lockfile as written.
Brings the inspector lockfile fix, which names the icu_provider crate again.
…seam-impl Brings the inspector lockfile fix, which names the icu_provider crate again.
The template cache harness builds its configuration from the example template and switched Prebid on by rewriting the template's selector line. The rename left it writing `provider = ["prebid"]`, which this branch reads as a settings table for an integration called `provider`, so `ts config validate` refused the file in CI's three harness runs with "[integration.prebid] and [integration.provider] is configured but not named in [integration] module". The harness now writes `module = ["prebid"]`. The generated configuration, in both the esi and inline modes, loads and passes deploy validation through the core crate's own readers.
A module's name is the path of its crate below `crates/`, with `.` between the parts, taken from `CARGO_MANIFEST_DIR` when the crate is built, so the name cannot drift from the folder and no crate carries a hand-written id. `module_name!()` gives a crate its own name, `module_name::resolve` finds the name an operator wrote among the modules offered, as written or with the section's type folder in front, and `module_name::short_form` gives the name back without that folder. Core's own modules keep bare names. The Edge Cookie side is the first to use it. The type folder of every Edge Cookie crate is `edgecookie`, so `[ec] module` may name an injected module in full or with that folder left off, and an `implementation` line may do the same. The rule for a name written in `[ec]`, its blocks and their `implementation` lines is the module name rule, parts joined by `.`, each of lower case letters, digits, `_` or `-`, in place of snake_case.
Brings the naming module, so a module is named by its crate folder, and the Edge Cookie side resolving a written name within its type folder. The host-signal module's key and the type folder sit side by side.
Brings the naming module from the Edge Cookie seam, so a module is named by its crate folder.
Each of the five modules takes its name from its crate folder through `module_name!()`, so `crates/permission-signal/gpp` is `gpp` and `crates/permission-signal/us-privacy` is `us-privacy`, where the two had called themselves `gpp_sale_opt_out` and `us_privacy` by hand. The page is told a signal's source by the short name, without the type folder. The section is `[permission-signal]`, named exactly as its folder, and its key is `modules`, a list, because signals compose where `[ec]`, `[geo]` and `[device]` each name one module. A name in the list may be written in full, as `permission-signal.gpp`, or with the type folder left off, and the refusal of a name this build does not offer lists the short names. A configuration still carrying `[permission_signal]`, a `module` key or the retired `sources` key is refused with directions to the new spelling.
Brings the naming module and the permission signal modules named by their crate folders, with [permission-signal] modules. The Edge Cookie module file keeps the client_fixed key beside the type folder, and the agent guide's capability table keeps this branch's rows with the permission signal selector as [permission-signal] modules.
Brings the naming module, the permission signal modules named by their crate folders and [permission-signal] modules, with their guides.
A name written in `[ec] module`, an `[ec.<name>]` block or an `implementation` line is parts joined by `.`, each of lower case letters, digits, `_` or `-`, in place of snake_case, and a module from a crate may be written in full, as `edgecookie.<name>`, or with that type folder left off. The sections table names `[permission-signal]`.
…seam-impl Brings the naming module, so a module is named by its crate folder, the permission signal modules named that way with [permission-signal] modules, and the guides stating the module name rule. The adapters and the template take the chain's permission signal wording, the settings keep both the removed-integrations refusal and the chain's refused_table! machinery, and the agent guide and the configuration guide keep this branch's tables with the chain's selector and name rule. The Fastly, Cloudflare and Spin adapters keep the chain's name for the resolved Edge Cookie module held in their application state, ec_module, at every use.
`[demand]` selects its sources with `modules`, a list, `[adserver]` is `[ad-server]`, the name of the type folder its implementations will live in, and selects with `module`, and a bidder route in `[auction.bidders]` names its demand source with `module`. The generic table takes the key from its selection type, `modules` where several run and `module` where one does, and refuses a `provider` key with the key to write instead. A configuration still carrying `[adserver]` is refused with its new name. Both refusals have tests. With that the word provider has left the configuration altogether, so the configuration rules, the guide, the template, the CHANGELOG and the agent notes read as one rule again: every type selects a module, with `module` or `modules`, and a module's name is its crate folder, with a `[demand]` or `[ad-server]` name staying snake_case because it may be a label of the operator's own. The implementation ids `openrtb`, `prebid_server`, `aps` and `adserver_mock` keep their spelling here; their move to the type paths of the folders they will live in comes with the type sections.
`[integration]` is gone. A page integration is a module named by its crate folder, `cmp.didomi`, `tag.google-tag-manager`, `ad-tag.google`, `ad-tag.google.diagnostics`, `bot-protection.datadome`, `identity.lockr`, `audience.permutive`, `framework.nextjs`, `auction.prebid` and `testing.testlight`, with `js_asset_proxy` one of core's own, and it is selected in the section of its type, written there with the type folder left off: `[cmp] module = "didomi"`, `[tag] modules = ["google-tag-manager"]`, `[ad-tag] modules = ["google", "google.diagnostics"]`, `[auction] modules = ["prebid"]` and `[proxy] modules = ["js_asset_proxy"]`. A module's settings live in the table at its name beneath that section, so `[integration.prebid]` is `[auction.prebid]`. Every top-level table core does not read itself is the section of a module type, read into `TypeSections`, and `[proxy]` and `[auction]` select modules beside their own settings. A section that selects nothing, a table its section does not select, a name selected in two sections and a name no module in the deployment supplies are each refused at startup, and `[integration]` and `[integrations]` are refused with directions. A builder carries its module name and the section that selects it, the registry runs a builder when a section selects its module, and deploy validation checks the sections before anything else. The seam probe moves to crates/testing/seam-probe and names itself from that folder, so `[testing] modules = ["seam-probe"]` selects it. The audit generator writes each detected module's section, the bundle and inspect commands read `[auction.prebid]`, the environment overlay names a section as written (`TRUSTED_SERVER__AD-TAG__GOOGLE__GAM_ATTRIBUTION_ENABLED`), and the guides, the template, the changelog and the agent notes describe the sections. The implementation ids `openrtb`, `prebid_server`, `aps` and `adserver_mock` keep their spelling for now.
The native-integration note formats the detected integration's section and name from a String, so the lookup takes a borrow and the fallback clones.
The four implementations this repository ships are named `auction-protocol.openrtb`, `auction.prebid-server`, `auction.aps` and `ad-server.mock`, the module paths the design gives the crates they move to, in place of the ids `openrtb`, `prebid_server`, `aps` and `adserver_mock`. A `[demand.<name>]` table names its implementation on an `implementation` line by that path, because `demand` is not the type an implementation is named under, and `[ad-server] module = "mock"` resolves within its own type as a name does in every other section. The plan resolves a written name with the module name resolver, and when the build has no such implementation it lists the ones it has as the section would write them. APS keeps `aps` as its bidder and response name on the wire. The table's validation still named the `provider` key in its messages after the key became `modules` and `module`. The messages name the key the table reads, and an `implementation` line is checked as a module name. `ts prebid server inspect` recognises a Prebid Server table by its `implementation` line. The tests, the fixtures, the example configuration, the guides, the changelog and the agent notes use the names, and the migration tables gain the row for the `prebid-server` and `aps` profiles.
Selecting page integrations in the section of their type left messages, comments, guides and the environment example pointing at settings under the `[integration]` table, which is now refused, and left the configuration reference documenting an `enabled` key that a module's table no longer takes. An operator following any of them was sent to a place that does not exist. This brings them into line with the code. What an operator is told - Prebid's bidder parameter validation names `auction.prebid.bid_param_overrides`, `bid_param_zone_overrides` and `bid_param_override_rules`, and the Next.js warning about cross-script payloads names `framework.nextjs.max_combined_payload_bytes`. - `ts prebid client` names `auction.prebid.bundle.modules`, `auction.prebid.managed_user_ids` and `auction.prebid.external_bundle_url` in every message, and `ts prebid server inspect` reports its browser source section as `auction.prebid`. - The external Prebid bundle build script and the browser console error for a client-side bidder with no adapter name `auction.prebid.bundle.modules`. What the guides say - The configuration reference drops the `enabled` row from the DataDome, Didomi, Google Tag Manager, GPT, JS Asset Proxy, lockr and Sourcepoint tables, says the GPT diagnostics module has nothing to set, documents `modules` in the `[proxy]` and `[auction]` tables, and no longer says that `[auction]` selects nothing. Its debug table names `include_adserver_response`, which is the key the code reads. - The integration inventory replaces its Deploy ID column with what the settings write to select each integration, and the API reference keys its rows by integration ID throughout. - The guides said that each page integration section is named by a type folder under `crates/`. That holds for a module with a crate of its own, such as the permission signals. An integration still in core carries the name its crate will have in a `MODULE` constant, so its section and table stay the same when it moves out, and the guides now say so. - `.env.example` names each overlay by the section the setting is in, lists scalar settings only because an overlay cannot replace a list, and no longer points at a section the file does not have. - Prose that still said mediator says ad server, and prose that still said provider profile says demand source or demand implementation. - The Prebid on AWS planning reference names the tables that `ts prebid server inspect` reads. Tests - A demand or ad server implementation named in a page integration's section is refused like any name no module supplies, which the guides state and nothing pinned. - The environment overlay test sets the bidder route's `module` leaf. It was still setting `provider`, which no longer exists, so the overlay it was written to prove did nothing. - The secret redaction test labels the DataDome key by its path under `[bot-protection]`. No behavior changes apart from the wording of the messages above.
Comments on the adapters and two test notes in core described what the code did before it changed. Each now says what the code does and why. - The resolved Edge Cookie module held on the Cloudflare, Fastly and Spin application state is resolved when the state is built, because resolving reads no request data. - The three tests that a selected module the adapter cannot build fails the request say what a default context would do. - The Spin state builder reads its settings from the config store, and its test says why the failure has to be the absence of a config store. - The test that keeps the internal header list in step with the Edge Cookie response headers, and the test for an unknown key in a module block, say what they guard. No code changes.
- The Cloudflare region test says why the region header has to reach the privacy outcome. - The Fastly geo module's re-export and the geo selector's default are described as they are. - The integration fixture's note on the geo selector no longer promises a setting that a later change does not add. No code changes.
- The integration fixture carried two notes on its geo selector that contradicted each other. The one that stays says that Viceroy maps the loopback client to US/CA, so the platform geo module resolves a real place. - That fixture, the Viceroy template, the template cache harness and the permission model guide no longer mention a default country setting, which no released version had. - Five code comments say what the code does without saying what it did before. No code changes.
Core builds the identity-graph key from the module's code and whatever `normalize_id_for_kv` returns, so the method decides what two visits must have in common to be treated as the same visitor. Its documentation described normalization only and advised a module with a case-sensitive identifier to return the value unchanged. That is right for a stable identifier and wrong for one that carries a signature, a nonce or a timestamp, because each reissue then gets a row of its own and the identity does not survive it. The trait documentation now says that the returned value is the identity two visits must share, and that a module whose identifier has a part reissued each time must return the stable part. It also says that core asks `accepts_id` about the returned string as well as about the identifier as issued, so a module must accept its own canonical form, or no row is read or written for it. `two_issues_of_one_identity_share_one_identity_graph_key` drives a fixture module whose identifier is a stable part and a part that changes on each issue through `AcceptedModules::canonical_kv_key`. Two identifiers that differ only in the reissued part reach one key, and a different stable part reaches another. The test fails for a module that returns the value unchanged. No behavior changes.
…d run the Cloudflare auction test with no demand modules The build script's TRUSTED_SERVER__GIT_VERSION reaches test processes and the strict loader refused it as an unknown field. Cloudflare runs one demand source at a time, so the fixture's two demand modules stopped worker startup.
The wasm clock lint reaches core's build script, which runs on the host.
Core's version_header module is removed, with its call from the finalize step of the Axum, Cloudflare and Spin adapters and from the Fastly adapter's health probe and its settings fallback, so no response carries x-ts-version unless a [[serve]] entry names the service_version middleware. That middleware now writes the git version the build compiled in from TRUSTED_SERVER__GIT_VERSION or local git as X-TS-Version, when the build knows one, and the version the adapter reports for the service as X-TS-Service-Version, when it reports one. HEADER_X_TS_FASTLY_VERSION, which nothing wrote, goes with the module. The health tests of the three adapters prove the probe carries no version, the middleware's own tests prove each header is written when its version is known and nothing when neither is, and the publisher tests prove both headers reach a buffered page and neither reaches a page no entry names the middleware for. The configuration guide, the getting started guide, the EdgeZero guide and the changelog say the same.
jwrosewell
marked this pull request as ready for review
October 14, 2026 12:35
This was referenced Oct 14, 2026
Collaborator
|
Moved into this repository as #1359, one branch of the stack, so the review continues there. This pull request is closed in its favor and its comments stay here for the record. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on the Model Terms cookie name (#1304). The additions that follow the seven pull requests open here are listed in #777.
Compare
split/17-cookie-constantwithsplit/18-inmobito see only this pull request's change.
What this pull request does
crates/cmp/inmobi, a consent management platform module for InMobi Choice, the TCF consent prompt a publisher loads from their own InMobi account.Where a
[[fetch]]entry fortext/htmlnamescmp.inmobi, the module's middleware writes three things into the head, in this order, and the stored page every reader is served from carries them.__tcfapiLocatorframe, queues every__tcfapicall made before the prompt arrives, answerspingas a stub, and relays calls posted from frames.pingand the other generic__gppcommands at once with the CMP id, queues every other call for the prompt, creates the__gppLocatorframe, and relays calls posted from frames.Each stub defines nothing where the page already has its interface, and the TCF stub defines nothing where a window above the page, up to the top, already carries a
__tcfapiLocator. The module serves no browser module, because the stubs and the Choice script are the whole client side. The prompt writes the reader's answer to theeuconsent-v2cookie, which core reads on the next request, and the TCF permission signal module reads the record core decodes from it, the way every signal reaches the permission model.The stubs land ahead of the page's own
<meta charset>, so the guide page says to send the encoding inContent-Typeas well.What is refused
script_urlthat is empty, is not a URL, is nothttps, is on a host other thancmp.inmobi.comorcdn.inmobi.com, or carries a user name or password. The value becomes a<script src>on every page, and a settings document reaches the service from a config store rather than from a person reading it. A host that merely contains an allowed name is refused by what it is rather than by what it looks like.[[fetch]]entry fortext/html, because the prompt would never be written.[cmp.inmobi]the module does not read.What a consent prompt module keeps to
The guide page states six things this module keeps to, and they are what every
[cmp]module will be held to: the prompt is written before any vendor's tag, the IAB interfaces are stubbed ahead of the loader, the loader is deferred, the reader's answer reaches the permission model through the permission signal modules and no other path, a script address written into every page is checked at load, and a selected prompt that no entry places is refused.Maintainers
The crate's manifest names the Trusted Server maintainers as its owner, with the status
seeking vendor owner, until InMobi adopt it, as Didomi and Sourcepoint do. With it the stock build has 1 cratevendor owned, 19seeking vendor ownerand 4project owned.CI
The two stubs are tested in a stand-in for the browser with Node's test runner and no packages, as
tests/*.test.mjsbeside the module. The vitest job now runs every module's such tests after the browser bundle's.How it was verified
CI passed on
58312af3aon the fork. Not exercised: no page has been served to a real browser with the prompt loading from InMobi. The stubs run in a stand-in for the browser, and the tag's parts and order are checked as written.References #1276.