Skip to content

Fold a build-time core source digest into the template fingerprint - #1210

Merged
aram356 merged 12 commits into
mainfrom
fix/template-build-fingerprint
Oct 8, 2026
Merged

aram356 merged 12 commits into
mainfrom
fix/template-build-fingerprint

Conversation

@prk-Jr

@prk-Jr prk-Jr commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

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:

  • Nine native digest tests, including regression tests for hidden artifacts, dangling editor-lock symlinks, and the required EdgeZero manifest. The regressions failed before the fixes and passed afterward.
  • Actual build-script smoke: watched inputs, private generated constant, hidden artifacts, source/app-manifest digest rotation and restoration, and config-store ID emission.
  • Rust format and all eight adapter/CLI/codegen clippy aliases, plus native digest-test clippy.
  • All four adapter test aliases and cross-adapter parity tests.
  • JS build, 1,185 tests across 48 files, JS format, and docs format, using pinned Node 24.12.0 for JS tests.

Any covered source/build-input change causes a cold template fill per URL variant after deployment, even if it does not change rendered HTML.

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.
@prk-Jr
prk-Jr marked this pull request as ready for review September 24, 2026 11:32
@prk-Jr prk-Jr self-assigned this Sep 24, 2026
@prk-Jr prk-Jr added this to the 202609 milestone Sep 24, 2026

@aram356 aram356 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 at crates/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.rs is #![cfg(not(target_arch = "wasm32"))], so clippy-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 warnings at 8eff2ed), but nothing keeps it that way. The test step was also added only to test.yml, so contributors who follow the AGENTS.md CI gate list never run it locally. Following the CLI and codegen precedent in format.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_digest to 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

Comment thread crates/trusted-server-core/build.rs Outdated
Comment thread crates/trusted-server-core/src/platform/template_cache.rs Outdated
Comment thread crates/trusted-server-core/build.rs Outdated

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 at crates/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 at crates/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

Comment thread crates/trusted-server-core/build.rs Outdated
Comment thread crates/trusted-server-core/build.rs Outdated
Comment thread docs/guide/configuration.md Outdated
Comment thread crates/trusted-server-core/tests/template_build_digest.rs
Comment thread crates/trusted-server-core/build.rs

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 for template_build_digest, and cargo 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.

prk-Jr and others added 2 commits October 1, 2026 11:51
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 dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.lock and workspace/Cargo.toml change 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, from cargo metadata or the Cargo.lock entries reachable from trusted-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)

Comment thread docs/guide/configuration.md Outdated
Comment thread crates/trusted-server-core/build.rs Outdated
prk-Jr added 2 commits October 1, 2026 13:02
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 ChristianPavilonis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved pending resolution of other reviewer comments.

@prk-Jr
prk-Jr requested a review from dhruv8sh October 1, 2026 13:23
@aram356 aram356 modified the milestones: 202609, 202610 Oct 1, 2026

@aram356 aram356 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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's edgezero.toml diagnostic: see inline at crates/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)

Comment thread crates/trusted-server-core/build.rs Outdated
Comment thread crates/trusted-server-core/src/platform/template_cache.rs

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 main and added its own gate 8. Markdown format outside docs/ …, and this PR also adds a gate 8. (native core build-digest), so AGENTS.md conflicts 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.rs auto-merges cleanly with #1180's all_module_ids change; AGENTS.md is 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

Comment thread crates/trusted-server-core/src/platform/template_cache.rs
Comment thread crates/trusted-server-core/build.rs
Comment thread crates/trusted-server-core/build.rs Outdated
Comment thread crates/trusted-server-core/build.rs
prk-Jr added 2 commits October 5, 2026 17:36
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.
@prk-Jr
prk-Jr requested a review from aram356 October 5, 2026 12:17
Comment thread docs/guide/configuration.md Outdated
@aram356
aram356 merged commit da31a21 into main Oct 8, 2026
22 checks passed
@aram356
aram356 deleted the fix/template-build-fingerprint branch October 8, 2026 16:17
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.

Template cache key ignores gpt_bootstrap.js and other Rust-inlined head scripts

4 participants