feat(serve): add serve-metadata headers; harden CI against flaky tests#31
Merged
Conversation
Every /s/ content-serve response (GET and HEAD) now carries, alongside the existing X-Dig-Verified/-Root/-Source provenance set: X-Dig-Store-Id, X-Dig-Owner-Puzzle-Hash (the on-chain store owner - the tip gate, #486 Part A), X-Dig-Generation, X-Dig-Capsule, and X-Dig-Resource-Key. Owner puzzle hash rides the SAME chain-anchored-root read as the existing pin (no extra coinset call, via a new AnchoredRootResolver::anchored_state default method); generation is a local-only PublicManifest lookup. Unknowable values are omitted, never a placeholder, and none of the five appear on a 404/error response. HEAD support needs no new code path: axum dispatches HEAD to the registered GET handler and strips the body. Also folds in #489 (triggered by the #488 flaky-test release block): - ci.yml now runs the workspace suite via cargo-nextest (--retries 2) driven through cargo-llvm-cov so a flaky test gets one retry before failing the job, without losing coverage measurement. - release.yml's tag/main-push gate drops its redundant `cargo test` re-run (fmt+clippy stay - deterministic, cheap fail-fast); the PR's own CI already tested this exact merged tree before merge. Part B (the dig-chrome-extension toolbar Tip button gated on X-Dig-Owner-Puzzle-Hash) is a release-first follow-up once this ships. Bump: feat -> minor (0.25.0 -> 0.26.0 workspace release version; dig-node-core 0.6.0 -> 0.7.0). Co-Authored-By: Claude <noreply@anthropic.com>
5db7e6d to
4b6ca71
Compare
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.
Summary
Part A of #486 only (Part B — the extension's toolbar Tip button — is a release-first follow-up once this ships). Also folds in #489 (CI flaky-test hardening), triggered by the #488 flaky-test release block.
Every dig-node
/s/<storeId>[:<root>]/<path>content-serve response (GET and HEAD) now carries, alongside the existingX-Dig-Verified/X-Dig-Root/X-Dig-Sourceprovenance set (#292):X-Dig-Store-Id: <64-hex>StorePath.store_idX-Dig-Owner-Puzzle-Hash: <64-hex>DIG_NODE_PIN=off) or the resolver can't supply itX-Dig-Generation: <n>PublicManifest— local-only, no chain callX-Dig-Capsule: <storeId:root>Servedoutcome, which always has a concrete root)X-Dig-Resource-Key: <key>index.html, never a blank header)All five are attached only via
served_response(i.e. only on a genuine served resource) — a404/502/400never carries any of them, no empty placeholder ever emitted.Owner puzzle hash plumbing.
AnchoredRootResolvergains a newanchored_state()method (default impl wrapsanchored_root()withowner_puzzle_hash: None, so it is backward compatible for any resolver that doesn't override it).CoinsetResolveroverrides it to capture both the root and the owner puzzle hash from the singlesync_datastorewalk it already performs — the same field (store.info.owner_puzzle_hash)dig-wallet::sage::tipping::ChainOwnerResolveralready reads elsewhere in this repo, so this is not a new chain-read pattern.HEAD support needs no new route/handler. axum 0.7's
MethodRouterdispatches aHEADrequest to the registeredGEThandler and strips the response body, preserving headers — verified with a new integration test (head_request_returns_the_same_serve_metadata_headers_with_no_body).CI hardening (#489)
ci.yml: the workspace test job now runs via cargo-nextest (--retries 2) driven throughcargo llvm-cov nextest(one combined invocation — nextest and llvm-cov as separate steps collects no coverage at all). Coverage stays measure-only for now (not newly gated) — see "Coverage gate" below for why.release.yml: the tag/main-pushcheckgate no longer re-runscargo test(that redundant re-run of an already-green PR tree is exactly what blocked the #488 v1.96.0 release on a flaky test).fmt+clippystay — deterministic, never flaky, cheap fail-fast before 4 platforms' worth of build minutes.Coverage gate — why not
--fail-under-lines 80yetI measured real coverage before deciding: a scoped
cargo llvm-cov nextest -p dig-node-servicerun shows several CLI/service-shell files (cli.rs,main.rs,meta.rs,pair.rs,pairing.rs,service.rs,win_service.rs) at or near 0% — matching the pre-existing "measure-only... floor tracked separately" comment already inci.ymlbefore this PR. A full-workspace run to get the exact aggregate number hitENOSPCon the shared build disk (freed by deleting my own scratch target dir, not touching anyone else's). Given the demonstrated gap is pre-existing and unrelated to this change, flipping the hard gate on in this PR would very likely turn CI red for reasons this PR didn't cause. I kept coverage measure-only (now on the nextest-combined runner) and left the "one-line addition" comment in place — raising the workspace floor to ≥80% is a separate, larger tracked effort, not bundled into this PR's scope.Tests
crates/dig-node-service/tests/content_serve.rs: extended the GET/index.html test with all 5 header assertions (present+correct) + owner omitted (pin off); extended the JS-asset and SPA-fallback tests to assertX-Dig-Resource-Keyreports the actual resource served; extended the 404 test to assert none of the 5 headers appear; addedhead_request_returns_the_same_serve_metadata_headers_with_no_body(HEAD → same headers, empty body).crates/dig-node-core/src/lib.rs: fixed a pre-existing test whosePlaintextOutcome::Served { .. }match didn't destructure the 2 new fields (would not have compiled) and added assertions for both; addedserve_content_plaintext_reports_the_resolver_owner_puzzle_hash_when_pin_enforced(owner present + correct when the resolver supplies it),serve_content_plaintext_omits_owner_puzzle_hash_when_pin_is_off(never guessed), andserve_content_plaintext_omits_generation_when_manifest_absent.cargo test -p dig-node-core -p dig-node-service(95+45+8+5 passed, 0 failed) andcargo check --workspace --all-targets --locked(dig-node-core, dig-node-service, dig-wallet, dig-runtime all clean).cargo fmt --checkandcargo clippy --all-targets -- -D warningsclean on the touched crates.Blast radius (gitnexus)
served_response(server.rs):impact→ 2 direct callers (serve_resource,serve_miss), both updated; risk LOW.AnchoredRootResolvertrait:impactflags HIGH (26 symbols / 2 processes reach it — chain-watch, gap-fill, subscriptions all consumeanchored_root). The actual change is a single additive, default-provided trait method (anchored_state) — no existing method signature/semantics changed. Verified empirically: full workspace compile + full test suite green (including dig-wallet/dig-runtime, which depend on this trait but don't override the new method).detect_changes(scope: all): 46 touched symbols acrosscontent_serve.rs/lib.rs/server.rs/the test file — mostly line-shift noise from inserting 3 new tests ahead of existing ones (e.g.spawn_authed_remote,test_node_with_resolverreported "touched" only because their line numbers moved, not their bodies).SYSTEM.md draft (for the orchestrator to commit to the superproject)
One paragraph to append after the existing
/s/provenance-headers sentence (superprojectSYSTEM.md, the dig-node "Exposes" bullet, ~line 102):Version bump
feat:→ minor: root workspace0.25.0→0.26.0(the releaseddig-nodebinary version);dig-node-core0.6.0→0.7.0(its own independently-versioned library), matching this repo's convention of bumping both together on a feature commit.Also touched
SPEC.md§4.6 "Provenance headers" — documented the 5 new headers, the omission rules, and the HEAD-needs-no-new-code-path note, in the same unit of work.Co-Authored-By: Claude noreply@anthropic.com