Skip to content

Migrate Mocktioneer to EdgeZero request and outbound lifecycles - #131

Draft
aram356 wants to merge 16 commits into
mainfrom
feat/edgezero-pr275-migration
Draft

aram356 wants to merge 16 commits into
mainfrom
feat/edgezero-pr275-migration

Conversation

@aram356

@aram356 aram356 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Migrate all four Mocktioneer adapters to the portable outbound HTTP and request lifecycle APIs in EdgeZero #275. All six dependencies and eight lockfile sources pin d47c8026a941a2361182c9e2042bebdcb8be4d04, the latest reviewed PR head observed on 2026-10-23. This explicitly requested update supersedes the original f6c708cc freeze.

JWKS fetching is bounded to 5 seconds and 64 KiB, with a portable 32-entry/2 MiB/10-minute cache and immutable shared hits. Bid routes retain 10-second reads, the default remains 30 seconds, and config extraction retains its 2-second observed budget. Auction/APS bodies remain capped at 1 MiB and mediation at 8 MiB. Oversized bodies now return 413 payload_too_large, with request body too large, CORS and no Retry-After; malformed JSON remains 400, validation 422 and body expiry 408.

Required test helpers now select explicit platform framing modes and pass actual response status/decoding policy. The new upstream synthesized-header policy stays unconfigured, preserving existing CORS scope. Adapters remain thin, prices/creatives/cookies stay deterministic, and approved timeout/cache policies are unchanged. Documentation, the R10 spec/plan and the narrowly scoped F14 comparator contract cover the adopted behavior.

Closes #130

Validation

  • Native workspace: 202 tests; rustfmt; strict all-feature Clippy; locked fetch; fastly cloudflare spin feature compilation.
  • Actual WASM target contracts: Fastly 5, Cloudflare 6, Spin 4, including signed JWKS fetch then cache hit.
  • Wire comparator: 61 offline Node tests; all 87 cases against both the original e6c2982 and preceding 04c3635 implementations; independent baseline/candidate restarts and repeats. Historical captures remain immutable.
  • 41 Playwright tests; strict typed-config validation; isolated CLI push and HTTP roundtrip at CPM 0.35.
  • Docs ESLint, Prettier and VitePress build.
  • Real local Docker linux/amd64, Fastly production main, Cloudflare/workerd and Spin 4.1 delivery checks; Spin CLI drift rejection and recovery.
  • Independent spec-compliance and quality reviews.
  • GitHub checks for this latest update. All 13 checks passed for preceding head e119453; that is historical evidence.

The checked-in implementation plan records commands, counts and local evidence indexes. Browser WASM tests use a test-only stream shim; the separate real workerd smoke uses the actual stream implementation. Direct origin delivery checks root bytes/length before Wrangler HTML rewriting. Local tests do not qualify hosted networking or provider cancellation guarantees.

Remaining gates and operating prerequisites

Keep this PR draft. JWKS hostname syntax validation does not authorize the resolved destination: the existing choice between operator-controlled exact hostname admission (recommended default-empty) and arbitrary publisher hosts with deployment DNS/IP egress controls remains open. Implement/test the selected boundary before completing that review or merging.

This remains stacked on still-open #118, with base worktree-deps-rust-1.98-align-ez366. Preserve the stack, target main after #118 lands and rerun integration checks. EdgeZero #275 remains draft/open/unmerged; review its shipping delta, repin consistently and rerun the release matrix before merge/release.

Cloudflare requires a real KV binding, config push and all three retained compatibility flags. Fastly signed verification requires dynamic backends; Axum/Docker require restart after config push; Spin requires 4.1+. Config envelope/rollback compatibility is unchanged. Hosted JWKS networking remains unverified. Outbound batch fan-out and cross-project dependency coordination remain out of scope.

Node tooling follow-up (2026-10-25)

Replaced both PR-added Python files with Node built-in scripts/tests, retaining curl and the capture/archive format. CI uses its existing pinned Node setup, and CLAUDE.md records the shell/Node preference. No npm package, Rust, Cargo, EdgeZero pin or policy change is included.

All 49 original regressions and seven new port/CLI guards pass (56 tests). Final qualification passed 52 archived comparisons / 2,262 case checks and 435 fresh checks against both baselines, archived d47, self and independent restart repeat. Raw request bytes remain exact. Required 201 native tests, fmt, Clippy, features and docs checks passed. Prior provider/browser runtime qualification remains historical evidence.

The first fresh repeat correctly failed a curl 55 reset during a 9 MiB upload. Its bytes match the archive and the unchanged server logged 413. Failed evidence is preserved; 16 identical direct Node/archive requests, the full rerun and final run passed without changing requests, curl flags, retries or comparison rules. The precise transport mechanism remains unproven. Fresh CI for this tooling commit is required; all 13 checks passed for prior head 91ffbd3.

Third-review fixes (R12)

Candidate wire comparisons now require 413 for all three F14 cap cases; historical self/repeat checks explicitly select --baseline-repeat. Both baselines and every saved-corpus byte remain supported. A real signed auction now traverses admission and router dispatch with seeded config and an injected client, asserting Ed25519 verification metadata and the exact outbound request. Its uncached no-client negative retains a successful bid with failed verification metadata.

Fetch misses share one immutable Arc with the cache and later hits, with pointer identity, one-send and actual-capacity accounting regressions. Fetch accepts a private canonical syntax-validated hostname. The oversized cache test now accurately exercises defensive insertion rejection. Provider suites separate synthetic fixtures from real 400/302/OPTIONS 204 handlers; a raw-constructor assertion catches the pre-egress 204 length guard. Axum docs, miss cleanup and redundant Spin cfg are corrected.

Fresh required verification: 202 workspace tests, strict native workspace Clippy/fmt/features/build, 61 Node tests, actual provider suites 5/6/4, docs lint/format/build, 52 archived comparisons / 2,262 checks and 435 fresh checks across all 87 cases with both baselines, archived d47, self and independent restart repeat. Candidate mode rejects all six real original/preceding over-cap cases. Independent spec and quality reviews approved. Prior Playwright/live Docker/workerd/Fastly/Spin qualification remains historical. Extra optional WASM-target Clippy probes reported lint diagnostics; these and their limited baseline attribution are recorded in the plan.

The destination policy remains unresolved. The new hostname type guarantees syntax only and does not prevent private DNS resolution. Keep the merge gate pending the user choice and selected boundary. Approved timeout/cache policies, CORS renderer trade-off, Proxy wire string, bounded-store fixtures and the d47 source pin remain unchanged. The private upstream admission defaults have no public delegation API; a source comment and shipping-repin checklist require auditing grant/completion drift. Comparator CI was already separated from Rust lint in e119453. All 13 checks passed for that preceding head; this update requires new CI.

Moves the pinned toolchain to Rust 1.98.1 / Node 24.20.0 and takes the
dependency majors edgezero PR #366 coordinates, so the two workspaces
resolve the same versions of the crates they share.

Toolchain (`.tool-versions`, the single source CI reads):

| Tool     | Bump             | Verification                          |
| -------- | ---------------- | ------------------------------------- |
| Rust     | 1.95.0 → 1.98.1  | Full gate suite; all 3 wasm targets   |
| Node.js  | 24.12.0 → 24.20.0| Docs lint/format/build; 41 e2e tests  |
| Fastly   | 13.0.0 → 16.0.0  | Matches edgezero's pin                |
| Viceroy  | 0.17.0 → 0.21.0  | 3 Fastly contract tests on wasip1     |
| wasmtime | 45.0.0 → 48.0.1  | 2 Spin contract tests on wasip2       |

Dependency majors, matching #366 where mocktioneer shares the crate:
`validator` 0.20→0.21, `fastly`/`log-fastly` 0.12→0.13, `sha2` 0.10→0.11,
`spin-sdk` ~6.0→~7.0, plus a full `cargo update` (162 packages). This also
drops `proc-macro-error2`, clearing the future-incompat warning that
printed on every build.

`sha2` 0.11 needed no source change here. It broke edgezero's two
`format!("{:x}", ..)` sites because 0.11 returns `hybrid_array::Array`,
which lacks `LowerHex`; mocktioneer's `hex_encode` already takes `&[u8]`,
so the digest call sites are unaffected and output is unchanged.

`inline_modules` is allowed at the workspace level. The new lint fires on
all 9 colocated `#[cfg(test)] mod tests` blocks, and complying would mean
splitting each into a sibling file, contradicting CLAUDE.md's "colocate
tests with implementation modules". edgezero carries the same allow for
the same reason.

edgezero is pinned to #366's head commit rather than a tag, since the PR
is not yet merged or released. A rev pin keeps the build reproducible; it
becomes a one-line swap to the tag once #366 ships.

Docker needed a fix beyond a version bump. The official `rust` image
publishes no `1.98.1-slim-bookworm` tag (only `1.98.0` and the `1.98`
alias), and docker.yml feeds `.tool-versions` straight into the `FROM`
line, so a naive bump would have failed the image build on a tag that was
never pushed. The version step now falls back to the minor alias when the
exact patch tag is absent, keeping `.tool-versions` authoritative.

Node dependency ranges move to current within their majors. `@types/node`
deliberately stays on 24.x to track the pinned Node 24 runtime rather than
typing against a release we do not run, matching edgezero. vitepress 1.x
is still the current major.

Verified:
- `cargo test --workspace --all-targets` — 173 passed, 0 failed
- `cargo fmt --all -- --check`, `cargo clippy ... -D warnings` — clean
- `cargo check --workspace --all-targets --features "fastly cloudflare"`
- wasm builds + contract tests: Fastly 3/3 (Viceroy 0.21.0), Cloudflare
  3/3 (headless Chrome), Spin 2/2 (wasmtime 48.0.1)
- `config validate --strict` — OK
- Playwright — 41 passed against a live Axum server
- Docs — lint, format and build clean on Node 24.20.0
- Docker image builds and serves: `/` returns 200 and an OpenRTB auction
  returns price 0.2 at 300x250 from the seeded config blob
…Mermaid

The spin-sdk 6 -> 7 bump resolved a blocker the docs still describe as open.
`docs/guide/configuration.md` warned that `spin up` fails to link because
spin-sdk 6 imports `wasi:http@0.3.0-rc`, which no released Spin provided,
and called it an upstream issue to be fixed in EdgeZero's pin. spin-sdk 7
imports `wasi:http@0.3.0` and Spin 4.1.0 ships that interface.

Verified rather than taken from the upstream PR: built the wasip2 release
component and ran a real `spin up` on Spin 4.1.0. It links and serves --
`/` returns 200. The auction returns a 503 `config_out_of_date`, which is
the correct fail-loud AppConfig path for a deploy with no pushed blob, not
a link failure. The warning is now a tip naming the 4.1 floor, and it keeps
the point that `cargo build` and the wasmtime contract tests both pass on a
component that cannot boot, so only a real `spin up` catches runtime skew.

CLAUDE.md carried the same stale claim and is corrected the same way.

The adapters overview omitted Spin entirely. That was defensible while the
adapter was documented as blocked; with it working, a reader landing on the
overview saw three adapters and no `--adapter spin`, contradicting both the
configuration page and CLAUDE.md's own compilation-targets table. Spin now
appears in the table, the production list, and the serve examples, linking
to the configuration section rather than inventing a new adapter page.

The ASCII architecture diagram becomes Mermaid, which is what motivated
adding `vitepress-plugin-mermaid` and `mermaid` to the docs devDependencies
and wrapping the VitePress config in `withMermaid`. The redrawn diagram
carries each adapter's compile target, which the ASCII version did not.

Verified in a browser at both themes: the diagram renders with all four
adapters, no clipped labels, no console errors, and the node fills hold
contrast in dark mode. Docs lint, format and build all pass.
edgezero #366 has merged and shipped in v0.0.10, which carries the
same Rust 1.98.1 toolchain and dependency majors this branch aligns
with. The six `edgezero-*` entries move from #366's pre-merge head
commit (`rev = "9ba4eae7"`) to `tag = "v0.0.10"`.

The lockfile change is limited to the eight edgezero packages; no
third-party crate moves. v0.0.10 also includes #373, #375, #379 and
#381 on top of #366, none of which required a source change here.

Verified on rustc 1.98.1:
- `cargo test --workspace --all-targets` — 173 passed, 0 failed
- `cargo fmt --all -- --check`, `cargo clippy ... -D warnings` — clean
- `cargo check --workspace --all-targets --features "fastly cloudflare"`
- `config validate --strict` — OK
- wasm release builds: wasip1, wasm32-unknown-unknown, wasip2
- contract tests: Fastly 3/3 (Viceroy 0.21.0), Cloudflare 3/3
  (headless Firefox), Spin 2/2 (wasmtime 48.0.1)
Brings in #120, which moves the edgezero git dependencies from
stackpop/edgezero to IABTechLab/edgezero.

Conflicts in Cargo.toml and Cargo.lock: kept this branch's
`tag = "v0.0.10"` and `fastly = "0.13"`, and took main's IABTechLab
URL. The lockfile was re-resolved by cargo from this branch's lock; the
only change is the eight edgezero `source` lines, still at 85d933b8.
Brings in #129, Dependabot's typescript-eslint 8.62.1 -> 8.71.2 bump in
docs/.

Conflicts in docs/package.json and docs/package-lock.json: kept this
branch's devDependencies (including mermaid and vitepress-plugin-mermaid)
and took main's higher `typescript-eslint` range, ^8.71.2. The lockfile
was regenerated by npm from this branch's lock; only the typescript-eslint
packages (8.70.0 -> 8.71.2) and their transitive `ignore` moved.
Design for moving mocktioneer onto edgezero PR #275 (portable outbound
HTTP and request lifecycle contracts) with a hard cutoff on the edgezero
API, adopting the new APIs where they do real work.

The spec covers the forced migration (repin, App::build, Fastly and Spin
entrypoints, wrangler flags, the JWKS fetch moving off the removed proxy
API, test doubles and contract harnesses), the adopted APIs (outbound
client policy, portable clock with a bounded JWKS cache, a configure hook
with bid-route admission, size-capped JSON extractors), the complete list
of accepted wire changes, and the verification plan.

Claims were checked against edgezero f6c708cc and by a throwaway compile
probe of every target. Two open questions in section 0 block approval.
@aram356
aram356 added this pull request to stack #134 October 21, 2026 17:29
Adopt the audited EdgeZero APIs across all four adapters, bound JWKS fetching and cache retention, and configure bid ingress and extraction limits. Add provider and wire-contract regressions, operational docs, and PR documentation gates.

Refs #130
@aram356 aram356 self-assigned this Oct 22, 2026
@aram356 aram356 changed the title Migrate Mocktioneer to edgezero #275 (outbound HTTP and request lifecycle) Migrate Mocktioneer to EdgeZero request and outbound lifecycles Oct 22, 2026
Base automatically changed from worktree-deps-rust-1.98-align-ez366 to main November 8, 2026 21:38

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.

Migrate Mocktioneer to EdgeZero request and outbound lifecycles

1 participant