Files
nexus/sreweekly/articles/517/06-the-code-nobody-read-is-already-in-production.html
2026-09-12 17:23:01 +08:00

193 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}
gtag("consent","default",{ad_storage:"denied",analytics_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",wait_for_update:500,region:["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB"]});
gtag("consent","default",{ad_storage:"granted",analytics_storage:"granted",ad_user_data:"granted",ad_personalization:"granted"});
window._hsp=window._hsp||[];
window._hsp.push(["addPrivacyConsentListener",function(consent){var cat=consent&&consent.categories;var analytics=!!(cat&&cat.analytics);var ads=!!(cat&&cat.advertisement);gtag("consent","update",{analytics_storage:analytics?"granted":"denied",ad_storage:ads?"granted":"denied",ad_user_data:ads?"granted":"denied",ad_personalization:ads?"granted":"denied"});}]);</script><script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer',"GTM-TX44QHS2");</script><script>window.disableHubSpotCookieBanner=true;</script><!-- If you POST via Forms API, disable HubSpot “Collect data from website forms” (Settings → Marketing → Forms → Non-HubSpot Forms) or you’ll get duplicate submissions from tracking. --><script type="text/javascript" id="hs-script-loader" async defer src="https://js-na2.hs-scripts.com/243729089.js"></script><title>AI Code is Shipping to Production Before Anyone Can Read It | Herald Blog</title><meta name="description" content="AI is flooding production with code no one fully reviewed. Ben Sigelman argues production must become the feedback loop for testing, quality, and reliability."><link rel="canonical" href="https://herald.dev/blog/the-code-nobody-read-is-already-in-production/"><!-- Open Graph --><meta property="og:type" content="website"><meta property="og:site_name" content="Herald"><meta property="og:title" content="AI Code is Shipping to Production Before Anyone Can Read It | Herald Blog"><meta property="og:description" content="AI is flooding production with code no one fully reviewed. Ben Sigelman argues production must become the feedback loop for testing, quality, and reliability."><meta property="og:url" content="https://herald.dev/blog/the-code-nobody-read-is-already-in-production/"><meta property="og:image" content="https://herald.dev/og-default.png"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><!-- Twitter / X --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="AI Code is Shipping to Production Before Anyone Can Read It | Herald Blog"><meta name="twitter:description" content="AI is flooding production with code no one fully reviewed. Ben Sigelman argues production must become the feedback loop for testing, quality, and reliability."><meta name="twitter:image" content="https://herald.dev/og-default.png"><link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png"><link rel="icon" href="/favicon.svg" type="image/svg+xml" sizes="any"><link rel="icon" href="/favicon.ico"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><link rel="manifest" href="/site.webmanifest"><meta name="theme-color" content="#F2F3F5" media="(prefers-color-scheme: light)"><meta name="theme-color" content="#0B0E1C" media="(prefers-color-scheme: dark)"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&#38;family=JetBrains+Mono:wght@400;500&#38;display=swap" rel="stylesheet"><link rel="stylesheet" href="/_astro/Footer.D35d5Zyb.css">
<style>.breadcrumb:where(.astro-mrlui5p2){display:flex;align-items:center;gap:var(--sp-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-tertiary);margin-bottom:var(--sp-5)}.breadcrumb:where(.astro-mrlui5p2) a:where(.astro-mrlui5p2){color:var(--text-tertiary);transition:color var(--duration-fast) var(--ease-default)}.breadcrumb:where(.astro-mrlui5p2) a:where(.astro-mrlui5p2):hover{color:var(--text-secondary)}.breadcrumb-sep:where(.astro-mrlui5p2){color:var(--border-default)}
</style>
<link rel="stylesheet" href="/_astro/_slug_@_@astro.yKHTB8D6.css">
<style>#hs_show_banner_button,#hs-hud-cookie-settings,#hs-cookie-settings-link,#hs-banner-parent{display:none!important}.consent-banner:where(.astro-2effgw6e){position:fixed;z-index:3000;bottom:var(--sp-6);right:var(--sp-6);width:min(100% - var(--sp-8),22rem);pointer-events:none;opacity:0;transform:translateY(var(--sp-4));transition:opacity var(--duration-mid) var(--ease-default),transform var(--duration-mid) var(--ease-default)}.consent-banner:where(.astro-2effgw6e)[data-visible=true]{pointer-events:auto;opacity:1;transform:translateY(0)}.consent-banner-panel:where(.astro-2effgw6e){background:var(--surface-overlay);border:1px solid var(--border-default);border-radius:var(--radius-md);box-shadow:0 2px 8px #00000014;padding:var(--sp-5);display:flex;flex-direction:column;gap:var(--sp-3)}.consent-banner-eyebrow:where(.astro-2effgw6e){font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--lh-xs);letter-spacing:.12em;text-transform:uppercase;color:var(--text-secondary)}.consent-banner-title:where(.astro-2effgw6e){font-size:var(--text-sm);line-height:var(--lh-sm);font-weight:600;color:var(--text-primary)}.consent-banner-desc:where(.astro-2effgw6e){font-size:var(--text-sm);line-height:var(--lh-sm);color:var(--text-secondary)}.consent-banner-inline-link:where(.astro-2effgw6e){color:inherit;text-decoration:underline;text-decoration-color:var(--border-default);text-underline-offset:2px;transition:color var(--duration-fast) var(--ease-default)}.consent-banner-inline-link:where(.astro-2effgw6e):hover{color:var(--text-primary)}.consent-banner-actions:where(.astro-2effgw6e){display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:var(--sp-1)}.consent-banner-btn:where(.astro-2effgw6e){flex:1 1 auto;justify-content:center;min-width:6.5rem}.consent-banner-btn:where(.astro-2effgw6e):focus-visible{outline:3px solid var(--brand-cta-ring);outline-offset:2px}@media(max-width:768px){.consent-banner:where(.astro-2effgw6e){bottom:0;right:0;left:0;width:auto;transform:translateY(100%)}.consent-banner:where(.astro-2effgw6e)[data-visible=true]{transform:translateY(0)}.consent-banner-panel:where(.astro-2effgw6e){border-radius:var(--radius-md) var(--radius-md) 0 0;border-bottom:none;padding:var(--sp-4) var(--sp-5) var(--sp-5)}.consent-banner-actions:where(.astro-2effgw6e){flex-direction:column}.consent-banner-btn:where(.astro-2effgw6e){width:100%}}
</style><script type="module" src="/_astro/page.CIKwc7qe.js"></script></head> <body> <noscript> <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TX44QHS2" height="0" width="0" style="display:none;visibility:hidden" title="Google Tag Manager"></iframe> </noscript> <header class="nav astro-dmqpwcec"> <div class="nav-inner container astro-dmqpwcec"> <a href="/" class="nav-logo astro-dmqpwcec" aria-label="Herald"> <picture class="astro-dmqpwcec"> <source srcset="/brand/Herald_Lockup_White.svg" media="(prefers-color-scheme: dark)" class="astro-dmqpwcec"> <img src="/brand/Herald_Lockup_Black.svg" alt="Herald" height="20" class="astro-dmqpwcec"> </picture> </a> <nav aria-label="Main navigation" class="astro-dmqpwcec"> <ul class="nav-links astro-dmqpwcec"> <li class="astro-dmqpwcec"> <a href="/product" class="nav-link astro-dmqpwcec">Product</a> </li><li class="astro-dmqpwcec"> <a href="/pricing" class="nav-link astro-dmqpwcec">Pricing</a> </li><li class="astro-dmqpwcec"> <a href="/about" class="nav-link astro-dmqpwcec">About</a> </li><li class="astro-dmqpwcec"> <a href="/platform" class="nav-link astro-dmqpwcec">Platform</a> </li><li class="astro-dmqpwcec"> <a href="/docs/" class="nav-link astro-dmqpwcec">Docs</a> </li> </ul> </nav> <div class="nav-ctas astro-dmqpwcec"> <a href="/contact" class="hero-text-link nav-secondary-cta astro-dmqpwcec" data-cta-location="nav_secondary"> Book a Demo </a> <a href="/try" class="btn btn-primary nav-cta astro-dmqpwcec" data-cta-location="nav"> Try for Free </a> </div> <button class="hamburger astro-dmqpwcec" aria-label="Toggle menu" aria-expanded="false" aria-controls="mobile-menu"> <span class="astro-dmqpwcec"></span> <span class="astro-dmqpwcec"></span> <span class="astro-dmqpwcec"></span> </button> </div> <div class="mobile-menu astro-dmqpwcec" id="mobile-menu" hidden> <ul class="mobile-links astro-dmqpwcec"> <li class="astro-dmqpwcec"> <a href="/product" class="mobile-link astro-dmqpwcec">Product</a> </li><li class="astro-dmqpwcec"> <a href="/pricing" class="mobile-link astro-dmqpwcec">Pricing</a> </li><li class="astro-dmqpwcec"> <a href="/about" class="mobile-link astro-dmqpwcec">About</a> </li><li class="astro-dmqpwcec"> <a href="/platform" class="mobile-link astro-dmqpwcec">Platform</a> </li><li class="astro-dmqpwcec"> <a href="/docs/" class="mobile-link astro-dmqpwcec">Docs</a> </li> </ul> <a href="/try" class="btn btn-primary mobile-cta astro-dmqpwcec" data-cta-location="nav_mobile"> Try for Free </a> <a href="/contact" class="hero-text-link mobile-secondary-cta astro-dmqpwcec" data-cta-location="nav_mobile_secondary"> Book a Demo </a> </div> </header> <script type="module">const e=document.querySelector(".hamburger"),i=document.getElementById("mobile-menu");e?.addEventListener("click",()=>{const t=e.getAttribute("aria-expanded")==="true";e.setAttribute("aria-expanded",String(!t)),e.classList.toggle("is-open",!t),t?i?.setAttribute("hidden",""):i?.removeAttribute("hidden")});</script> <main class="astro-4sn4zg3r"> <article class="astro-4sn4zg3r"> <!-- Post header --> <header class="post-header astro-4sn4zg3r"> <div class="post-header-inner container-narrow astro-4sn4zg3r"> <nav class="breadcrumb astro-mrlui5p2" aria-label="Breadcrumb"> <a href="/blog" class="astro-mrlui5p2">Blog</a> </nav> <h1 class="post-title astro-4sn4zg3r">The Code Nobody Read Is Already in Production</h1> <p class="post-excerpt astro-4sn4zg3r">Ben Sigelman argues that AI-generated code is a reliability crisis in slow motion, and what it means for how we observe production systems.</p> <div class="post-meta astro-4sn4zg3r"> <div class="meta-line meta-line--authors astro-4sn4zg3r"> <span class="meta-author astro-4sn4zg3r"> <img src="https://cdn.sanity.io/images/b3uvbvvc/production/9bcd3886060c22273870f55ed0342c5e6ac92fd2-700x467.jpg?rect=117,0,467,467&#38;w=56&#38;h=56&#38;fit=crop" alt="Peter Farago" class="author-avatar astro-4sn4zg3r" loading="lazy"> <span class="meta-author-text astro-4sn4zg3r"> <span class="author-name astro-4sn4zg3r">Peter Farago</span> <span class="meta-sep astro-4sn4zg3r">·</span> <span class="author-role astro-4sn4zg3r">VP Marketing</span> </span> </span> </div> <div class="meta-line astro-4sn4zg3r"> <time datetime="2026-04-29T03:03:00.000Z" class="meta-date astro-4sn4zg3r"> April 29, 2026 </time> </div> </div> </div> </header> <!-- Main image --> <div class="post-hero-shell astro-4sn4zg3r"> <div class="post-hero-image astro-4sn4zg3r"> <img src="https://cdn.sanity.io/images/b3uvbvvc/production/d5014761ae9c26c2a4eaad062e0a7da21594a7b4-1754x1012.png?rect=0,46,1754,921&#38;w=1200&#38;h=630&#38;fit=crop" alt="Ben Sigel playing cello with code and past experiences flowing out from the instrument" loading="eager" class="astro-4sn4zg3r"> </div> </div> <!-- Series banner --> <!-- Body --> <div class="post-body container-narrow astro-4sn4zg3r"> <div class="prose astro-4sn4zg3r"><p>AI is generating code faster than anyone can review it, and most of it is already in production.</p><p><a href="https://www.linkedin.com/in/bensigelman/" target="_blank" rel="noopener noreferrer">Ben Sigelman</a> has been building and studying production systems for over 20 years: at Google, where he co-created the Dapper tracing and Monarch monitoring systems, as co-founder and CEO of Lightstep, and as co-creator of OpenTelemetry. He predicts that because AI tools continue to make it cheaper to write (and rewrite) code on demand, production environments will become the primary place to evaluate whether software is correct or incorrect. To many people, that might sound insane. To Ben, it&#x27;s already inevitable.</p><p>Ben argues that the natural consequence of this change is that the observability stack needs to continuously feed signals from production back into the process of writing, shipping, and rewriting code.</p><p><strong>A Crisis Already Here</strong></p><p>Software development is accelerating in a way that has decoupled velocity from review. Code generated by AI tools ships to production without the kind of detailed human scrutiny that production code used to require. This must be the case for productivity gains to be real; otherwise, the bottleneck would simply move from reading to review.</p><blockquote>The amount of code that is running in production – that was never really properly reviewed by anybody – is going up so fast. There&#x27;s always a reliability-velocity tradeoff, and I think people are seeing the velocity and saying, ‘I don&#x27;t really care that much about the reliability. I just can&#x27;t resist the siren song of pushing features as fast.’ That to me feels like a full-on crisis for software.</blockquote><p>The crisis is the loss of context that makes debugging possible in the first place. Back in the old days (2022), when a person wrote code, they understood its structure. When something broke, the understanding of what it was <em>supposed </em>to do and why it was implemented that way existed in someone’s head. With AI-generated code, the reasoning lives in the weights of a model that neither the engineer who shipped it nor the engineer investigating the incident can interrogate. The <em>why</em> behind a given design decision is often absent.</p><p>The only place left to understand how it will <em>actually</em> behave is in prod. As Ben puts it, you need to go into production to understand how the software should be written. Production stops being the place where software goes after it&#x27;s been validated – it becomes the place where true validation actually happens.</p><p><strong>Production as a Necessary Test Environment</strong></p><p>Pre-production testing still matters. Ben expects it to become more rigorous, not less, as teams try to compensate for the loss of careful human review, and as LLMs make it easier to achieve high test coverage numbers. Still, there is a limit to what any pre-production environment can tell you.</p><blockquote>&quot;You absolutely cannot know if software is viable until it&#x27;s also been tested in production. We need the production workload to fully qualify things, and we can never simulate that.&quot;</blockquote><p>The reason is straightforward. Staging environments test what you anticipate. Production reveals what you didn&#x27;t: not just in the sense of individual requests or transactions, but in the sense of the overall workload, including caching consequences and interference effects. The gap between the staging and prod has always existed, but now the velocity of AI-generated code is making that gap wider and harder to measure.</p><p>What changes is what happens next. Rewriting used to be expensive enough to justify exhaustive upfront validation. Now it isn&#x27;t. As Ben explains, given how easy it is to revert and try again, it&#x27;s only natural that more candidate releases will get as far as production traffic before one gets selected for mainline merging.</p><blockquote>&quot;Within two years, I would be surprised if we don&#x27;t have multiple copies of the same software written in different ways, running concurrently for a lot of production applications. The idea that code can be evaluated as correct or incorrect without the workload is academically ridiculous. It needs to be in production to evaluate it.&quot;</blockquote><p><strong>What This Demands from Reliability</strong></p><p>As production becomes the environment where software gets evaluated, the role of reliability changes. The on-call model — wait for an alert, investigate, resolve — was designed for a world where code was reviewed before it shipped and failures were exceptions. Waiting for something to break is too late.</p><p>In Ben&#x27;s framing, the feedback loop from production back into the development cycle is essential to navigating the velocity-reliability tradeoff. Not a manual loop, an automated one. Ship fast, watch what happens, feed that signal back into the next version.</p><p>That loop runs continuously, not just when an incident fires. It requires something that understands what&#x27;s running, what changed, and what the behavior means across reliability signals and business metrics before anyone gets paged.</p><p>The system this era requires continuously models your production environment, detects deviation before thresholds are crossed, and investigates without waiting to be told what to look for. The on-call engineer stops being the first line of defense and becomes the decision-maker at the end of an investigation that has already happened. That is a different job. It requires different tooling.</p><p>The teams that recognize this shift will have a significant advantage.</p><blockquote>&quot;The insights are already there,&quot; Ben says. &quot;It&#x27;s just a matter of developing trust and repeatability with people.&quot;</blockquote><p></p><p><em>Ben Sigelman co-created the Dapper distributed tracing system and Monarch monitoring system at Google, co-founded Lightstep (acquired by ServiceNow in 2021), and co-created OpenTracing and OpenTelemetry.</em></p></div> </div> <!-- Author bio --> <footer class="post-footer container-narrow astro-4sn4zg3r"> <div class="author-bios astro-4sn4zg3r"> <div class="author-bio-card astro-4sn4zg3r"> <img src="https://cdn.sanity.io/images/b3uvbvvc/production/9bcd3886060c22273870f55ed0342c5e6ac92fd2-700x467.jpg?rect=117,0,467,467&#38;w=80&#38;h=80&#38;fit=crop" alt="Peter Farago" class="bio-avatar astro-4sn4zg3r"> <div class="bio-content astro-4sn4zg3r"> <div class="bio-header astro-4sn4zg3r"> <span class="bio-name astro-4sn4zg3r">Peter Farago</span> <span class="bio-role astro-4sn4zg3r">VP Marketing</span> <div class="bio-links astro-4sn4zg3r"> <a href="https://x.com/peter_farago" target="_blank" rel="noopener noreferrer" class="bio-link astro-4sn4zg3r">
X / Twitter
</a> <a href="https://www.linkedin.com/in/peterfarago/" target="_blank" rel="noopener noreferrer" class="bio-link astro-4sn4zg3r">
LinkedIn
</a> </div> </div> <p class="bio-text astro-4sn4zg3r">Peter has led marketing for several Silicon Valley startups. He co-founded Flurry Analytics, acquired by Yahoo, was CMO for Acompli, acquired by Microsoft. He was founding VP Marketing at HackerOne, led marketing for a global franchise at Electronic Arts and was VP of Growth &amp; Monetization for Yahoo. Peter earned an MBA from the Wharton School and a B.S. from UC Berkeley.</p> </div> </div> </div> <div class="back-link astro-4sn4zg3r"> <a href="/blog" class="astro-4sn4zg3r">← All posts</a> </div> </footer> </article> </main> <footer class="footer astro-sz7xmlte"> <div class="footer-main container astro-sz7xmlte"> <div class="footer-brand astro-sz7xmlte"> <a href="/" aria-label="Herald" class="astro-sz7xmlte"> <picture class="astro-sz7xmlte"> <source srcset="/brand/Herald_Lockup_White.svg" media="(prefers-color-scheme: dark)" class="astro-sz7xmlte"> <img src="/brand/Herald_Lockup_Black.svg" alt="Herald" height="24" class="astro-sz7xmlte"> </picture> </a> <p class="footer-tagline astro-sz7xmlte">Toil Less. Build More. Love Work.</p> <p class="footer-copy astro-sz7xmlte">© 2026 RunLLM, Inc. All rights reserved.</p> </div> <div class="footer-cols astro-sz7xmlte"> <div class="footer-col astro-sz7xmlte"> <span class="footer-col-label astro-sz7xmlte">Company</span> <ul class="astro-sz7xmlte"> <li class="astro-sz7xmlte"><a href="/product" class="footer-link astro-sz7xmlte">Product</a></li><li class="astro-sz7xmlte"><a href="/pricing" class="footer-link astro-sz7xmlte">Pricing</a></li><li class="astro-sz7xmlte"><a href="/about" class="footer-link astro-sz7xmlte">About</a></li><li class="astro-sz7xmlte"><a href="/platform" class="footer-link astro-sz7xmlte">Platform</a></li><li class="astro-sz7xmlte"><a href="/docs/" class="footer-link astro-sz7xmlte">Docs</a></li> <li class="astro-sz7xmlte"> <a href="https://trust.herald.dev" class="footer-link astro-sz7xmlte" target="_blank" rel="noopener noreferrer">
Trust
</a> </li> <li class="astro-sz7xmlte"><a href="/blog" class="footer-link astro-sz7xmlte">Blog</a></li> </ul> </div> <div class="footer-col astro-sz7xmlte"> <span class="footer-col-label astro-sz7xmlte">Contact</span> <ul class="astro-sz7xmlte"> <li class="astro-sz7xmlte"> <a href="mailto:sales@herald.dev" class="footer-link astro-sz7xmlte">sales@herald.dev</a> </li> <li class="astro-sz7xmlte"> <a href="https://app.herald.dev" class="footer-link footer-link-cta astro-sz7xmlte" target="_blank" rel="noopener noreferrer"> Try it now →
</a> </li> <li class="astro-sz7xmlte"> <a href="/contact" class="footer-link footer-link-cta astro-sz7xmlte" data-cta-location="footer"> Book a Demo →
</a> </li> </ul> </div> <div class="footer-col astro-sz7xmlte"> <span class="footer-col-label astro-sz7xmlte">Legal</span> <ul class="astro-sz7xmlte"> <li class="astro-sz7xmlte"><a href="/legal/privacy" class="footer-link astro-sz7xmlte">Privacy Policy</a></li> <li class="astro-sz7xmlte"><a href="/legal/terms" class="footer-link astro-sz7xmlte">Terms of Service</a></li> <li class="astro-sz7xmlte"> <button type="button" class="footer-link footer-consent-link astro-sz7xmlte" data-open-consent>
Cookie preferences
</button> </li> </ul> </div> </div> </div> </footer> <div id="herald-consent-banner" class="consent-banner astro-2effgw6e" role="dialog" aria-modal="true" aria-labelledby="consent-banner-title" aria-describedby="consent-banner-desc" aria-hidden="true" inert data-visible="false"> <div class="consent-banner-panel astro-2effgw6e"> <p class="consent-banner-eyebrow astro-2effgw6e">Privacy</p> <p id="consent-banner-title" class="consent-banner-title astro-2effgw6e">Cookie preferences</p> <p id="consent-banner-desc" class="consent-banner-desc astro-2effgw6e"> Herald uses cookies for analytics and marketing. You can accept or decline non-essential
cookies. See our <a href="/legal/privacy" class="consent-banner-inline-link astro-2effgw6e">Privacy Policy</a> for
details.
</p> <div class="consent-banner-actions astro-2effgw6e"> <button type="button" class="btn btn-primary consent-banner-btn astro-2effgw6e" data-consent-action="accept">
Accept
</button> <button type="button" class="btn btn-ghost consent-banner-btn astro-2effgw6e" data-consent-action="decline">
Decline
</button> </div> </div> </div> <script>(function(){
var STORAGE_KEY="herald-consent-v1";
var HUBSPOT_COOKIE_UI_SELECTORS=["#hs_show_banner_button","#hs-hud-cookie-settings","#hs-cookie-settings-link","#hs-banner-parent"];
function removeHubSpotCookieUi() {
HUBSPOT_COOKIE_UI_SELECTORS.forEach(function(sel) {
document.querySelectorAll(sel).forEach(function(el) {
el.remove();
});
});
}
function watchHubSpotCookieUi() {
removeHubSpotCookieUi();
if (!window.MutationObserver || !document.body) return;
var observer = new MutationObserver(removeHubSpotCookieUi);
observer.observe(document.body, { childList: true, subtree: true });
}
function updateGoogleConsent(analytics, advertisement) {
if (typeof gtag !== 'function') return;
var state = function(v) { return v ? 'granted' : 'denied'; };
gtag('consent', 'update', {
analytics_storage: state(analytics),
ad_storage: state(advertisement),
ad_user_data: state(advertisement),
ad_personalization: state(advertisement),
});
}
function updateHubSpotConsent(analytics, advertisement) {
window._hsp = window._hsp || [];
window._hsp.push(['setHubSpotConsent', {
analytics: !!analytics,
advertisement: !!advertisement,
functionality: true,
}]);
}
window.applySiteConsent = function(choices) {
var analytics = !!choices.analytics;
var advertisement = !!choices.advertisement;
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
analytics: analytics,
advertisement: advertisement,
ts: Date.now(),
}));
} catch (e) {}
updateGoogleConsent(analytics, advertisement);
updateHubSpotConsent(analytics, advertisement);
document.dispatchEvent(new CustomEvent('herald:consent-update', {
detail: { analytics: analytics, advertisement: advertisement },
}));
};
window.openSiteConsentBanner = function() {
var banner = document.getElementById('herald-consent-banner');
if (!banner) return;
banner.removeAttribute('inert');
banner.setAttribute('aria-hidden', 'false');
banner.dataset.visible = 'true';
var acceptBtn = banner.querySelector('[data-consent-action="accept"]');
if (acceptBtn && typeof acceptBtn.focus === 'function') acceptBtn.focus();
};
window.closeSiteConsentBanner = function() {
var banner = document.getElementById('herald-consent-banner');
if (!banner) return;
banner.dataset.visible = 'false';
banner.setAttribute('aria-hidden', 'true');
banner.setAttribute('inert', '');
};
function readStoredConsent() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
var parsed = JSON.parse(raw);
if (typeof parsed.analytics !== 'boolean') return null;
if (typeof parsed.advertisement !== 'boolean') return null;
return parsed;
} catch (e) {
return null;
}
}
function initConsent() {
var stored = readStoredConsent();
if (stored) {
window.applySiteConsent(stored);
return;
}
window.openSiteConsentBanner();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
watchHubSpotCookieUi();
initConsent();
});
} else {
watchHubSpotCookieUi();
initConsent();
}
document.addEventListener('click', function(e) {
var trigger = e.target && e.target.closest ? e.target.closest('[data-open-consent]') : null;
if (!trigger) return;
e.preventDefault();
window.openSiteConsentBanner();
});
})();</script> <script>
(function () {
var banner = document.getElementById('herald-consent-banner');
if (!banner) return;
banner.addEventListener('click', function (e) {
var btn = e.target && e.target.closest ? e.target.closest('[data-consent-action]') : null;
if (!btn) return;
var action = btn.getAttribute('data-consent-action');
if (action === 'accept') {
window.applySiteConsent({ analytics: true, advertisement: true });
} else if (action === 'decline') {
window.applySiteConsent({ analytics: false, advertisement: false });
} else {
return;
}
window.closeSiteConsentBanner();
});
})();
</script> <script>(function(){
window.dataLayer=window.dataLayer||[];
window.pushSiteAnalyticsEvent=window.pushSiteAnalyticsEvent||function(eventName,params){
window.dataLayer.push(Object.assign({event:eventName},params||{}));
};
document.addEventListener('click',function(e){
var link=e.target&&e.target.closest?e.target.closest('a[href^="mailto:"]'):null;
if(!link)return;
var href=(link.getAttribute('href')||'').replace(/^mailto:/i,'').split(/[?#]/)[0].trim().toLowerCase();
if(href!=="sales@herald.dev")return;
window.pushSiteAnalyticsEvent("sales_email_click",{
link_text:(link.textContent||'').trim(),
link_href:link.getAttribute('href')||'',
page_location:window.location.href,
page_path:window.location.pathname
});
},true);
document.addEventListener('click',function(e){
var link=e.target&&e.target.closest?e.target.closest('a[data-cta-location]'):null;
if(!link)return;
var ctaLocation=link.getAttribute('data-cta-location');
if(!ctaLocation)return;
var params={
cta_text:(link.textContent||'').replace(/\s+/g,' ').trim(),
cta_location:ctaLocation,
cta_destination:link.getAttribute('href')||'',
page_location:window.location.href,
page_path:window.location.pathname
};
var pricingTier=link.getAttribute('data-pricing-tier');
if(pricingTier)params.pricing_tier=pricingTier;
window.pushSiteAnalyticsEvent("cta_click",params);
},true);
})();</script></body></html>