Implement APS render fix and TSJS resilience - #1002
Draft
aram356 wants to merge 646 commits into
Draft
Conversation
The winning-bid `hb_auction_id` carried `AuctionRequest.id`, which is
`ts-{ec_id}` whenever an Edge Cookie ID exists. That value reached
`window.tsjs.bids` and the page-bids JSON for every visitor, handing any
script on the page the identifier the `ts-ec` cookie keeps HttpOnly, and
it could not distinguish one auction from the next because it is stable
per visitor.
Mint an unrelated `ts-auc-{uuid}` per auction instead, and emit it only
when the GPT diagnostics integration is enabled, since nothing else
consumes it. `AuctionRequest.id` is unchanged for SSPs.
Keep the operator API read-only: `window.tsjs.gptDiagnostics` now exposes only snapshot, export, subscribe, show, and hide. The evidence writers Trusted Server's own modules use move to a separate internal channel, `window.tsjs.gptDiagnosticsRecorder`, so the documented contract matches what the object actually offers. Bound the store's deferred work by retained state rather than refresh rate. Request-intent evidence now expires lazily when the slot is next recorded or requested instead of owning a timer per source, which also removes the WeakRef-absent fallback that strongly retained every marked slot until expiry. Delivery-boundary notifications share one timer that re-arms from retained cycles. Stop reporting a source-agnostic GPT identifier as a reservation. Those IDs are populated for reservation and backfill alike, so they classify as `reservation` only alongside an explicit non-backfill fact. Evict a creative attempt whose cycle rendered empty, so a late markup response cannot claim a Trusted Server delivery against an empty render, and label badges from the derived delivery state instead of re-deriving the precedence rules from raw timestamps. Also: attribute `refresh(null)`, make the presentation switches exhaustive, hoist the snapshot out of the subscriber loop so every subscriber sees one capture, and make the export's attribution fields required. Type-check the export contract: the `expectTypeOf` assertions were never evaluated, and one of them was a genuine error. Scope `test.typecheck` to the type tests, since a package-wide `tsc --noEmit` still fails on pre-existing errors elsewhere. Fix the replacement-after-eviction test, which passed vacuously because ten open cycles made the final render ambiguous, and cover the paths the review identified: publisher-refresh malformed input, the association LRU trim, the out-of-order callback arms, a declined creative attempt, the Prebid dispatch-context restore arm, and wrapper install ordering. Correct the operator guide where it contradicted the implementation, and record the auction-token revision in the design spec.
Conflict in the Prebid refresh handler: main (#965) documented that the delegated refresh preserves the publisher's original bare form, while this branch replaced that call with the diagnostics recording plus the scoped dispatch context. Both hold — `dispatchPrebidRefresh` passes `slots` and `opts` through unchanged — so the resolution keeps the diagnostics calls and main's comment, extended to say the wrapper only scopes the shared context. Also add `bid_id` to the auction-ID test provider's `Bid` literal, a field main added in #996 after this branch introduced the provider.
Brings in the PR #997 review fixes: the read-only diagnostics facade split from the internal recorder channel, lazily expiring request-intent evidence with one shared delivery-boundary timer, source-agnostic IDs no longer reported as reservations, the empty-render attempt eviction, and the scoped type-check gate for the export contract. The branch also carries a merge of main, whose #965 and #996 arrive here as squashes of work rc/july already implements more fully. Where the two sides describe the same feature, rc/july's implementation is kept: - APS, adserver_mock, auction/types.rs, auction/formats.rs — rc/july's OpenRTB provider, renderer-aware bid_id precedence, and typed renderer envelope supersede main's versions, which drop fields rc/july needs. - prebid.rs — rc/july canonicalizes the excluded-suffix list at both the startup and build paths already, so main's `load_config` helper adds nothing. Main's test is taken instead of rc/july's: it builds from raw settings rather than reusing the config `validate_config_for_startup` already canonicalized, so it actually exercises the build path. - prebid/index.ts — a bare refresh that filtered slots must deliver the resolved target list, not stay bare, so rc/july's `deliveredSlots` behavior and its test expectation both stand. Three fixes are ported into rc/july's shapes rather than resolved away: - The EC-derived auction ID reached page JavaScript here too, through different plumbing: both collect paths inlined `request.id.as_str()` into `write_bids_to_state`, and page-bids passed it to `build_bid_map_with_auction_id`. All three now mint a per-auction token via `diagnostics_auction_id()`, gated on the diagnostics integration being enabled. - A blank Prebid Cache UUID no longer ships cache coordinates. It loses the hb_adid precedence to `adid` or the bid id, so the Universal Creative would fetch `?uuid=<non-cache-id>` and miss instead of using the inline adm. The gate moves from `is_some()` to `non_empty()`, and main's regression test comes along with rc/july's `Bid` fields added. - The browser-side excluded-suffix list is validated before use. The server only de-duplicates it, so an empty suffix matched every ad unit path and pulled every slot out of the refresh auction, and a non-array value threw inside the publisher's own `refresh()`. Also collapses a duplicated `hb_auction_id` write in `build_bid_map` down to one guarded insert, and points the Prebid refresh recorder at `gptDiagnosticsRecorder` to match the new channel.
| const MAX_ALIASES = 32; | ||
| const MAX_FACTS = 512; | ||
| const HASH = /^[0-9a-f]{64}$/; | ||
| const CAPABILITY = /^[a-z][a-z0-9_]*(?:[._][a-z0-9_]+)*$/; |
|
|
||
| function exactControllerInline(document: string): string { | ||
| const inline = [ | ||
| ...document.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/giu), |
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
Implements the APS render fix and TSJS resilience design as a coordinated hard cutover, with no backward-compatibility runtime or legacy API aliases.
core + render_runtime + creativeboot artifact, including authenticated opaque-origin handlingrc/julyTSJS behavior through the executable adoption ledger and hard-cutover gatesScope boundaries
Current remediation checkpoint
5b12c161daeed3e6f9e64a7a7012d8a6f5153f12da6237db414516d27426d1ae0be03c024274dd0e869a335fb3c00bbc52afc0bdmainVerification
Local verification at the current implementation checkpoint:
Open merge blocker: first-display load time
The automatic production-shaped candidate-versus-current-
maingate is intentionally strict and remains red. The completed paired run measured:mainp90: approximately 473.3 msPerformance run 31657180720
This is an architecture blocker, not an accepted budget reset. The current parser-blocking release carries roughly 395 KB raw for the production
core + render_runtime + creative + gptshape versus roughly 81 KB on currentmain. The next implementation checkpoint must introduce a lean first-display owner and move the full resilient lifecycle behind the protected first display while preserving APS/ADM/GPT correctness. The 1.10 threshold and actual-byte network measurement will not be weakened or relabeled.The timeout/head-attestation defect exposed by the failing run is fixed at the current head, so subsequent failing runs retain complete schema-5 evidence and bind PR evidence to the source head SHA rather than GitHub's synthetic merge SHA.
Protected cutover prerequisites
This PR is not merge-ready until the first-display performance gate passes. Production activation also requires release coordination to supply the active Fastly service/version identity and the protected real-GAM environment. No production deployment or protected real-GAM run was performed from this worktree.