Skip to content

Declare the Model Terms cookie name in the module that reads it - #1304

Closed
Jamesr51d wants to merge 514 commits into
IABTechLab:mainfrom
jwrosewell:split/17-cookie-constant
Closed

Jamesr51d wants to merge 514 commits into
IABTechLab:mainfrom
jwrosewell:split/17-cookie-constant

Conversation

@Jamesr51d

@Jamesr51d Jamesr51d commented Oct 12, 2026 •

Copy link
Copy Markdown

Stacks on auction telemetry as a module (#1303). The additions that follow the seven pull requests open here are listed in #777.
Compare split/16-analytics with split/17-cookie-constant
to see only this pull request's change.

COOKIE_MTM_PREF, the name of the cookie a preference platform writes the Model Terms for Marketing preference into, sat in core's constants. The Model Terms signal crate (crates/permission-signal/mtm) is the only code that reads the cookie. The constant moves to that crate, with its comment, and core names one standard less.

Nothing else changes. The cookie's name is the same, the module reads it as before, and the Axum adapter's test of the signal takes the name from the crate.

How it was verified

CI passed on f3cf80046 on the fork.

References #1275.

Ten resolve tests built the same request and context and differed only
in a value and the answer they expected. They become two tables that
name the case in every assertion and keep every case.

resolve_answers_204_with_no_cookie_when_it_creates_nothing covers the
closed permission gate, no module, no identity graph and a value that
fails verification. resolve_refuses_a_request_it_cannot_take covers no
Origin, a foreign origin, a sibling subdomain, plain http, a port, a
form body and a body over the limit, and now also asserts that each sets
no cookie. Both fail when the origin and gate checks are taken out.
The workspace pins the edgezero adapters to a revision rather than the
v0.0.8 tag, and the inspector resolves against the same crates, so its
own lock follows.
The header double's mint flag becomes the identifier it returns, so a
test can post an identifier the cookie cannot carry, and a second helper
takes a request the test builds itself.

Three tests are added, each failing with the behavior it covers broken:
an identifier outside the cookie bounds is refused with 400 and leaves
no cookie and no identity-graph row, a failed identity-graph write
answers 503 with no cookie, and a Content-Length over the limit is
refused before the body is read.

The reserved-effect tests say created where they said minted, and the
comments say what the code does rather than what it once did.
The docs format job also runs prettier over the Markdown outside docs/,
which rejected both files. This is prettier's own output, with no change
to the wording.
Three tests built the same ClientResolveInput and differed only in the
module, the payload and the identifier expected. They become one table
naming each case: client_fixed with the known word creates the
identifier, client_fixed with another word creates nothing, and hmac
creates nothing from any payload because a server-side module inherits
the no-op resolve_from_client default.
Brings the four commits that fixed the permission branch's CI: the
inspector no longer calls a removed method, its lock follows the
workspace's edgezero revision, and prettier's formatting of the two
permission guide pages, the agent guide and the permission signal README.

# Conflicts:
#	AGENTS.md
What an operator selects to supply a capability is a module, and provider
keeps the one meaning it has on main, an auction provider instance. This
renames the words this branch adds on top of the permission model, which
already says module, and only those words: every provider word was
compared with upstream main, and a word that exists there is untouched,
as is the icu_provider crate the permissions inspector's lock file names.

- ClientFixedProvider is ClientFixedModule, CLIENT_FIXED_PROVIDER_KEY is
  CLIENT_FIXED_MODULE_KEY, and check_named_provider_configuration is
  check_named_module_configuration.
- The test doubles ResolveHeaderProvider and TestIdProvider are
  ResolveHeaderModule and TestIdModule, HEADER_PROVIDER_ID is
  HEADER_MODULE_ID, and the test helpers and test names say module.
- The plain word says module wherever it meant an Edge Cookie module, in
  the resolve endpoint, the cookie and finalize code, the integration
  registry, the demonstration page script, the cargo feature's
  description and the API reference.
resolve_conflicts_when_a_different_identity_already_exists built its
context by hand with no module, so once the endpoint stopped rebuilding
one it answered 204 for no module where the test expects the 409
conflict. The context now carries the module the settings select, as the
other resolve tests' contexts do.
Brings main at 7a0ecb4 and the refreshed lower branches into the
documentation set. Nine of the eleven conflict blocks differed only by the
module rename and are settled as this branch's text with the rename
applied. By hand: the evidence module keeps the HostSignals trait where
this branch moved it, the setup guide keeps this branch's description of
the ec_id value ahead of main's text on grouped mappings, and the Edge
Cookie guide keeps the client_fixed paragraph and takes main's
completion-marker text for the ec_identity_store paragraph where this
branch moved it.
What an operator selects to supply a capability is a module, and provider
keeps the one meaning it has on main, an auction provider instance. This
renames the words this branch adds on top of the client resolve path,
which already says module, and only those words: every provider word was
compared with upstream main, and a word that exists there is untouched,
as is the icu_provider crate the permissions inspector's lock file names.

- The environment overrides the configuration guide and the error
  reference show read TRUSTED_SERVER__EC__MODULE,
  TRUSTED_SERVER__DEVICE__MODULE and TRUSTED_SERVER__GEO__MODULE, and the
  selectors in every example read module.
- The configuration, Edge Cookie, setup, error reference and Fastly
  guides, the example settings, the evidence module's documentation and
  the no-client-IP test's message say module wherever they meant an Edge
  Cookie, device or geo module.
Brings the fix that threads the selected module into the resolve conflict
test's context.
…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.
Jamesr51d and others added 23 commits October 13, 2026 14:10
…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

Copy link
Copy Markdown
Collaborator

Moved into this repository as #1358, 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.

@jwrosewell jwrosewell closed this Oct 15, 2026
jwrosewell added a commit to jwrosewell/trusted-server that referenced this pull request Oct 16, 2026
Row 27 renames the EIDs cookie constant and row 41 removes it from core, and IABTechLab#1304 is named as closed unmerged in favour of IABTechLab#1358.
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.

2 participants