Skip to content

feat(diagnostics): Phase 3a — structured ad:error events + Logger wiring#5

Draft
LockeAG wants to merge 5 commits into
feat/gpt-modernization-phase-0-2from
feat/phase-3a-diagnostics
Draft

feat(diagnostics): Phase 3a — structured ad:error events + Logger wiring#5
LockeAG wants to merge 5 commits into
feat/gpt-modernization-phase-0-2from
feat/phase-3a-diagnostics

Conversation

@LockeAG

@LockeAG LockeAG commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 3a: make every ad failure programmatically observable. Stacked on
top of #3 (feat/gpt-modernization-phase-0-2) — rebase onto main
after #3 lands.

Five additions, all opt-in, none of which existed before:

  1. ad:error CustomEvent on the host <dreams-ad-engine> element
    with typed payload: slotId, adUnit, phase, error, recoverable.
  2. Activate the dormant Logger — was shipped but imported by
    nothing. Now wired across 9 call sites (8 in ad.component.ts, 1 in
    config.provider.ts).
  3. Debug toggle, precedence high → low:
    1. DreamsAdConfig.init({ debug: true | false }) — explicit boolean wins
    2. ?dae-debug=1 URL param — parsed once at module load
    3. window.__dreamsDebug = true — runtime toggleable (auto mode only)
  4. DreamsAdConfig.openConsole(slotId?) — wraps googletag.openConsole()
    with cmd queueing and a safe fallback for builds without the API.
  5. Auto-bridge ad:errorwindow.dataLayer as dreams_ad_error.
    Mirrors the existing prebid_bid_won pattern; GTM consumers get
    errors with zero additional wiring.

Wrapped lifecycle phases

Previously-unprotected GPT calls now have granular try/catch:

Phase Recoverable Sites
config-resolution reserved for future config-load failures
targeting-resolution yes DreamsTargetingService silent timeout, slot.setConfig({ targeting })
slot-define no defineSlot().addService(), outer catch-all
slot-display no googletag.display(), container-not-in-DOM guard
slot-refresh no both pubads().refresh([defineAdSlot]) sites
apstag-init yes apstag.init(), apstag.setDisplayBids()
prebid-init yes pbjs.que.push, pbjs.setTargetingForGPTAsync, pbjs.requestBids
out-of-page-define no interstitial + top/bottom anchor defineOutOfPageSlot()
size-mapping yes sizeMapping().addSize().build()

Files touched

  • src/features/logging/logger.types.ts (new)AdErrorPhase, AdErrorEventDetail
  • src/features/logging/logger.tsLogger.dispatchAdError(), __dreamsDebug runtime check
  • src/features/logging/index.ts — export new types
  • src/features/config/config.types.tsdebug?: boolean on AdConfigInit
  • src/features/config/config.provider.ts — debug resolution, openConsole(), URL param parsing, console.warnLogger.warn
  • src/features/dreamsAdEngine/components/ad.component.ts — 8 console.*Logger.*, 11 try/catch additions, reorder firstUpdated so divId exists before targeting resolution
  • src/features/dreamsAdEngine/types/interfaces.ts__dreamsDebug?: boolean on Window
  • dist/, types/ — rebuilt

Build: ✓ pnpm build clean. Bundle 82.86 kB / 20.96 kB gzipped.

Consumer-facing event shape

interface AdErrorEventDetail {
  slotId: string;        // CONTAINER_ID (DOM id)
  adUnit: string;        // /<networkId>/<sitePrefix>-...
  phase: AdErrorPhase;   // one of the 9 above
  error: Error | string;
  recoverable: boolean;
}
window.dataLayer.push({
  event: "dreams_ad_error",
  phase, slotId, adUnit,
  error_message: String(error),
});

Out of scope (deliberate)

  • Sentry / Datadog / external error tracking — library stays vendor-agnostic; consumers wire via ad:error.
  • Retry logic — recoverable is informational; auto-retry is policy.
  • Error rate-limiting — defer until reported as a problem.
  • INP/LCP attribution — separate Phase 3b candidate.

Test plan

Combined cobertura360.mx staging verification (with #3) when MVP is ready:

  • All original feat: GPT modernization (Phase 0 + 2) — lifecycle events, SRA, collapseDiv, CLS reserve #3 verification sections still pass (slots render, event order, SRA, CLS, empty-slot, SPA nav, APS+Prebid race)
  • ad:error fires on injected failures — e.g. pass a malformed ad unit path
  • window.dataLayer receives dreams_ad_error events
  • DreamsAdConfig.openConsole() opens the GPT console overlay
  • ?dae-debug=1 enables verbose logging in prod
  • window.__dreamsDebug = true toggles logging at runtime
  • Targeting timeout surfaces as ad:error (recoverable: true)

LockeAG added 5 commits May 13, 2026 20:06
Make every ad failure programmatically observable. Five additions, all
opt-in, none of which existed:

- `ad:error` CustomEvent on the host element with typed phase + slotId +
  adUnit + error + recoverable payload (AdErrorEventDetail).
- Activate the dormant Logger across 9 sites in ad.component.ts +
  config.provider.ts (was imported by nothing).
- Debug toggle with high → low precedence:
    1. DreamsAdConfig.init({ debug }) — explicit boolean
    2. ?dae-debug=1 URL param (parsed once at module load)
    3. window.__dreamsDebug = true (runtime toggleable, auto mode only)
- DreamsAdConfig.openConsole() wraps googletag.openConsole() with cmd
  queueing + safe fallback.
- Auto-bridge ad:error → window.dataLayer as `dreams_ad_error`, mirroring
  the existing prebid_bid_won pattern. GTM consumers get errors with no
  additional wiring.

Wraps previously-unprotected GPT calls in granular try/catch — phase
field localizes which lifecycle step failed:
config-resolution, targeting-resolution, slot-define, slot-display,
slot-refresh, apstag-init, prebid-init, out-of-page-define, size-mapping.

Targeting service's silent timeout (resolve with []) now surfaces as
ad:error (recoverable: true) so consumers can detect window.dfp setup
issues without diffing analytics.

Out of scope: Sentry/external trackers, retry logic, error rate-limiting,
INP/LCP attribution.
Add consumer-facing documentation for the additions landing in v0.7.0:

- Features list: ad:error event, debug toggle, full lifecycle bullets
- New Diagnostics & Debugging section: ad:error wiring, dataLayer
  bridge, debug toggle precedence (init.debug > ?dae-debug=1 >
  window.__dreamsDebug), DreamsAdConfig.openConsole()
- Events section: ad:requested, ad:response, ad:loaded, ad:error
  with full phase reference table
- AdConfigInit example + signature: collapseEmptyDivs, debug
- Methods list: openConsole, getCollapseEmptyDivs
- Exported types: AdErrorEventDetail, AdErrorPhase, LoggerConfig,
  PageSettingsConfig
- Migration: v0.6 → v0.7 section covering all behavior changes
  (Logger now routes nine console.* sites, targeting timeout
  surfaces as ad:error)
- CDN examples bumped @0.5 → @0.7 for WordPress + vanilla HTML
Combined entry covering PR #3 (GPT modernization) + PR #5 (Phase 3a
diagnostics). All changes additive — no public API removals or renames.

Sections:
- Added: lifecycle events (ad:requested, ad:response, ad:loaded),
  ad:error CustomEvent + AdErrorPhase types, window.dataLayer bridge,
  debug toggle (3-tier precedence), DreamsAdConfig.openConsole(),
  Logger.dispatchAdError() helper, collapseEmptyDivs config,
  explicit SRA opt-in, PageSettingsConfig interface, CLS reserve
  fallback from sizing attribute, new exported types
- Changed: console.* sites now route through Logger (prod-quiet by
  default), firstUpdated reordered for stable slotId, 11 GPT calls
  wrapped with granular phases, targeting timeout dispatches ad:error
This branch was cut from feat/gpt-modernization-phase-0-2 before #4
merged to main, so it still carried the stale package-lock.json that
#4 deleted. Mirror that change here so the rebase onto main at merge
time is conflict-free, and so this branch is correctly published from
under pnpm only.

Adds package-lock.json and yarn.lock to .gitignore — block accidental
regeneration if someone runs `npm install` against the source tree.
Prerelease for cobertura360.mx staging verification. Combines PR #3
(GPT modernization — lifecycle events, SRA, collapseDiv, CLS reserve
fallback) and PR #5 (Phase 3a diagnostics — ad:error, Logger wiring,
debug toggle, openConsole, dataLayer bridge).

Publish with:
  pnpm publish --tag next --access public

Pinning consumers to @next isolates the RC from `latest` (still 0.6.4).
After staging verifies, the real 0.7.0 cut bumps from RC and promotes
to latest via a separate release commit on main.
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.

1 participant