feat(credential-rendering): wire shadow parity mode behind LD flag
loading diff…
Stacked on #10646 (template compiler + renderer); top of the stack started at #10645. Flag-gated (default off), fire-and-forget — can never affect the request. Prod risk low.
Render+resolve the credential grammar alongside the legacy path on sampled live traffic and compare structurally.
Shadow harness (credential_rendering/shadow/, deleted at serve cutover):
origin_probe / refresh_pin_probe on the rendered destination — exactly what the proxy will evaluate); nothing enforces them yetconnectionState.val — then buildAuthOverlay → resolveAuthOverlay (dev0) → hashed diff of base_url/headers/query vs legacybuildRefreshRequest → resolveRenderedRequest → the grammar package's own encodeResolvedRequestBody → hashed diff vs the legacy constructionrunShadowGuarded (the unkillable fire-and-forget wrapper both runners use) + renderNotPossibleFieldscredential_rendering_shadow, facet shadow.outcome + rendered_bytes/envelope_count for proxy body budgetsWiring:
getAuthorization (getAuthorizationParams.ts): capture before legacy render, compare after successrefreshOAuth2AccessToken (refreshAccessToken.ts): capture before the OAuth2 construction; comparison sends nothingcredentialRenderingShadowSampleRate (percent, project context, fractional, default 0 = off; invalid values → off)oAuth2.ts legacy-parts extraction: refresh request construction moved to public buildRefreshHttpRequest() which the live send path consumes (shadow observation cannot drift); differential refresh suite pins byte-identity.
🤖 Generated with Claude Code