Repository navigation
Type the redirect target at the transport boundary instead of passing a raw Location #705
Description
Activity
- addedenhancementNew feature or requestNew feature or requestmediumRoadmap items to schedule within the current quarter. Clear scope, normal review cycles.Roadmap items to schedule within the current quarter. Clear scope, normal review cycles.
on Sep 13, 2026 - addedrefactorBehaviour-preserving restructuring that improves code health.Behaviour-preserving restructuring that improves code health.
on Sep 13, 2026 @CodeRabbit plan
coderabbitai commented
on Sep 16, 2026 coderabbitaiboton Sep 16, 2026 – with coderabbitaiContributorMore actionsCoding Plan
Summary
Select option 1 and record it as a dated addendum to ADR-023.
Move
Locationresolution and its absent and unparsable diagnostics intoredirect.rs. ReduceRedirectRejectionto the four redirect-decision variants. Keep the check order and the four bounded telemetry fields.Keep
location_missingandlocation_invalidin the closed telemetry vocabulary. Reuse the existing Fluent keys, so metric cardinality and user-visible text stay fixed.Update the unit tests, snapshots, and documentation in the same change. Keep the redirect tests green.
File-level change summary
docs/adr-023-revalidate-fetch-redirects.md: add a dated addendum; correct the implementation-reference attribution.src/stdlib/network/redirect_chain.rs: changeadvanceto take aUrl; removeLocationMissingandLocationInvalid; update doc comments.src/stdlib/network/redirect.rs: add theLocationFailureenum, the resolver, and the reporter; wire them intodispatch_request; trimfailure_categoryandrejection_errorto four variants.src/stdlib/network/telemetry.rs: no vocabulary change; verifyFETCH_REDIRECT_FAILURE_VALUESstill lists both location reasons.src/stdlib/network/redirect_chain_tests.rs: pass resolvedUrlvalues; removeunusable_locations_are_refused.src/stdlib/network/redirect_adapter_tests.rs: trim the rejection enumeration to four variants; add resolver and reporter tests.src/snapshots/network_redirect/: relocate or regenerate the two location snapshots.src/localization/keys.rsandlocales/*/messages.ftl: verify the two keys and messages remain unchanged.docs/developers-guide.md: update the "Fetch redirect architecture" section.
Follow-up agent prompt
Implement the ADR-023 addendum and the redirect boundary change described in the plan. Constraints you must not break: - Redirect telemetry and trace events emit only operation, outcome, reason, and hop. Never pass a URL, host, location, or userinfo into any emitted or logged field. - Keep the check order in RedirectChain::advance: hop limit, cross-origin credential removal, loop detection, policy check. The policy check must still precede every redirected connection. - Keep "location_missing" and "location_invalid" in telemetry::FETCH_REDIRECT_FAILURE_VALUES. The adapter still records them. - Reuse the existing Fluent keys STDLIB_FETCH_REDIRECT_LOCATION_MISSING and STDLIB_FETCH_REDIRECT_LOCATION_INVALID with redacted current_url. Do not change their message text. Steps: 1. Change RedirectChain::advance to take a resolved Url and remove the LocationMissing and LocationInvalid variants. 2. Add a LocationFailure enum, a header resolver, and a failure reporter in redirect.rs, and call chain.advance only with a resolved Url. 3. Trim failure_category and rejection_error to the four remaining variants. 4. Update redirect_chain_tests.rs and redirect_adapter_tests.rs, add adapter tests for the two location failures, and regenerate the two snapshots. 5. Update the developers-guide "Fetch redirect architecture" section. Run the redirect unit tests and the tests/std_filter_tests redirect suites, and confirm they are green.Design Choices
Design Choice 1: Which option does the ticket select?
Options Considered:
- Move
Locationresolution to the adapter and hand the chain a typed, already-resolved target. RemoveLocationMissingandLocationInvalidfromRedirectRejection. - Keep
advance(Option<&str>)and document why a header-level fact stays in the domain's rejection vocabulary.
Chosen Option: 1
Rationale: It aligns with the documented domain/adapter boundary (ADR-005, ADR-021, developers-guide) that keeps parsing and transport facts in the adapter and keeps only pure decisions in the domain.
Design Choice 2: What typed target does the adapter hand to the chain?
Options Considered:
advance(&mut self, target: Url). The adapter resolves the header and handles absence or parse failure with an adapter-local enum before callingadvance.advance(&mut self, target: Result<Url, LocationFailure>). The chain receives the failure and forwards it.
Chosen Option: 1
Rationale: It keeps
advancefree of transport failure vocabulary and keeps the domain input a fully validUrl, so the domain describes only redirect decisions.Design Choice 3: Do we amend ADR-023 or write a new ADR?
Options Considered:
- Append a dated
## Addendumto ADR-023. - Create ADR-024 that cross-links back to ADR-023.
Chosen Option: 1
Rationale: The repository convention amends an existing decision with a dated addendum in the same file, and this change refines ADR-023 rather than introducing an independent decision.
💡 User Tips
Regenerate the plan with different choices with
@coderabbitai <feedback>.Implementation Steps
Phase 1: Record the decision
Record the architectural choice before you change any code. This makes the boundary change auditable, and it restates the ordering and telemetry guarantees in one place.
Add an ADR-023 addendum selecting option 1
Amend the existing decision record to move
Locationresolution to the adapter.- Append a
## Addendum — <YYYY-MM-DD>: Resolve the Location header at the transport boundarysection todocs/adr-023-revalidate-fetch-redirects.md. - State the amendment: the adapter now resolves
Locationand owns the "absent" and "present but unparsable" diagnostics, and the chain now receives an already-resolvedUrl. - Restate the unchanged invariants: the hop limit, cross-origin credential removal, loop detection, and the policy check still run in that order; the policy check still precedes every redirected connection; redirect telemetry still emits only
operation,outcome,reason, andhop. - Correct the "Implementation references" attribution so
Locationparsing is credited tosrc/stdlib/network/redirect.rsand the chain module is credited only with decisions on a resolved target.
🤖 Prompt for AI agents
Implement Phase 1: record the architectural decision before touching any code. - Open `docs/adr-023-revalidate-fetch-redirects.md` and append a new section titled `## Addendum — <YYYY-MM-DD>: Resolve the Location header at the transport boundary`. Use the actual date. - In the addendum, state clearly that the adapter now resolves the `Location` header and owns the "absent" and "present but unparsable" diagnostics, and that the chain now receives an already-resolved `Url` instead of a raw string. - Restate the invariants that do not change: the check order (hop limit, cross-origin credential removal, loop detection, policy check) stays the same; the policy check still runs before every redirected connection; redirect telemetry still emits exactly four fields: `operation`, `outcome`, `reason`, and `hop`. - Correct the "Implementation references" section of the ADR so that `Location` parsing is attributed to `src/stdlib/network/redirect.rs`, and the chain module (`redirect_chain.rs`) is attributed only with decisions made on an already-resolved target.Phase 2: Relocate Location resolution to the adapter
Move the header resolution and its two failure diagnostics from the pure chain into the adapter. Reduce
RedirectRejectionto redirect decisions only. Preserve the check ordering and the four bounded telemetry fields.Task 1: Narrow the domain to decisions on a resolved target
Make
RedirectChainoperate on a validUrland drop the transport-shaped variants.- Update
src/stdlib/network/redirect_chain.rs: changeadvanceto accept a resolvedUrlinstead ofOption<&str>, and remove the earlyLocationMissingandjoin/LocationInvalidbranches. - Remove the
LocationMissingandLocationInvalidvariants fromRedirectRejection. KeepCredentialsNotRemovable,LimitExceeded,Loop, andPolicy. - Keep the remaining check order inside
advance:reject_excessive_redirects,redact_cross_origin_userinfo,reject_redirect_loop,evaluate_target. - Update the module and
advancedoc comments to state that the input is an already-resolved target and that transport parsing lives in the adapter.
Task 2: Resolve the Location header in the adapter with typed failures
Add the header resolution step and an adapter-local failure type at the transport boundary.
- Add a small adapter-local enum in
src/stdlib/network/redirect.rsthat distinguishes an absent header from a present but unparsable value (for exampleLocationFailure::MissingandLocationFailure::Unparsable). - Add a resolver function in
redirect.rsthat reads the raw header, resolves it againstchain.current_url()withjoin, and returns either the resolvedUrlor the typedLocationFailure. - Update
dispatch_requestso it resolves the header first, returns the adapter diagnostic on failure, and callschain.advance(target)only with a resolvedUrl. - Compute the reported hop for a resolution failure as
chain.hops().saturating_add(1), matching the existing refusal hop computation.
Task 3: Emit adapter diagnostics and telemetry for resolution failures
Reproduce the localised error and the four-field telemetry for the two relocated cases without going through
RedirectRejection.- Add a reporter function in
redirect.rsforLocationFailurethat mirrorsreport_refused_redirect: calltelemetry::record_redirect_refusedwith"location_missing"or"location_invalid", emit thetracing::warn!event with onlyoperation,redirect_outcome,redirect_failure, andhop, and return the localised error. - Build the localised error for the two cases with the existing Fluent keys
STDLIB_FETCH_REDIRECT_LOCATION_MISSINGandSTDLIB_FETCH_REDIRECT_LOCATION_INVALID, usingredacted_url(chain.current_url())for the message argument. Do not pass any URL, host, location, or userinfo into the telemetry or trace fields. - Update
failure_categoryandrejection_errorinredirect.rsto remove theLocationMissingandLocationInvalidarms, so both functions match only the four remainingRedirectRejectionvariants. - Keep
"location_missing"and"location_invalid"intelemetry::FETCH_REDIRECT_FAILURE_VALUES. The adapter still records these reasons, so the closed vocabulary and metric cardinality stay fixed.
🤖 Prompt for AI agents
Implement Phase 2: move `Location` header resolution from the domain module into the transport adapter, and shrink the domain's rejection vocabulary accordingly. In `src/stdlib/network/redirect_chain.rs`: - Change `advance` to accept a resolved `Url` instead of `Option<&str>`. Remove the early `LocationMissing` and `join`/`LocationInvalid` branches. - Remove `LocationMissing` and `LocationInvalid` from `RedirectRejection`. Keep only `CredentialsNotRemovable`, `LimitExceeded`, `Loop`, and `Policy`. - Keep the check order inside `advance` unchanged: `reject_excessive_redirects`, `redact_cross_origin_userinfo`, `reject_redirect_loop`, `evaluate_target`. - Update the module and `advance` doc comments to state that the input is an already-resolved target, and that transport parsing now lives in the adapter. In `src/stdlib/network/redirect.rs`: - Add a small adapter-local enum, for example `LocationFailure::Missing` and `LocationFailure::Unparsable`, to distinguish an absent header from a present but unparsable value. - Add a resolver function that reads the raw `Location` header, resolves it against `chain.current_url()` using `join`, and returns either the resolved `Url` or the `LocationFailure`. - Update `dispatch_request` to call the resolver first. On failure, return the adapter diagnostic. On success, call `chain.advance(target)` with the resolved `Url` only. - Compute the reported hop for a resolution failure as `chain.hops().saturating_add(1)`, matching the existing refusal hop computation. - Add a reporter function for `LocationFailure` that mirrors `report_refused_redirect`: call `telemetry::record_redirect_refused` with `"location_missing"` or `"location_invalid"`, emit a `tracing::warn!` event with exactly `operation`, `redirect_outcome`, `redirect_failure`, and `hop`, and return the localised error. - Build the localised error using the existing Fluent keys `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` and `STDLIB_FETCH_REDIRECT_LOCATION_INVALID`, with `redacted_url(chain.current_url())` as the message argument. Never pass a URL, host, location, or userinfo into any telemetry or trace field. - Trim `failure_category` and `rejection_error` in `redirect.rs` to remove the `LocationMissing` and `LocationInvalid` arms, so both functions handle only the four remaining `RedirectRejection` variants. - Keep `"location_missing"` and `"location_invalid"` in `telemetry::FETCH_REDIRECT_FAILURE_VALUES` in `telemetry.rs`. Do not remove them; the adapter still records these reasons, and the closed telemetry vocabulary must stay fixed.Phase 3: Update tests, snapshots, localisation, and documentation
Bring every guard and every document that pins the old boundary into line with the new one. Keep the redirect tests green.
Task 1: Update the domain and adapter unit tests
Realign the tests that drive
advanceand enumerate the rejections.- Update
src/stdlib/network/redirect_chain_tests.rs: change everyadvancecall to pass a resolvedUrl, and removeunusable_locations_are_refused, because theLocationMissingandLocationInvalidvariants no longer exist in the domain. - Update
src/stdlib/network/redirect_adapter_tests.rs: reduceevery_rejectionand the exhaustiveness and redaction tests to the four remaining variants. - Add adapter tests for the resolver and the new reporter that assert: an absent header yields the
"location_missing"reason and theSTDLIB_FETCH_REDIRECT_LOCATION_MISSINGmessage; an unparsable header yields the"location_invalid"reason and theSTDLIB_FETCH_REDIRECT_LOCATION_INVALIDmessage; neither path leaks credentials.
Task 2: Relocate the location snapshots
Keep the pinned Fluent output for the two relocated cases.
- Regenerate or move the two snapshot fixtures under
src/snapshots/network_redirect/forlocation_missingandlocation_invalid, sourced from the new adapter test path inredirect_adapter_tests.rs. - Confirm the rendered text is unchanged: the same redacted
current_url, the same "did not include a Location header" and "Invalid redirect location '' … Location could not be resolved" wording.
Task 3: Verify localisation and integration coverage
Confirm the Fluent keys stay consistent across all locales and the integration suite still passes.
- Verify that
STDLIB_FETCH_REDIRECT_LOCATION_MISSINGandSTDLIB_FETCH_REDIRECT_LOCATION_INVALIDinsrc/localization/keys.rsand their messages in everylocales/*/messages.ftlfile remain correct. Keep the message text and arguments unchanged, because the adapter reuses these keys. - Run and, if needed, update
tests/std_filter_tests/network_redirect_chain_tests.rsandtests/std_filter_tests/network_redirect_tests.rs. These suites do not exercise the absent or unparsable paths, so expect no behavioural change; adjust only if a compilation reference to the removed variants exists.
Task 4: Update the developers guide
Bring the architecture prose into line with the new boundary.
- Update the "Fetch redirect architecture" section of
docs/developers-guide.md: state that the adapter resolves theLocationheader and owns the absent and unparsable diagnostics, and that the chain receives an already-resolved target. - Update the rejection vocabulary description so
location_missingandlocation_invalidare documented as adapter-levelredirect_failurereasons, notRedirectRejectionvariants. - Restate the maintenance rule and the four-field bound so they remain consistent with the ADR-023 addendum.
🤖 Prompt for AI agents
Implement Phase 3: align every test, snapshot, localisation source, and documentation page with the new domain/adapter boundary from Phase 2, and keep the redirect test suites green. Tests: - In `src/stdlib/network/redirect_chain_tests.rs`, change every `advance` call to pass a resolved `Url`. Remove the `unusable_locations_are_refused` test, because `LocationMissing` and `LocationInvalid` no longer exist in the domain. - In `src/stdlib/network/redirect_adapter_tests.rs`, reduce `every_rejection` and the exhaustiveness and redaction tests to the four remaining `RedirectRejection` variants. - Add new adapter tests for the resolver and the reporter. Assert that an absent header produces the `"location_missing"` reason and the `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` message. Assert that an unparsable header produces the `"location_invalid"` reason and the `STDLIB_FETCH_REDIRECT_LOCATION_INVALID` message. Assert that neither path leaks credentials. Snapshots: - Regenerate or move the two snapshot fixtures under `src/snapshots/network_redirect/` for `location_missing` and `location_invalid`, sourced from the new adapter test path. - Confirm the rendered text stays exactly the same: the same redacted `current_url`, the same "did not include a Location header" wording, and the same "Invalid redirect location '<redacted>' … Location could not be resolved" wording. Localisation and integration: - Verify `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` and `STDLIB_FETCH_REDIRECT_LOCATION_INVALID` in `src/localization/keys.rs`, and their messages in every `locales/*/messages.ftl` file, stay correct and unchanged, because the adapter reuses these keys as-is. - Run `tests/std_filter_tests/network_redirect_chain_tests.rs` and `tests/std_filter_tests/network_redirect_tests.rs`. Expect no behavioural change, since neither suite exercises the absent or unparsable paths. Fix only compilation references to the removed variants, if any exist. Documentation: - Update the "Fetch redirect architecture" section of `docs/developers-guide.md`. State that the adapter resolves the `Location` header and owns the absent and unparsable diagnostics, and that the chain receives an already-resolved target. - Update the rejection vocabulary description so `location_missing` and `location_invalid` are documented as adapter-level `redirect_failure` reasons, not as `RedirectRejection` variants. - Restate the maintenance rule and the four-field telemetry bound so the guide stays consistent with the ADR-023 addendum.Research
The fetch redirect logic splits across two modules under
src/stdlib/network/.redirect_chain.rsis a pure state machine. It holdsRedirectChain, the six-variantRedirectRejectionenum, andadvance, which today accepts the rawLocationstring, resolves it withcurrent_url.join, and then applies the hop limit, cross-origin credential removal, loop detection, and policy check in that order.redirect.rsis the transport adapter. It drives the HTTP loop withureq, readsresponse.header("Location"), hands the raw value toadvance, maps rejections to the closedredirect_failuretelemetry vocabulary throughfailure_category, and builds localised Fluent diagnostics throughrejection_error.telemetry.rsdeclares the closed label vocabularies, includingFETCH_REDIRECT_FAILURE_VALUES. ADR-023 and the "Fetch redirect architecture" section ofdocs/developers-guide.mddocument the current resolve-then-check ownership boundary. The repository convention (ADR-005, ADR-021) keeps pure decisions in the domain module and keeps parsing, telemetry, and localised text in the adapter.
🚀 Next Steps
🤖 All AI agent prompts combined
Task: 1 Implement Phase 1: record the architectural decision before touching any code. - Open `docs/adr-023-revalidate-fetch-redirects.md` and append a new section titled `## Addendum — <YYYY-MM-DD>: Resolve the Location header at the transport boundary`. Use the actual date. - In the addendum, state clearly that the adapter now resolves the `Location` header and owns the "absent" and "present but unparsable" diagnostics, and that the chain now receives an already-resolved `Url` instead of a raw string. - Restate the invariants that do not change: the check order (hop limit, cross-origin credential removal, loop detection, policy check) stays the same; the policy check still runs before every redirected connection; redirect telemetry still emits exactly four fields: `operation`, `outcome`, `reason`, and `hop`. - Correct the "Implementation references" section of the ADR so that `Location` parsing is attributed to `src/stdlib/network/redirect.rs`, and the chain module (`redirect_chain.rs`) is attributed only with decisions made on an already-resolved target. =============================================================================== Task: 2 Implement Phase 2: move `Location` header resolution from the domain module into the transport adapter, and shrink the domain's rejection vocabulary accordingly. In `src/stdlib/network/redirect_chain.rs`: - Change `advance` to accept a resolved `Url` instead of `Option<&str>`. Remove the early `LocationMissing` and `join`/`LocationInvalid` branches. - Remove `LocationMissing` and `LocationInvalid` from `RedirectRejection`. Keep only `CredentialsNotRemovable`, `LimitExceeded`, `Loop`, and `Policy`. - Keep the check order inside `advance` unchanged: `reject_excessive_redirects`, `redact_cross_origin_userinfo`, `reject_redirect_loop`, `evaluate_target`. - Update the module and `advance` doc comments to state that the input is an already-resolved target, and that transport parsing now lives in the adapter. In `src/stdlib/network/redirect.rs`: - Add a small adapter-local enum, for example `LocationFailure::Missing` and `LocationFailure::Unparsable`, to distinguish an absent header from a present but unparsable value. - Add a resolver function that reads the raw `Location` header, resolves it against `chain.current_url()` using `join`, and returns either the resolved `Url` or the `LocationFailure`. - Update `dispatch_request` to call the resolver first. On failure, return the adapter diagnostic. On success, call `chain.advance(target)` with the resolved `Url` only. - Compute the reported hop for a resolution failure as `chain.hops().saturating_add(1)`, matching the existing refusal hop computation. - Add a reporter function for `LocationFailure` that mirrors `report_refused_redirect`: call `telemetry::record_redirect_refused` with `"location_missing"` or `"location_invalid"`, emit a `tracing::warn!` event with exactly `operation`, `redirect_outcome`, `redirect_failure`, and `hop`, and return the localised error. - Build the localised error using the existing Fluent keys `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` and `STDLIB_FETCH_REDIRECT_LOCATION_INVALID`, with `redacted_url(chain.current_url())` as the message argument. Never pass a URL, host, location, or userinfo into any telemetry or trace field. - Trim `failure_category` and `rejection_error` in `redirect.rs` to remove the `LocationMissing` and `LocationInvalid` arms, so both functions handle only the four remaining `RedirectRejection` variants. - Keep `"location_missing"` and `"location_invalid"` in `telemetry::FETCH_REDIRECT_FAILURE_VALUES` in `telemetry.rs`. Do not remove them; the adapter still records these reasons, and the closed telemetry vocabulary must stay fixed. =============================================================================== Task: 3 Implement Phase 3: align every test, snapshot, localisation source, and documentation page with the new domain/adapter boundary from Phase 2, and keep the redirect test suites green. Tests: - In `src/stdlib/network/redirect_chain_tests.rs`, change every `advance` call to pass a resolved `Url`. Remove the `unusable_locations_are_refused` test, because `LocationMissing` and `LocationInvalid` no longer exist in the domain. - In `src/stdlib/network/redirect_adapter_tests.rs`, reduce `every_rejection` and the exhaustiveness and redaction tests to the four remaining `RedirectRejection` variants. - Add new adapter tests for the resolver and the reporter. Assert that an absent header produces the `"location_missing"` reason and the `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` message. Assert that an unparsable header produces the `"location_invalid"` reason and the `STDLIB_FETCH_REDIRECT_LOCATION_INVALID` message. Assert that neither path leaks credentials. Snapshots: - Regenerate or move the two snapshot fixtures under `src/snapshots/network_redirect/` for `location_missing` and `location_invalid`, sourced from the new adapter test path. - Confirm the rendered text stays exactly the same: the same redacted `current_url`, the same "did not include a Location header" wording, and the same "Invalid redirect location '<redacted>' … Location could not be resolved" wording. Localisation and integration: - Verify `STDLIB_FETCH_REDIRECT_LOCATION_MISSING` and `STDLIB_FETCH_REDIRECT_LOCATION_INVALID` in `src/localization/keys.rs`, and their messages in every `locales/*/messages.ftl` file, stay correct and unchanged, because the adapter reuses these keys as-is. - Run `tests/std_filter_tests/network_redirect_chain_tests.rs` and `tests/std_filter_tests/network_redirect_tests.rs`. Expect no behavioural change, since neither suite exercises the absent or unparsable paths. Fix only compilation references to the removed variants, if any exist. Documentation: - Update the "Fetch redirect architecture" section of `docs/developers-guide.md`. State that the adapter resolves the `Location` header and owns the absent and unparsable diagnostics, and that the chain receives an already-resolved target. - Update the rejection vocabulary description so `location_missing` and `location_invalid` are documented as adapter-level `redirect_failure` reasons, not as `RedirectRejection` variants. - Restate the maintenance rule and the four-field telemetry bound so the guide stays consistent with the ADR-023 addendum.💡 Iterate on the plan with:
`@coderabbitai` <feedback>Example Feedback - `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2. - `@coderabbitai` For design choice 1 go ahead with option 3 and replan.
- added a commit that references this issue
on Sep 19, 2026
Context
Follow-up from the Domain Architecture warning raised during review of PR #667,
which implements #647 and ADR-023 (revalidate every fetch redirect against
NetworkPolicy). The warning is about the shape of the transport/domainboundary, not about the policy check the PR adds, so it was deliberately
deferred rather than actioned in #647.
Observation
RedirectChain::advanceaccepts the rawLocationheader value as a string andthen reports the transport's parsing failures in the chain's own vocabulary:
Two of the six
RedirectRejectionvariants —LocationMissingandLocationInvalid— therefore describe the HTTP response rather than a redirectdecision. The domain resolves and parses the header, then has to localize a
failure that belongs to the adapter.
Decision required
Pick one and record it:
Locationheader at thetransport boundary and hand the chain a typed target — either an
already-resolved
Url, or an enum distinguishing absent from present butunparsable — with both cases localized as adapter diagnostics instead of
RedirectRejectionvariants.belongs in the domain's rejection vocabulary.
Blast radius if option 1 is taken
src/stdlib/network/redirect.rs:240-241(theredirect_failuremetricmapping) and the two localized error constructors at
:255and:261.locales/.redirect_failurevocabulary(
location_missing,location_invalid) insrc/stdlib/network/telemetry.rs,and any snapshot fixtures that pin them.
src/stdlib/network/redirect_chain_tests.rsand the end-to-end coverage intests/std_filter_tests/network_redirect_chain_tests.rsandtests/std_filter_tests/network_redirect_tests.rs.docs/developers-guide.md, which bothdocument the current resolve-then-check ordering.
Constraints to preserve
operation,outcome,reason, andhop. Both variants currently carry only a redactedcurrent_url, so the redesign must not reintroduce a location, URL, host, oruserinfo into any emitted or logged field.
cross-origin credential removal, and the policy check must still run in that
order, and the policy check must still precede every redirected connection.
Acceptance
with its rationale.
redirect_failurevocabulary, the Fluentkeys in every locale, the snapshots, and the documentation are updated in the
same change, with the redirect tests still green.
Refs #647, PR #667.