Skip to content

Let a module declare the caches it loads through - #1373

Open
jwrosewell wants to merge 57 commits into
feature/31-caching-releasefrom
feature/32-cache-features
Open

jwrosewell wants to merge 57 commits into
feature/31-caching-releasefrom
feature/32-cache-features

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Changes

Area Change
crates/trusted-server-core/src 4 files, 300 lines added, 12 removed
docs/superpowers 1 file, 257 lines added, 0 removed
crates/trusted-server-adapter-axum/tests 1 file, 117 lines added, 0 removed
crates/testing/seam-probe 2 files, 64 lines added, 0 removed
docs/guide 2 files, 24 lines added, 0 removed
CHANGELOG.md 1 file, 1 line added, 0 removed
Cargo.lock 1 file, 1 line added, 0 removed

Closes

Closes #1320

Spec

Spec: module-cache-declarations

Test plan

CI on this pull request at 56dd3e8 passed all 20 checks.

  • cargo test-fastly && cargo test-axum
  • cargo clippy-fastly && cargo clippy-axum
  • cargo fmt --all -- --check
  • JS tests: cd crates/trusted-server-js/lib && npx vitest run
  • JS format: cd crates/trusted-server-js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM build: cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1
  • Manual testing via fastly compute serve
  • Other: the full workflow set of this repository, run on this pull request at 56dd3e8

Checklist

  • Feature PRs: spec linked above, ending in a review log of two or more review rounds
  • Changes follow AGENTS.md conventions
  • No unwrap() in production code (clippy denies unwrap_used in CI)
  • Uses log macros as AGENTS.md asks (not println!)
  • New code has tests
  • No secrets or credentials committed

On top of the move of the loading cache module to the released caching crate, fiftyone-caching 4.5.13 (#1372). Issue: #1320.

What changed after the 51Degrees PR review

Agreed at the review on 23 October, point 2. The 51Degrees loading cache is pluggable through modules, and the publisher asset feature becomes a module.

  • The probe's cache test no longer counts a stock loading cache. It links a second loading cache module beside the probe's, because a stock build links none, and checks that a build that links none keeps nothing.
  • The declared cache example names a module a deployment links. The configuration guide's example with module = "51degrees" holds answers only in a deployment that links crates/loading-cache/51degrees.
  • This pull request's copy of the module cache declarations design takes its final text from Add the integration seam design specs #1342, which says that a build that links one loading cache module, rather than a stock build, holds a declared cache's answers.

Fixes found in review

  • The design copy calls this pull request ready, where its header said draft.

Kept current

What this adds

A module declares the caches it loads through, by name, on its builder, IntegrationBuilder::with_cache_features(&["example-answers"]). Core reads a [cache.<name>] table for each declared name as it reads its own [cache.robots-txt], and refuses a table whose name no linked module declares, naming the ones it could be, both in ts config validate and when the service starts. A name is the module's own: a builder declaring core's robots-txt, or a name another builder declares, is refused when the caches are resolved, so two vendors never share one cache and its keys without a word. LoadingCaches keys its selections by name rather than by a fixed list, and CacheSettings::loading_caches returns core's own table first and the declared ones after it, in name order. A declared cache with no table, like a table naming no module (#1365), takes the one loading cache module the build links, so a deployment that links one holds a module's answers without a line in the document, and a build that links none or several keeps nothing. No stock build links one, so a deployment that wants copies kept hands a loading cache module's builder to its adapter.

[cache.example-answers]
module = "51degrees"

That table is refused unless the build links crates/loading-cache/51degrees, which no stock build does.

The seam probe declares seam-probe-answers and offers a loading cache of its own, and the Axum adapter's seam tests prove from outside core that the table selects it beside a second loading cache module, that a declared cache with no table takes the one module linked and keeps nothing with none or two linked, and that a misspelt table is refused by the deploy check with the message startup gives.

Why

A module that holds its own answers, one service answer that every page of a deployment asks for, asked core for the cache of the name it chose, found no table for it, and got the cache that holds nothing, so every request loaded the answer again. Measured on one deployment at six service calls per page request where one is needed, with a loading cache linked and nothing in the document able to say the module's cache existed, because core read a fixed list of names.

What breaks

Nothing in a deployment's documents. CacheSettings no longer rejects an unknown [cache.<name>] table when the document is parsed. ts config validate refuses it instead, as the service does when it starts, if no linked module declares the name.

The commits

Commit What it does
d37d283 A module declares the caches it loads through
7d0f70e The chain below merged in, carrying the loading cache default
d9656fd A declared cache with no table takes the one loading cache module the build links
1133273 Review: the deploy check refuses what the cache build refuses, a duplicate or robots-txt declaration is refused, the seam probe declares and offers a cache, and the guide names a fictional module
0f84dd6 The probe compares the two refusals of a misspelt cache table by message
6fe25f7 The cache check's test compares the two refusals of a misspelt table by message
0ef3ff7 The module cache declarations design
be4f478 The module cache declarations design takes its round 1 review
414ccfa The design header names the pull request that carries it
6e752f2 The module cache design names the shared store on each adapter
9786f09 The configuration guide says what a declared table changes and when to push it
613b386 The integration guide lists the builder method that declares a module's caches
97fc713 The cache declaration checks are pub(crate), since only core calls them
e0a8a90 The module cache design takes its four follow-ups out of the open questions
9266831 The module cache design ends with its review log, as the other designs do
ce141ad The module cache design says the deploy check refuses a module nothing offers
084cf79 The probe's cache test links a second loading cache module beside the probe's, because a stock build links none, and checks that a build that links none keeps nothing
d3c0d4a The configuration guide's declared cache example, which names the 51Degrees loading cache module, says it holds only in a deployment that links that module
f9c7cb9, 1539206 This row's copy of the module cache declarations design takes its final text from #1342

The other commits merge the branch below into this one, and through it Tech Lab main at 7aa5c99.

What is not in this pull request

  • A way to hold nothing in a build that links one loading cache module. A table names a module that offers a cache, and one naming anything else, none included, is refused when the service starts.

jwrosewell and others added 13 commits October 13, 2026 00:43
A deployment selects a loading cache for each feature in its own
[cache.<name>] table, and core listed one feature, robots-txt, so a
module's own cache was never selected and every one of its loads ran on
every call. A builder now declares the caches its modules load through,
by name, [cache.<name>] is read for each declared name with the same
settings as [cache.robots-txt], and a table naming a cache no linked
module declares is refused when the deployment starts, naming the ones
that are declared.
A cache name no linked module declares is refused by validate_settings_for_deploy_with as it is when the caches are made, so a misspelt [cache.<name>] fails ts config validate and not the deployment. A builder declaring robots-txt, or a name another builder declares, is refused naming the builders. The seam probe declares seam-probe-answers and offers a loading cache of its own, and the Axum seam tests prove the table selects it from outside core. The guide names a fictional module.
The debug form of a report carries a backtrace where the test runner asks
for one, as CI does, and the deploy check and startup raise the refusal on
different stacks, so the comparison held only while both were inlined
alike. The message is what the test is about.
…by message

As with the probe's test: the debug form of a report carries a backtrace
where the test runner asks for one, and the deploy check and the cache
build raise the refusal on different stacks.
Series 32 (#1373, for issue #1320) had a pull request and an issue but no design document. This one describes what the code does, adapter by adapter, with the configuration and its validation, the consent and privacy position, the failure handling, the rollout for existing deployments and the tests that exist, and it says plainly which joins have no test.
@jwrosewell
jwrosewell added this pull request to stack #1401 October 15, 2026 17:56
Review round 1 of the design document found three blocking points. A declared table's lifetimes are range-checked and then applied by nothing, two modules of one publisher keep their copies apart only by a naming convention that nothing checks, and the changelog entry left out the public declared field and the Vec return.

The document now states each as the code stands, adds the order of a push, the other callers of loading_caches_from, the name forms core does not check, the paths with no test and four open questions, and drops the service call figure, which has no source. The changelog entry now names the declared field and the Vec return.
@jwrosewell
jwrosewell removed this pull request from stack #1401 October 15, 2026 20:51
Three statements that were only partly true now say what the code does, and the round 1 log sentence no longer claims that every code change waits on a decision. The guide, rustdoc and visibility follow-ups are listed under the open questions with their files and lines.
…s do

Each of the 53 designs of the stack that carries both sections puts the
revision record before the review log, and this one put it after. The
text of both sections is unchanged.
…g offers

Since the loading cache change, validate_settings_for_deploy_with calls check_loading_cache_modules, so the deploy check refuses a table whose module names a crate that offers no loading cache, as the state build does. Section 2.7 said the state build alone refused it, and section 3 listed the check as missing. Section 3 now keeps the one limit left, that ts config validate refuses a deployment's own loading cache module unless a tool registers it.
@jwrosewell
jwrosewell removed this pull request from stack #1408 October 18, 2026 20:15
@jwrosewell
jwrosewell added this pull request to stack #1418 October 19, 2026 12:18
@jwrosewell
jwrosewell removed this pull request from stack #1418 October 19, 2026 16:30
@jwrosewell
jwrosewell added this pull request to stack #1421 October 19, 2026 17:38
@jwrosewell jwrosewell changed the title A module declares the caches it loads through Let a module declare the caches it loads through Oct 19, 2026
@jwrosewell
jwrosewell removed this pull request from stack #1421 October 19, 2026 18:29
@jwrosewell
jwrosewell added this pull request to stack #1422 October 19, 2026 19:20
@jwrosewell
jwrosewell marked this pull request as ready for review October 19, 2026 20:23
a_cache_the_probe_declares_is_selected_in_its_own_table counted the
51Degrees module as linked by the stock list, which now links no loading
cache module. Its first case links a second loading cache module beside
the probe's, a test builder offering core's MemoryLoadingCache, so only
a table that is read keeps values, and a second case with the same build
and no table keeps nothing. With the probe's cache alone, a declared
cache with no table takes it, and with no loading cache module linked it
keeps nothing, so those two assertions flip.

The comment in core above the step for a declared cache with no table
says that a deployment that links one loading cache module holds a
module's answers, where it said a stock build did.
The configuration guide said that [cache.example-answers] with
module = "51degrees" asks the service once however many requests carry
the same evidence. A stock build refuses that module, so the guide now
says that this holds in a deployment that links
crates/loading-cache/51degrees.
@jwrosewell
jwrosewell removed this pull request from stack #1422 October 28, 2026 11:47

This branch has not been deployed

No deployments
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.

A module cannot hold its own answers in a loading cache, because core reads one cache table

2 participants