release: wire prod Turnstile sitekey + wrangler.jsonc comment audit (post-#115 follow-up)#116
Merged
Merged
Conversation
Adds the real production Turnstile sitekey to the top-level `vars` block in wrangler.jsonc. Without it, the homepage form reads an empty TURNSTILE_SITEKEY meta tag at request time and disables itself with a "Live scoring is available on staging only" message: the exact UX production showed immediately after PR #115 deployed live scoring. The sitekey is public-by-design (Turnstile embeds it in HTML for client-side widget rendering; anyone viewing page source sees it). The matching TURNSTILE_SECRET was set on the production Worker via `wrangler secret put TURNSTILE_SECRET` separately and is not committed. Comment cleanup: drops the stale "deferred until production promotion" framing on both the top-level and env.staging `vars` blocks, and adds an explicit note about `vars` REPLACE-not-merge inheritance semantics so a future contributor who adds a top-level var knows env.staging will not pick it up automatically. No env.staging change to the actual sitekey value: env.staging.vars already explicitly defined the Cloudflare always-pass test sitekey (1x...AA), which still wins via REPLACE semantics.
…nale Audit of wrangler.jsonc against the WHY-only / no-temporal / no-task-flow / no-local-doc-ref / no-instructional policy. Trimmed eight comment blocks; net 65 lines removed from wrangler.jsonc and 41 lines of consolidated rationale added to RELEASES-RATIONALE.md. Moves to RELEASES-RATIONALE.md (new "Wrangler env inheritance traps" section): - Which keys inherit from top-level (routes, triggers, vars) and which do not (containers, durable_objects, migrations, ratelimits, r2_buckets, kv_namespaces, analytics_engine_datasets). - REPLACE-not-merge semantics on `vars`, and the future-additions mirroring requirement. - The 2026-04-30 routing-drift incident as the historical context for the explicit `routes: []` override. - Container app naming quirk (no automatic env-suffix). Trims in wrangler.jsonc (each block now WHY-only with a pointer): - Dropped the `dotfiles config/shell/telemetry.sh` reference on `send_metrics` (personal-repo local-doc ref). - Dropped "first-ever" temporal on the live-scoring binding block. - Dropped the duplicated promotion runbook on both prod and staging `containers[0]` blocks (lives in RELEASES.md § Sandbox image releases); kept the account-id-committed-deliberately WHY inline. - Dropped `docs/plans/` references on SCORE_LIMITER_IP and SCORE_KV. - Dropped the kill-switch flip command on SCORE_KV (lives in RELEASES.md § Cost guardrails). - Replaced the routes-override block's temporal + local-doc + instructional content with a pointer to RATIONALE. - Trimmed the staging triggers prophylactic to a pointer. No behavior change. All gates pass: 737 tests, lint clean, wrangler dry-runs on both envs clean (TURNSTILE_SITEKEY values unchanged).
Merged
3 tasks
brettdavies
added a commit
that referenced
this pull request
May 25, 2026
…udit from release #116 (#117) ## Summary Back-port of PR #116 (which shipped to production via main) onto dev so the next release branch carries the production Turnstile wiring and the consolidated `wrangler.jsonc` comment hygiene by default, rather than re-introducing the fail-closed gap or the duplicated runbook prose. Two commits cherry-picked from the original `release/2026-05-25-prod-turnstile-wiring` branch (deleted on PR #116 merge), preserving the same diff that already shipped to production: - **`feat(worker)` c08a0fa, mirror prod TURNSTILE_SITEKEY wiring from release #116.** Enables the top-level `vars` block in `wrangler.jsonc` and populates `TURNSTILE_SITEKEY` with the production `sitekey` from 1Password (`agentnative-site Cloudflare Turnstile / prod.site_key`). The matching `TURNSTILE_SECRET` lives in CF-encrypted wrangler secrets, not committed. env.staging.vars is unchanged: it carries Cloudflare's always-pass test `sitekey` (`1x...AA`), which under wrangler `vars` REPLACE semantics correctly isolates staging from the new top-level value. Without this back-port, the next release branch snapshot of dev would re-introduce the empty `TURNSTILE_SITEKEY` and re-create the fail-closed gap on production. - **`docs(wrangler)` bac003d, trim comments per `/code-comments` policy + stash rationale.** Eight comment blocks audited against the WHY-only / no-temporal / no-task-flow / no-local-doc-ref / no-instructional policy. Net 65 lines removed from `wrangler.jsonc`, 41 lines added to `RELEASES-RATIONALE.md` under a new `## Wrangler env inheritance traps` section that consolidates which keys inherit from top-level (`routes`, `triggers`, `vars`), which do not, the REPLACE-not-merge semantics on `vars`, and the 2026-04-30 routing-drift incident as historical context. Each trimmed comment in `wrangler.jsonc` keeps the WHY that's unique to inline context and points at the consolidated rationale for the rest. ## Changelog ### Added - Mirror the production `TURNSTILE_SITEKEY` wiring from release #116 onto dev so the next release-branch snapshot carries it. No behavior change on dev (env.staging keeps the test `sitekey` for CLI verification flows under `vars` REPLACE semantics). ### Changed - Consolidate Wrangler env-inheritance rationale (`routes` / `triggers` / `vars` inheritance semantics, the 2026-04-30 routing-drift incident, container app naming quirk) into `RELEASES-RATIONALE.md` § Wrangler env inheritance traps. `wrangler.jsonc` comments now point at the consolidated rationale. ### Documentation - Trim eight `wrangler.jsonc` comment blocks per the `/code-comments` policy: drop temporal phrasing (`first-ever`, `since 2026-04-30`, etc.), drop `docs/plans/` and personal-repo references, drop instructional voice (`Flip via:`, `Deploy with:`, `Removing this line will reintroduce the bug`), drop runbook content that duplicates `RELEASES.md` § Sandbox image releases. ## Type of Change - [x] `feat`: New feature (non-breaking change which adds functionality) The `feat` headlines because the next release-branch cut now ships the working homepage form on production by default. Documentation cleanup rides along. ## Related Issues/Stories - Story: Back-port of PR #116 onto dev to prevent the next release-branch snapshot from re-introducing the empty-`sitekey` fail-closed state on production. PR #116 already shipped to anc.dev via squash-merge to main; this PR aligns dev with main on the relevant files. - Issue: n/a - Architecture: n/a - Related PRs: #116 (the production release this back-ports), #115 (the live-scoring v3 launch that ran behind the deliberate fail-closed gate), #114 (sandbox image bump to anc 0.4.0). ## Testing - [x] Unit tests added/updated - [x] All tests passing **Test Summary:** - `bun test`: 737 pass / 0 fail across 28 files. - `bun x wrangler deploy --dry-run`: clean. Lists `env.TURNSTILE_SITEKEY ("ff0x4AAAAAADQFMBoVm56-OPuQ")` (the real production `sitekey`). - `bun x wrangler deploy --dry-run --env staging`: clean. Lists `env.TURNSTILE_SITEKEY ("1x00000000000000000000AA")` (Cloudflare's always-pass test `sitekey`, unchanged). Confirms env.staging.vars REPLACE semantics correctly isolates staging from the new top-level value. - Pre-push gate: pass (lint, build, test, both wrangler dry-runs, pack-README, banned-fonts, prose-check). **Post-merge verification plan** (after the staging deploy on this PR's merge): - The staging Worker on `agentnative-site-staging.<subdomain>.workers.dev` continues to render its homepage form via the test `sitekey`; nothing on staging changes because env.staging.vars REPLACE wins. - The next release-branch cut from this dev tip carries `TURNSTILE_SITEKEY: ff0x...` in `wrangler.jsonc` top-level by default. No further hot-fix needed to keep the production form enabled across future cuts. ## Files Modified **Modified:** - `wrangler.jsonc`: enabled the top-level `vars` block with the production `sitekey`; trimmed eight comment blocks per `/code-comments` policy. Net 65 lines removed. - `RELEASES-RATIONALE.md`: new `## Wrangler env inheritance traps` section consolidates inheritance semantics, override patterns, and the historical context that the config-file comments previously held inline. **Created:** - None. **Renamed:** - None. **Deleted:** - None.
3 tasks
brettdavies
added a commit
that referenced
this pull request
May 25, 2026
…Turnstile 400020) (#118) ## Summary Fast follow to PR #116. The production `TURNSTILE_SITEKEY` value pinned in `wrangler.jsonc` was `ff0x4AAAAAADQFMBoVm56-OPuQ` (26 chars), which the Cloudflare Turnstile widget rejects with error 400020 (Invalid `sitekey`) on every request. Cloudflare API confirmed the dashboard's actual `sitekey` for this account is `0x4AAAAAADQFMBoVm56-OPuQ` (24 chars, starting with `0x` per Turnstile's `sitekey` convention). The 1Password item `agentnative-site Cloudflare Turnstile / prod.site_key` had a stray `ff` prefix from a paste error when the credential was first saved; PR #116 dutifully read that wrong value into `wrangler.jsonc`. The 1Password field has been corrected at source and this PR ships the corrected pin to production. User-visible state after PR #116 deployed: - Homepage form was enabled (no longer in the fail-closed "Live scoring is available on staging only" state). - Turnstile widget tried to challenge `https://challenges.cloudflare.com/...<key-in-path>...` with the pinned `ff0x4...` value, got HTTP 400 back, console showed Turnstile error 400020. - Browser console additionally showed "Call to execute() on a widget that is already executing" because the client retries the challenge on its own (separate client-side bug; will be filed as its own PR). - No `/api/score` POST ever reached the Worker because the widget never produced a token; no rate-limit or kill-switch impact; no telemetry events written. env.staging is unchanged: it carries Cloudflare's always-pass test `sitekey` (`1x00000000000000000000AA`), independent of the 1Password value. ## Changelog ### Fixed - Correct the production `TURNSTILE_SITEKEY` value in `wrangler.jsonc` from `ff0x4AAAAAADQFMBoVm56-OPuQ` (paste-error value carried into PR #116 from a stale 1Password entry) to `0x4AAAAAADQFMBoVm56-OPuQ` (the actual dashboard `sitekey` for this account). Cloudflare Turnstile error 400020 on the anc.dev homepage form clears with this deploy. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: PR #116 enabled the homepage form on production after fail-closed verification, but the pinned `TURNSTILE_SITEKEY` value had a stray `ff` prefix from a 1Password paste error. This corrects the value at source (1Password) and ships the corrected pin. - Issue: n/a - Architecture: n/a - Related PRs: #116 (the enable-the-form release whose 1Password value was wrong), #115 (the live-scoring v3 launch this restores to working order). ## Testing - [x] Unit tests added/updated - [x] All tests passing **Test Summary:** - `bun test`: 737 pass / 0 fail across 28 files. - `bun x wrangler deploy --dry-run`: clean. Lists `env.TURNSTILE_SITEKEY ("0x4AAAAAADQFMBoVm56-OPuQ")` (the corrected production `sitekey`). - `bun x wrangler deploy --dry-run --env staging`: clean. Lists `env.TURNSTILE_SITEKEY ("1x00000000000000000000AA")` (Cloudflare's always-pass test `sitekey`, unchanged). - Pre-push gate: pass (lint, build, test, both wrangler dry-runs, pack-README, banned-fonts, prose-check). - Cloudflare API: `GET /accounts/<id>/challenges/widgets` failed with auth-scope error on the existing `CF_API_TOKEN`, so the dashboard `sitekey` was retrieved manually and re-staged into 1Password via the no-echo `stage_secret.sh` pipeline. 1Password's `prod.site_key` field is now 24 chars matching the dashboard value. **Post-merge verification plan** (after the production deploy on this PR's merge): - View source on anc.dev and confirm the meta tag `turnstile-sitekey` carries `content="0x4AAAAAADQFMBoVm56-OPuQ"` (with `0x4` prefix, no `ff`). - Open anc.dev in a browser. Submit a real input (e.g., `ripgrep`). Confirm the Turnstile challenge succeeds (invisible-mode, no widget popup), POST to `/api/score` returns a scorecard, browser redirects to `/live-score/<binary>` with the inline scorecard. - Confirm browser console no longer shows Turnstile error 400020. - Separately track: the "Call to execute() on a widget that is already executing" warning is a client-side bug in `src/client/live-score.ts:acquireTurnstileToken` (always-render + always-execute pattern, needs reset()-before-execute) and the `static.cloudflareinsights.com/beacon.min.js` CSP violation is the CF Web Analytics auto-injected beacon hitting a CSP that doesn't list `static.cloudflareinsights.com`. Both are out of scope here. ## Files Modified **Modified:** - `wrangler.jsonc`: top-level `vars.TURNSTILE_SITEKEY` changed from `ff0x4AAAAAADQFMBoVm56-OPuQ` to `0x4AAAAAADQFMBoVm56-OPuQ` (drop stray `ff` prefix). **Created:** - None. **Renamed:** - None. **Deleted:** - None.
3 tasks
brettdavies
added a commit
that referenced
this pull request
May 25, 2026
…119) ## Summary `acquireTurnstileToken` called `api.render()` on every acquire, so the second form submit produced "Call to execute() on a widget that is already executing" in the console plus Turnstile error 400020 from `challenges.cloudflare.com`. Render exactly once per page session, then `reset()` + `execute()` on the existing widget id for retries. Surfaced after #118 corrected the production `sitekey` and the form started producing real challenges. ## Changelog ### Fixed - `/api/score` form on anc.dev succeeds on retry submits. Pre-fix, only the first submit per page could produce a Turnstile token; subsequent submits silently failed with Turnstile error 400020. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: Surfaced during browser-side QA after PR #118 corrected the production `TURNSTILE_SITEKEY`. - Issue: n/a - Architecture: n/a - Related PRs: #118, #116, #115. ## Testing - [x] Unit tests added/updated - [x] All tests passing **Test Summary:** - `bun test`: 737 pass / 0 fail. No client-side unit test added: no DOM harness in Bun test today; regression test pinned to follow-up `feat(test-infra)` PR (plan in flight). - Manual: on staging after merge, submit twice in the same page session; both should round-trip with zero Turnstile console warnings. ## Files Modified **Modified:** - `src/client/live-score.ts`: render Turnstile once; reset+execute the existing widget id on subsequent acquires. Module-scope `turnstileWidget` + `pendingTurnstile` slot with a `settleTurnstile` helper rotating the resolver per acquire. **Created:** - None. **Renamed:** - None. **Deleted:** - None.
Merged
3 tasks
brettdavies
added a commit
that referenced
this pull request
May 25, 2026
…ide widget teardown (#120) ## Summary Three fixes that surfaced sequentially while validating PR #119's reset+execute fix on staging. Validated end-to-end at staging Worker version `c6ab5306-b238-4e07-b41b-472858261c15`. **Commit 1 (`3ff7b7a`), drop invalid `size: 'invisible'` + add `execution: 'execute'`.** `acquireTurnstileToken` passed `size: 'invisible'` to `api.render()`. Per CF docs, `size` accepts `compact | flexible | normal` only; `invisible` throws `Uncaught TurnstileError` and puts the widget in a stuck "executing" state that masks the #119 reset+execute fix. Invisible behavior is `sitekey`-mode (set in CF dashboard), not a render-time argument. Drop the invalid value; the off-screen container CSS keeps the widget visually hidden. Add `execution: 'execute'` so the challenge defers to our explicit `api.execute()` instead of starting on render. **Commit 2 (`1ff0b01`), allow Lato in CSP + tear down widget on `pagehide`.** Even with the `sitekey` configured as `Invisible` mode, Turnstile's bootstrap injects `<link rel=stylesheet href="https://fonts.googleapis.com/css?family=Lato...">` into the host document (defensive UI prep). Our CSP blocks it. Allowlist `https://fonts.googleapis.com` on `style-src` and `https://fonts.gstatic.com` on `font-src` in both `CSP_HTML` (`src/worker/headers.ts`) and `LIVE_SCORE_CSP` (`src/worker/score/summary-render.ts`). Separately, on `pagehide`, call `api.remove(widgetId)` and clear module-scope state so a `bfcache` restore can't re-bootstrap a half-dead widget and re-inject the Lato stylesheet. ## Changelog ### Fixed - `/api/score` homepage form on anc.dev now executes Turnstile cleanly: zero `Uncaught TurnstileError`, zero "already executing" warnings, zero CSP violations on initial load OR `bfcache` restore (back-button to homepage from a result page). ### Changed - CSP allowlist for `https://fonts.googleapis.com` on `style-src` and `https://fonts.gstatic.com` on `font-src` (both `CSP_HTML` and `LIVE_SCORE_CSP`). Required for Turnstile's defensive Lato bootstrap even on Invisible-mode `sitekeys`. - TurnstileApi type tightened to match docs: `size` is now `'compact' | 'flexible' | 'normal'`; new optional `execution` field. ## Type of Change - [x] `fix`: Bug fix (non-breaking change which fixes an issue) ## Related Issues/Stories - Story: Surfaced sequentially during browser-side validation of PR #119. Each fix unmasked the next: #119 fixed the render-twice pattern, exposing the `size:'invisible'` invalid value; fixing that unmasked the Lato CSP gap and the `bfcache` stale-widget. All three now clean. - Issue: n/a - Architecture: n/a - Related PRs: #119 (reset+execute, now actually reachable), #118, #116, #115. ## Testing - [x] Unit tests added/updated - [x] All tests passing **Test Summary:** - `bun test`: 737 pass / 0 fail. - `bun run lint`: clean. - `bun run build`: clean. `dist/js/live-score.js` bundle contains `execution:'execute'` and the `pagehide` handler; no `size:'invisible'`. - Manual on staging at Worker version `c6ab5306-b238-4e07-b41b-472858261c15` (deployed from this branch via `bun x wrangler deploy --env staging`): - First submit (`ripgrep`) round-trips, redirects to `/score/ripgrep`. Zero console warnings. - Back-button to homepage. Zero CSP violations on `bfcache` restore. - Second submit succeeds the same as the first. ## Files Modified **Modified:** - `src/client/live-score.ts`: drop `size: 'invisible'` from `api.render()`; add `execution: 'execute'`; tighten `TurnstileApi` type; add `pagehide` listener that removes the widget + clears module-scope state. - `src/worker/headers.ts`: extend `CSP_HTML` `style-src` and `font-src` to allow Google Fonts origins (Turnstile bootstrap requirement). - `src/worker/score/summary-render.ts`: same CSP extension on `LIVE_SCORE_CSP` for `/live-score/<binary>` pages. **Created:** - None. **Renamed:** - None. **Deleted:** - None.
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
Two related changes in two commits.
Commit 1, enable the production homepage form after fail-closed verification. PR #115 deliberately omitted the production
TURNSTILE_SITEKEYvalue fromwrangler.jsonc, with the express purpose of forcing the live-scoring form to fail closed in production immediately after the v3 cut deployed: an emptysitekeycausessrc/client/live-score.tsto disable the form with a "Live scoring is available on staging only" notice rather than render a non-functional Turnstile widget. The point of that deliberate omission was to verify, on live anc.dev, that the fail-closed path actually works end-to-end before flipping the switch. It did: the form was disabled, the disabled-state message rendered, the surface degraded gracefully without a single 5xx. With fail-closed verified in production, this commit now enables the form by wiring the real productionsitekeyinto the top-levelvarsblock. The matchingTURNSTILE_SECRETwas set on the production Worker viawrangler secret put TURNSTILE_SECRETseparately (encrypted at rest in CF; never committed). Thesitekeyis public-by-design: Turnstile embeds it in HTML at request time for the client-side widget to render. Anyone viewing the page source already sees it; committing it towrangler.jsoncis intentional. The secret is what enforces ownership server-side at thesiteverifyAPI boundary, and it is not in the repo.Commit 2, trim wrangler.jsonc comments per
/code-commentspolicy + stash rationale. Eight comment blocks audited against the WHY-only / no-temporal / no-task-flow / no-local-doc-ref / no-instructional policy. Net 65 lines removed fromwrangler.jsonc, 41 lines added toRELEASES-RATIONALE.mdunder a new## Wrangler env inheritance trapssection that consolidates which keys inherit from top-level (routes,triggers,vars), which do not (containers,durable_objects,migrations, etc.), the REPLACE-not-merge semantics onvars, and the 2026-04-30 routing-drift incident as historical context. Each trimmed comment inwrangler.jsonckeeps the WHY that's unique to inline context and points at the consolidated rationale for the rest. Procedural runbook content that was duplicated betweenwrangler.jsoncandRELEASES.md§ Sandbox image releases is dropped from the config in favor of the pointer.Changelog
Added
TURNSTILE_SITEKEY. PR release: live-scoring v3 + anc 0.4.0 + post-#91 promotion #115's intentional omission served its purpose: the fail-closed path was verified in production (form disabled with the staging-only notice, no 5xx, graceful degradation). With fail-closed proven, the realsitekeyis now in place and the form is live.Changed
routes/triggers/varsinheritance semantics, the 2026-04-30 routing-drift incident, container app naming quirk) into a newRELEASES-RATIONALE.md§ Wrangler env inheritance traps.wrangler.jsonccomments now point at the consolidated rationale.Documentation
wrangler.jsonccomment blocks per the/code-commentspolicy: drop temporal phrasing (first-ever,since 2026-04-30, etc.), dropdocs/plans/and personal-repo references, drop instructional voice (Flip via:,Deploy with:,Removing this line will reintroduce the bug), drop runbook content that duplicatesRELEASES.md§ Sandbox image releases.Type of Change
feat: New feature (non-breaking change which adds functionality)PR #115 shipped working live-scoring infrastructure behind a deliberate fail-closed gate. Commit 1 flips the gate open after that fail-closed behavior was verified in production. Commit 2 is documentation hygiene that surfaced during a
/code-commentsaudit of the config file we were already editing.Related Issues/Stories
TURNSTILE_SITEKEYwas a designed-in safety gate so the v3 cut would fail closed if anything about Turnstile wiring were misconfigured. Manual visit to anc.dev right after release: live-scoring v3 + anc 0.4.0 + post-#91 promotion #115 deployed confirmed the fail-closed UX: form disabled, staging-only notice rendered, no error pages. Commit 1 enables the form now that fail-closed is proven. Documentation cleanup is opportunistic, triggered by being in the file already.Testing
Test Summary:
bun test: 737 pass / 0 fail across 28 files.bun x wrangler deploy --dry-run: clean. Listsenv.TURNSTILE_SITEKEY ("ff0x4AAAAAADQFMBoVm56-OPuQ")(the real productionsitekey).bun x wrangler deploy --dry-run --env staging: clean. Listsenv.TURNSTILE_SITEKEY ("1x00000000000000000000AA")(Cloudflare's always-pass testsitekey, unchanged). Confirms env.staging.vars REPLACE semantics correctly isolates staging from the new top-level value./code-commentspolicy pattern scan againstwrangler.jsonc: zero temporal / zero local-doc / zero instructional findings post-trim.wrangler secret listagainst the production Worker confirmsTURNSTILE_SECRETis set (re-set from 1Password'sagentnative-site Cloudflare Turnstile / prod.secret_keyfield viawrangler secret putbefore this PR opened)./api/scorePOST was dispatched; no 5xx in the request log. The deliberate omission worked exactly as designed.Post-merge verification plan (after the production deploy on this PR's merge):
/api/scorereturns a scorecard, browser redirects to/live-score/<binary>with the inline scorecard.curl https://anc.dev/api/score -H 'Content-Type: application/json' -d '{}'still returns400 unrecognized_input(sanity: handler unchanged by this PR).Files Modified
Modified:
wrangler.jsonc: enabled the top-levelvarsblock and populatedTURNSTILE_SITEKEYwith the productionsitekeyfrom 1Password (agentnative-site Cloudflare Turnstile / prod.site_key). Trimmed eight comment blocks per the/code-commentspolicy (see## Summarycommit 2 for the per-block summary). Net 65 lines removed.RELEASES-RATIONALE.md: new## Wrangler env inheritance trapssection consolidates inheritance semantics, override patterns, and the historical context that the config-file comments previously held inline.Created:
Renamed:
Deleted: