Repository navigation
Fold a build-time core source digest into the template fingerprint - #1210
Conversation
The template cache key only covered settings and JS bundle hashes, so edits to Rust-inlined head scripts such as gpt_bootstrap.js (and any other core source change) kept serving stale cached templates after a deploy. build.rs now hashes every file under src/ plus the core build script, core and workspace manifests, and the workspace lockfile into a SHA-256 digest that template_fingerprint mixes in first.
aram356
left a comment
There was a problem hiding this comment.
Summary
Folds a SHA-256 of every core source file, the core build script, both manifests and the lockfile into template_fingerprint. This closes #1198 without a list to maintain. I checked incremental builds at 8eff2ed with cargo check: editing gpt_bootstrap.js rotates TEMPLATE_BUILD_DIGEST, reverting restores it, and adding or removing a nested file rotates and restores it too. One edge case in the source walk breaks the build and needs a fix. The other notes cover docs accuracy and CI coverage.
2 of the inline comments below carry a one-click GitHub
suggestion. Use Commit suggestion (or Add suggestion to batch for both) to apply them as commits on the PR branch. The remaining comment describes its fix in prose because it spans two files.
Blocking
🔧 wrench
- Editor and OS dotfiles under
src/break the core build: see inline atcrates/trusted-server-core/build.rs:97
Non-blocking
🤔 thinking
- The remaining manual-bump list names things the digest already covers: see inline at
crates/trusted-server-core/src/platform/template_cache.rs:33
⛏ nitpick
- Generated const can be private: see inline at
crates/trusted-server-core/build.rs:33
Cross-cutting / body-level findings
-
🌱 The native-only digest tests are outside the lint gate and the documented local gates.
tests/template_build_digest.rsis#![cfg(not(target_arch = "wasm32"))], soclippy-fastly(wasm32) compiles it, and the#[path = "../build.rs"]module inside it, to an empty crate. No other clippy step builds core's tests on the host. The file is clean today (cargo clippy -p trusted-server-core --test template_build_digest -- -D warningsat 8eff2ed), but nothing keeps it that way. The test step was also added only totest.yml, so contributors who follow the AGENTS.md CI gate list never run it locally. Following the CLI and codegen precedent informat.yml:# The build-digest tests are native-only, so clippy-fastly compiles them # to an empty crate. Lint them on the host. - name: Run host-target core build-digest test clippy run: cargo clippy --package trusted-server-core --target x86_64-unknown-linux-gnu --test template_build_digest -- -D warnings
Also add
cargo test -p trusted-server-core --test template_build_digestto the AGENTS.md CI Gates list.
CI Status
- cargo test: PASS (required)
- cargo fmt: PASS (required)
- format-docs: PASS (required)
- format-typescript: PASS (required)
- cargo test (axum native): PASS
- cargo test (ts CLI, native): PASS
- cargo test (cross-adapter parity): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- vitest: PASS
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
- CLAUDE.md symlink guard: PASS
- CodeQL: PASS
- Analyze (rust): PASS
- Analyze (actions): PASS
- Analyze (javascript-typescript): PASS
dhruv8sh
left a comment
There was a problem hiding this comment.
Summary
Folding a SHA-256 digest of core sources, build inputs, and the lockfile into the template fingerprint is a sound, safely over-invalidating fix for #1198, and the digest construction and tests are solid. One blocking issue: the build script panics when an editor lock symlink sits in src/, which I reproduced locally.
2 of the inline comments below carry a one-click GitHub
suggestion— use Commit suggestion (or Add suggestion to batch for several at once) to apply them as commits on the PR branch. The remaining comments describe the fix in prose because the change restructures more than one contiguous range or is informational.
Blocking
🔧 wrench
- Editor lock symlink in
src/panics the build — see inline atcrates/trusted-server-core/build.rs:97
Non-blocking
♻️ refactor / 📝 note
- Watched and hashed input lists can drift — see inline at
crates/trusted-server-core/build.rs:15 - Docs should name the non-core crate gap — see inline at
docs/guide/configuration.md:2358 #[path]include limits build.rs to core's normal deps — see inline atcrates/trusted-server-core/tests/template_build_digest.rs:11
👍 praise
- Digest construction and test seam — see inline at
crates/trusted-server-core/build.rs:81
CI Status
- browser integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- integration tests: PASS
- CodeQL: PASS
- cargo test (ts CLI, native): PASS
- CLAUDE.md symlink guard: PASS
- vitest: PASS
- Analyze (actions): PASS
- cargo test: PASS (required)
- Analyze (javascript-typescript): PASS
- cargo fmt: PASS (required)
- cargo test (axum native): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- format-docs: PASS (required)
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- cargo test (cross-adapter parity): PASS
- format-typescript: PASS (required)
- Analyze (rust): PASS
- prepare integration artifacts: PASS
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Review summary
Approval is conditional on the author addressing the outstanding comments from the other reviewers to their satisfaction before merge. This approval does not override their requested changes or resolve their threads.
Reviewed 8eff2edbf69964e57104ac05800d02c074fe5f80 against a4e01eb55fe940bd02b2426dccd46050704c54c5 in two passes. I found no additional actionable issues beyond the existing feedback. The build digest is correctly incorporated into the template-cache key, and the traced lookup, storage, and assembly paths preserve the existing cache contracts.
Validation
- Native build-digest tests: 6 passed.
- WASI fingerprint tests: 6 passed; cache-key field isolation test: 1 passed.
- Publisher template-cache end-to-end tests: 70 passed.
- Fastly template-cache tests: 14 passed.
BID_DELAY=3 ./scripts/template-cache-local-test.sh esi: 22 passed, including the cookie-variant matrix, session bypass, private responses, and streamed assembly.- Independently recomputed the digest over all 132 declared inputs and matched the generated artifacts; checked Cargo's recorded watch set.
cargo fmt --all -- --check, host clippy fortemplate_build_digest, andcargo clippy-fastly: passed.- All 20 reported CI checks passed.
Cross-deployment rollover and source-edit-triggered incremental rebuilding were not independently exercised. Non-core workspace source changes remain outside the digest by design.
Preserve manifest-derived config-store defaults while merging main. Ignore hidden editor and OS artifacts, share watched and hashed build inputs, and include the EdgeZero manifest in the digest. Clarify schema-bump requirements, keep the generated digest private, and add native digest lint and local verification gates. Verified all CI gates locally: Rust format, nine clippy commands, four adapter test aliases, native digest tests, parity, JS build and 1185 tests, JS format, and docs format.
dhruv8sh
left a comment
There was a problem hiding this comment.
Summary
Re-review at a18001f1. Every finding from the previous round is resolved: dot-prefixed entries are skipped before the file-type check, the watched and hashed input lists are shared, the schema-version docs name the non-core gap, the generated const is private, and the native digest tests have their own clippy/test gates. I also reproduced the original Emacs lock-file case with a real build: with a dangling src/integrations/.#gpt.rs symlink, cargo check -p trusted-server-core reruns the build script once, succeeds, and is Fresh on the next run. Only non-blocking notes remain.
1 of the inline comments below carries a one-click GitHub
suggestion. Use Commit suggestion to apply it. The other inline comment describes its fix in prose because it would also need a test in another file.
Non-blocking
⛏ nitpick
- Docs paragraph has an overlong line and an early break: see inline at
docs/guide/configuration.md:2374 - Non-dot editor artifacts are still hashed: see inline at
crates/trusted-server-core/build.rs:127
Cross-cutting / body-level findings
- 🌱 The lockfile input is workspace-wide.
workspace/Cargo.lockandworkspace/Cargo.tomlchange on any dependency bump in the workspace, including CLI-only or Axum-only ones, so each such bump causes a cold template fill per URL variant on the next deploy. The PR description accepts this as intentional over-invalidation, and that's a reasonable trade-off for now. If it becomes noticeable, a tighter option is to hash only core's resolved dependency subgraph (for example, fromcargo metadataor theCargo.lockentries reachable fromtrusted-server-core) instead of the whole lockfile.
CI Status
- cargo test: PASS (required)
- cargo fmt: PASS (required)
- format-docs: PASS (required)
- format-typescript: PASS (required)
- cargo test (axum native): PASS
- cargo test (ts CLI, native): PASS
- cargo test (cross-adapter parity): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- vitest: PASS
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
- CLAUDE.md symlink guard: PASS
- CodeQL: PASS
- Analyze (rust): PASS
- Analyze (actions): PASS
- Analyze (javascript-typescript): PASS (both runs)
Keep canonical settings hashing from main inside the build-digest-aware template fingerprint. Preserve stable context allowlist cache keys and source-based cache invalidation without rewriting branch history. Verify Rust formatting, all clippy gates, four adapter test aliases, native digest tests, parity, CLI config overlays, JS build and tests, and JS/docs formatting.
Exclude Emacs auto-save and backup files, with regression coverage. Rewrap the template-cache documentation as requested in review.
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Approved pending resolution of other reviewer comments.
aram356
left a comment
There was a problem hiding this comment.
Summary
Re-review at 7c6ab3c. All four round-1 findings are fixed, and I re-ran their repros on a real build. With a dangling .#gpt.rs lock link, cargo check succeeds and the next run is Fresh. Editor auto-save and backup files leave the digest unchanged. The schema-version docs name the non-core gap, the generated const is private, and the native digest tests have their own test and clippy gates. Incremental builds still rotate TEMPLATE_BUILD_DIGEST when gpt_bootstrap.js, edgezero.toml, or the set of source files changes, and restore it on revert.
What remains is from the merge with main. main's build.rs now loads edgezero.toml, and the digest runs before it, so a missing manifest no longer produces main's named error. There is also one stale test comment.
Both inline comments describe their fix in prose. The fixes touch lines outside this diff's hunks, so they can't be one-click suggestions.
Blocking
🔧 wrench
- Computing the digest before the manifest load hides
main'sedgezero.tomldiagnostic: see inline atcrates/trusted-server-core/build.rs:39
Non-blocking
🏕 camp site
- The v1-predecessor test comment contradicts the new schema-version doc: see inline at
crates/trusted-server-core/src/platform/template_cache.rs:31
CI Status
- cargo test: PASS (required)
- cargo fmt: PASS (required)
- format-docs: PASS (required)
- format-typescript: PASS (required)
- cargo test (axum native): PASS
- cargo test (ts CLI, native): PASS
- cargo test (cross-adapter parity): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- vitest: PASS
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
- CLAUDE.md symlink guard: PASS
- CodeQL: PASS
- Analyze (rust): PASS
- Analyze (actions): PASS
- Analyze (javascript-typescript): PASS (both runs)
dhruv8sh
left a comment
There was a problem hiding this comment.
Summary
Folds a build-time SHA-256 digest of core sources and build inputs into the template fingerprint, so edits to Rust-inlined head scripts (and any other core change) select a new cached template without a manual schema bump. The hashing is well framed and well tested; the notes below are non-blocking.
1 of the inline comments below carries a one-click GitHub
suggestion— use Commit suggestion to apply it as a commit on the PR branch. The remaining comments are discussion or describe a fix in prose because it touches lines outside the diff.
Non-blocking
🤔 thinking / ⛏ nitpick
- Existing seam tests still say a seam change must bump the schema — see inline at
crates/trusted-server-core/src/platform/template_cache.rs:30 - Digest scope is broader than template-shaping code — see inline at
crates/trusted-server-core/build.rs:17 - "non-hidden" undersells what the source filter skips — see inline at
crates/trusted-server-core/build.rs:71
👍 praise
- Length-framed, path-independent hashing with regression tests — see inline at
crates/trusted-server-core/build.rs:111
Cross-cutting / body-level findings
-
📝 AGENTS.md conflicts with main (CI gate #8 clash) — #1177 landed on
mainand added its own gate8. Markdown format outside docs/ …, and this PR also adds a gate8.(native core build-digest), soAGENTS.mdconflicts and GitHub reports the PR as conflicting. When resolving, keep main's item 8 and renumber this PR's gate to 9:8. Markdown format outside `docs/` (requires `cd docs && npm ci` first): `docs/node_modules/.bin/prettier --config docs/.prettierrc --check "*.md" ".claude/**/*.md" ".github/**/*.md" "crates/**/*.md" "scripts/**/*.md" "tinybird/**/*.md"`; fix with `--write` in place of `--check` 9. Native core build-digest test and lint (`cargo test -p trusted-server-core --test template_build_digest` and `cargo clippy -p trusted-server-core --test template_build_digest -- -D warnings`)
(
publisher.rsauto-merges cleanly with #1180'sall_module_idschange;AGENTS.mdis the only conflict.)
CI Status
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- integration tests: PASS
- CodeQL: PASS
- cargo test (ts CLI, native): PASS
- vitest: PASS
- CLAUDE.md symlink guard: PASS
- cargo test: PASS (required)
- format-docs: PASS (required)
- cargo fmt: PASS (required)
- cargo test (axum native): PASS
- format-typescript: PASS (required)
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo test (cross-adapter parity): PASS
- prepare integration artifacts: PASS
- Analyze (actions): PASS
- Analyze (rust): PASS
- Analyze (javascript-typescript): PASS
Run the digest after the edgezero.toml block so a missing or invalid manifest reports main's named Cargo error instead of an unnamed read panic. Align the seam and v1-predecessor test comments with the build-digest schema rule, and describe the editor-artifact source filter precisely.
Resolve AGENTS.md CI gate conflict: keep main's markdown-format gate as item 8 and renumber the native core build-digest gate to item 9.
The template cache fingerprint now includes a build-time SHA-256 digest of core sources and build inputs. Changes to Rust-inlined head scripts therefore select a new template without a manual schema bump.
The digest uses sorted logical paths and length-framed path/content pairs. It covers non-hidden core sources, core build.rs and Cargo.toml, workspace Cargo.toml, edgezero.toml, and the optional Cargo.lock. Missing and empty lockfiles remain distinct. Editor lock symlinks, swap files, OS metadata, and hidden directories do not affect the digest.
The review fixes share the watched and hashed input lists, make the generated constant private, and document the remaining compatibility gap: changes outside the digest, such as Fastly entry storage or the Rust side of trusted-server-js, still require a TEMPLATE_SCHEMA_VERSION bump unless another fingerprint input isolates them. Native digest tests now have a dedicated CI clippy gate and documented local test/lint commands.
Merged main while preserving its EdgeZero manifest loading and compiled default config-store ID. Consolidated the build-dependency sections and added edgezero.toml to the digest because it now affects compiled defaults.
Closes #1198.
Validation:
Any covered source/build-input change causes a cold template fill per URL variant after deployment, even if it does not change rendered HTML.