Created
June 30, 2026 21:32
-
-
Save twinge/bb4dd79bcad542ff4cca1a58d624f2b5 to your computer and use it in GitHub Desktop.
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
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>AI Auditability & Control: Design Brief</title> | |
| <style> | |
| :root{ | |
| color-scheme: light; | |
| --bg:#f4f5f8; | |
| --slide:#ffffff; | |
| --ink:#16202c; | |
| --muted:#5a6675; | |
| --line:#dfe3ea; | |
| --accent:#3b5bdb; | |
| --accent-soft:#eaeefb; | |
| --accent2:#0c8599; | |
| --accent2-soft:#e3f4f6; | |
| --good:#2b8a3e; | |
| --good-soft:#e8f6ec; | |
| --warn:#b08900; | |
| --warn-soft:#fbf3da; | |
| --bad:#c92a2a; | |
| --bad-soft:#fbe9e9; | |
| --chip:#eef1f6; | |
| --radius:14px; | |
| --maxw:1040px; | |
| --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; | |
| --mono:"SF Mono",ui-monospace,"Cascadia Code",Menlo,Consolas,monospace; | |
| } | |
| *{box-sizing:border-box;margin:0;padding:0} | |
| html,body{background:var(--bg);color:var(--ink);font-family:var(--font);-webkit-font-smoothing:antialiased} | |
| body{display:flex;flex-direction:column;align-items:center;min-height:100vh;padding:18px 14px 86px} | |
| .deck{width:100%;max-width:var(--maxw)} | |
| .slide{ | |
| display:none;background:var(--slide);border:1px solid var(--line); | |
| border-radius:var(--radius);padding:40px 46px;min-height:600px; | |
| box-shadow:0 1px 3px rgba(20,32,44,.05),0 12px 32px rgba(20,32,44,.06); | |
| animation:fade .25s ease; | |
| } | |
| .slide.active{display:block} | |
| @keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}} | |
| .kicker{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);font-weight:700;margin-bottom:14px} | |
| h1{font-size:37px;line-height:1.12;letter-spacing:-.02em;margin-bottom:16px} | |
| h2{font-size:27px;line-height:1.18;letter-spacing:-.01em;margin-bottom:18px} | |
| h3{font-size:15px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin:18px 0 8px} | |
| p{font-size:16.5px;line-height:1.55;color:var(--ink);margin-bottom:12px} | |
| p.lead{font-size:18.5px;color:var(--ink)} | |
| .sub{color:var(--muted)} | |
| .muted{color:var(--muted)} | |
| ul{list-style:none} | |
| li{font-size:16px;line-height:1.5;margin-bottom:11px;padding-left:24px;position:relative} | |
| li::before{content:"";position:absolute;left:4px;top:9px;width:7px;height:7px;border-radius:2px;background:var(--accent)} | |
| li.good::before{background:var(--good)} | |
| li.bad::before{background:var(--bad)} | |
| li.warn::before{background:var(--warn)} | |
| li.no{padding-left:24px} | |
| li.no::before{content:"✕";background:none;width:auto;height:auto;left:3px;top:1px;color:var(--muted);font-size:13px;font-weight:700} | |
| li.yes::before{content:"✓";background:none;width:auto;height:auto;left:2px;top:1px;color:var(--good);font-size:14px;font-weight:700} | |
| strong{font-weight:670} | |
| .tag{display:inline-block;font-size:12px;font-weight:600;padding:3px 10px;border-radius:999px;background:var(--chip);color:var(--muted);margin-right:6px} | |
| .tag.a{background:var(--accent-soft);color:var(--accent)} | |
| .tag.b{background:var(--accent2-soft);color:var(--accent2)} | |
| .tag.pick{background:var(--good-soft);color:var(--good)} | |
| .two{display:grid;grid-template-columns:1fr 1fr;gap:26px;margin-top:6px} | |
| .three{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:6px} | |
| .card{border:1px solid var(--line);border-radius:11px;padding:16px 18px;background:#fcfcfe} | |
| .card.accent{border-color:#c7d2f7;background:var(--accent-soft)} | |
| .card.a{border-left:4px solid var(--accent)} | |
| .card.b{border-left:4px solid var(--accent2)} | |
| .card.pick{border-left:4px solid var(--good);background:var(--good-soft)} | |
| .card h4{font-size:16px;margin-bottom:8px} | |
| .card p,.card li{font-size:14.5px} | |
| .card li{margin-bottom:7px} | |
| table{width:100%;border-collapse:collapse;margin-top:8px;font-size:14.5px} | |
| th,td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:top} | |
| th{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700} | |
| thead th:nth-child(2){color:var(--accent)} | |
| thead th:nth-child(3){color:var(--accent2)} | |
| td:first-child{font-weight:600;width:30%} | |
| .pill{display:inline-block;font-size:12px;font-weight:600;padding:2px 9px;border-radius:6px} | |
| .pill.g{background:var(--good-soft);color:var(--good)} | |
| .pill.w{background:var(--warn-soft);color:var(--warn)} | |
| .pill.r{background:var(--bad-soft);color:var(--bad)} | |
| .pill.n{background:var(--chip);color:var(--muted)} | |
| pre{background:#0f1722;color:#e6edf3;border-radius:11px;padding:18px 20px;font-family:var(--mono); | |
| font-size:13.5px;line-height:1.55;overflow:auto;margin-top:6px} | |
| pre .c{color:#7d8aa0} | |
| pre .k{color:#79c0ff} | |
| pre .s{color:#a5d6ff} | |
| .flow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:14px 0} | |
| .node{border:1.5px solid var(--line);border-radius:10px;padding:11px 14px;font-size:13.5px;font-weight:600;background:#fff;text-align:center;line-height:1.3} | |
| .node.app{border-color:#c7d2f7;background:var(--accent-soft)} | |
| .node.gw{border-color:#9bd4dd;background:var(--accent2-soft)} | |
| .node.store{border-color:#cdd4df;background:#f4f6fa} | |
| .node.pick{border-color:#a3d9b1;background:var(--good-soft)} | |
| .node small{display:block;font-weight:500;color:var(--muted);font-size:11.5px;margin-top:2px} | |
| .arrow{color:var(--muted);font-size:20px;font-weight:700} | |
| .arrow small{display:block;font-size:10.5px;font-weight:600;color:var(--muted);text-align:center;margin-top:-2px} | |
| .schema{display:grid;grid-template-columns:1fr 1fr;gap:6px 26px;margin-top:8px} | |
| .field{display:flex;gap:10px;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--line);font-size:14px} | |
| .field code{font-family:var(--mono);font-size:13px;color:var(--accent);font-weight:600;white-space:nowrap} | |
| .field span{color:var(--muted);font-size:13px} | |
| .phase{display:flex;gap:14px;margin-bottom:13px} | |
| .phase .n{flex:none;width:30px;height:30px;border-radius:8px;background:var(--accent);color:#fff;font-weight:700;display:flex;align-items:center;justify-content:center;font-size:14px} | |
| .phase .n.alt{background:var(--accent2)} | |
| .phase .n.opt{background:#9aa4b2} | |
| .phase h4{font-size:16px;margin-bottom:3px} | |
| .phase p{font-size:14.5px;margin-bottom:0} | |
| .titlewrap{display:flex;flex-direction:column;justify-content:center;min-height:560px} | |
| .audience{display:flex;gap:8px;flex-wrap:wrap;margin-top:22px} | |
| .aud{font-size:13px;font-weight:600;color:var(--ink);background:var(--chip);padding:6px 13px;border-radius:8px} | |
| .foot{margin-top:24px;font-size:13px;color:var(--muted);border-top:1px solid var(--line);padding-top:14px} | |
| .callout{background:var(--accent-soft);border:1px solid #c7d2f7;border-radius:11px;padding:16px 18px;margin-top:14px} | |
| .callout.pick{background:var(--good-soft);border-color:#a3d9b1} | |
| .callout p{margin-bottom:0;font-size:15.5px} | |
| .big{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:10px} | |
| .stat{border:1px solid var(--line);border-radius:11px;padding:16px;background:#fcfcfe} | |
| .stat h4{font-size:15px;margin-bottom:5px;color:var(--accent)} | |
| .stat p{font-size:13.5px;margin-bottom:0;color:var(--muted)} | |
| .nav{position:fixed;bottom:0;left:0;right:0;background:rgba(255,255,255,.94);backdrop-filter:blur(8px); | |
| border-top:1px solid var(--line);display:flex;align-items:center;justify-content:center;gap:16px;padding:11px;z-index:10} | |
| .nav button{font:inherit;font-size:14px;font-weight:600;border:1px solid var(--line);background:#fff;color:var(--ink); | |
| padding:7px 16px;border-radius:9px;cursor:pointer} | |
| .nav button:hover{border-color:var(--accent);color:var(--accent)} | |
| .nav button:disabled{opacity:.4;cursor:default} | |
| .counter{font-size:13.5px;color:var(--muted);font-variant-numeric:tabular-nums;min-width:54px;text-align:center} | |
| .progress{position:fixed;top:0;left:0;height:3px;background:var(--accent);z-index:11;transition:width .25s} | |
| @media(max-width:720px){.two,.three,.big,.schema{grid-template-columns:1fr}.slide{padding:28px 22px}h1{font-size:29px}} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="progress" id="progress"></div> | |
| <div class="deck" id="deck"> | |
| <!-- 1 TITLE --> | |
| <section class="slide active"> | |
| <div class="titlewrap"> | |
| <div class="kicker">AI Compliance Framework · Design Brief</div> | |
| <h1>Auditability for every AI feature,<br>with control where it counts</h1> | |
| <p class="lead sub">A low-friction <strong>SDK</strong> that gives every internally-built AI feature a complete audit trail,<br>and a high-control <strong>gateway</strong> alongside it for the use cases that need enforcement.<br>Both, sequenced in phases.</p> | |
| <div class="audience"> | |
| <span class="aud">Architects</span> | |
| <span class="aud">Application developers</span> | |
| <span class="aud">Data privacy</span> | |
| <span class="aud">Legal / counsel</span> | |
| </div> | |
| <div class="foot">Scope: AI features <em>we build</em>. Purchased AI tools are a separate ingestion problem, out of scope here.</div> | |
| </div> | |
| </section> | |
| <!-- 2 OUTCOME --> | |
| <section class="slide"> | |
| <div class="kicker">The outcome we're solving for</div> | |
| <h2>Every internally-developed AI feature should send audit-grade records to one central, immutable place.</h2> | |
| <div class="two"> | |
| <div class="card"> | |
| <h4>Where we are today</h4> | |
| <ul> | |
| <li>Each tool calls model providers (OpenAI, Anthropic, internal models) directly, with no shared path.</li> | |
| <li>Logging, where it exists, is per-team, inconsistent, and not built as evidence.</li> | |
| <li>No way to answer "show me everything this model did" with confidence.</li> | |
| </ul> | |
| </div> | |
| <div class="card accent"> | |
| <h4>Where we need to be</h4> | |
| <ul> | |
| <li>A <strong>complete</strong> record of what every AI feature did: inputs, outputs, model, actor, decisions.</li> | |
| <li><strong>Immutable</strong> and tamper-evident, retained to a defined legal schedule.</li> | |
| <li>And for some features, the ability to <strong>actively control</strong> what the model does, not just record it.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>Two distinct needs sit inside that goal: <strong>auditability</strong> (know what happened) and <strong>control</strong> (govern what's allowed). They call for two different tools.</p></div> | |
| </section> | |
| <!-- 3 AUDIT VS OBSERVABILITY --> | |
| <section class="slide"> | |
| <div class="kicker">Quick framing for the room</div> | |
| <h2>Audit evidence is not the same as observability</h2> | |
| <div class="two"> | |
| <div class="card b"> | |
| <h4>Observability</h4> | |
| <p class="muted" style="font-size:13.5px;margin-bottom:10px">Metrics, traces, logs (OpenTelemetry / APM)</p> | |
| <ul> | |
| <li>Latency, tokens, cost, error rates.</li> | |
| <li><strong>Sampled, lossy, short retention.</strong></li> | |
| <li>For engineers debugging.</li> | |
| </ul> | |
| </div> | |
| <div class="card a"> | |
| <h4>Audit evidence</h4> | |
| <p class="muted" style="font-size:13.5px;margin-bottom:10px">The system of record for compliance</p> | |
| <ul> | |
| <li>Inputs, outputs, model+version, actor, decisions.</li> | |
| <li><strong>Complete, immutable, tamper-evident.</strong></li> | |
| <li>For auditors & regulators.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>The SDK borrows proven observability <em>plumbing</em> but produces audit-grade evidence: <strong>complete and unsampled</strong>, not best-effort telemetry.</p></div> | |
| </section> | |
| <!-- 4 TWO NEEDS TWO TOOLS --> | |
| <section class="slide"> | |
| <div class="kicker">The approach</div> | |
| <h2>Two needs → two tools, and we're building both</h2> | |
| <div class="two" style="margin-top:8px"> | |
| <div class="card pick"> | |
| <span class="tag pick">Start here</span> | |
| <h4 style="margin-top:10px">The SDK: auditability, low friction</h4> | |
| <p>Know exactly what every AI feature sent and received, in one immutable store. A few lines per feature, no latency, nothing new to operate.</p> | |
| <p class="muted" style="font-size:13.5px;margin-bottom:0">Broad coverage, fast.</p> | |
| </div> | |
| <div class="card b"> | |
| <span class="tag b">Building alongside</span> | |
| <h4 style="margin-top:10px">The gateway: control & enforcement</h4> | |
| <p>Govern which models may be used, block dangerous prompts/responses in-line, and capture with the strongest guarantee. For the use cases that need it.</p> | |
| <p class="muted" style="font-size:13.5px;margin-bottom:0">Selective, high-assurance.</p> | |
| </div> | |
| </div> | |
| <div class="callout"><p><strong>Both/and, not either/or.</strong> The SDK gives every feature auditability quickly; the gateway adds active control where the use case demands it. Both emit the same record to the same store.</p></div> | |
| </section> | |
| <!-- 5 SDK WHAT IS --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK</span> | |
| <h2 style="margin-top:10px">The low-friction path to auditability</h2> | |
| <p>A thin client your application embeds. It captures each model call automatically and ships an audit event out-of-band. Your app keeps calling the provider directly. The SDK <strong>logs the call, it doesn't proxy it.</strong></p> | |
| <div class="flow"> | |
| <div class="node app">AI Feature<small>+ SDK</small></div> | |
| <span class="arrow">→</span> | |
| <div class="node">Model providers<small>direct, no latency</small></div> | |
| </div> | |
| <div class="flow"> | |
| <div class="node app" style="visibility:hidden">AI Feature</div> | |
| <span class="arrow">↘</span> | |
| <div class="node store">Central audit pipeline<small>agent → logger → immutable store</small></div> | |
| </div> | |
| <div class="callout pick"><p>Designed so adoption is <strong>a dependency and a few lines</strong>, not a migration and not new infrastructure for your team to run.</p></div> | |
| </section> | |
| <!-- 6 SDK VALUE --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK · value</span> | |
| <h2 style="margin-top:10px">What you get</h2> | |
| <div class="two"> | |
| <div class="card"> | |
| <ul> | |
| <li class="good"><strong>Complete, central audit record</strong>: every prompt, response, model, actor, and outcome in one immutable place.</li> | |
| <li class="good"><strong>Zero added latency</strong>: capture is asynchronous; your model call is untouched.</li> | |
| <li class="good"><strong>Nothing new to operate</strong>: a shared agent and logging service handle delivery, parsing, and redaction. Not your team's problem.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <ul> | |
| <li class="good"><strong>No provider treadmill</strong>: calls are captured opaquely, so new model features never wait on the SDK.</li> | |
| <li class="good"><strong>Business context included</strong>: you attach the feature, actor, and outcome the raw wire can't show.</li> | |
| <li class="good"><strong>Audit-grade, not sampled</strong>: 100% of calls captured, built to satisfy legal, not just dashboards.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>Net: every AI feature becomes <strong>auditable in days</strong>, with no latency cost and no operational burden on the building team.</p></div> | |
| </section> | |
| <!-- 7 SDK HOW --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK · how it works</span> | |
| <h2 style="margin-top:10px">Capture at the call site, ship out-of-band</h2> | |
| <div class="flow"> | |
| <div class="node app">App + SDK<small>captures the call</small></div> | |
| <span class="arrow">→<small>direct</small></span> | |
| <div class="node">Providers</div> | |
| </div> | |
| <div class="flow"> | |
| <div class="node app" style="visibility:hidden">App + SDK</div> | |
| <span class="arrow">↘<small>async</small></span> | |
| <div class="node pick">Co-located agent</div> | |
| <span class="arrow">→</span> | |
| <div class="node gw">HA logging service<small>parse + redact</small></div> | |
| <span class="arrow">→</span> | |
| <div class="node store">Immutable store</div> | |
| </div> | |
| <ul style="margin-top:6px"> | |
| <li>The model call goes <strong>straight to the provider</strong>, with no proxy hop and no latency.</li> | |
| <li>The SDK hands the event to a co-located agent and moves on. It is <strong>non-blocking</strong> and never breaks the feature.</li> | |
| <li>The agent and logging service own <strong>delivery, parsing, and redaction</strong>. The app does none of it.</li> | |
| <li>Capture is <strong>100%</strong>, with no sampling.</li> | |
| </ul> | |
| </section> | |
| <!-- 8 DEVELOPER ADOPTION --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK · what you actually do</span> | |
| <h2 style="margin-top:10px">Adoption, from a developer's seat</h2> | |
| <div class="two"> | |
| <div class="card pick"> | |
| <h4>You do, once per feature</h4> | |
| <ul> | |
| <li class="yes">Add the SDK dependency.</li> | |
| <li class="yes">Wrap your model calls (a few lines), or enable auto-instrumentation for supported clients.</li> | |
| <li class="yes">Pass a little context: feature ID, actor, outcome.</li> | |
| <li class="yes">Register the feature and get your provider key through central issuance.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <h4>You don't have to, ever</h4> | |
| <ul> | |
| <li class="no">Run or operate any logging infrastructure.</li> | |
| <li class="no">Write redaction or PII-handling logic; it's server-side.</li> | |
| <li class="no">Budget for latency or tune performance.</li> | |
| <li class="no">Track provider API changes or parameters.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout pick"><p>Total lift: <strong>a dependency, a wrapper, and a registry entry.</strong> Most features onboard in an afternoon.</p></div> | |
| </section> | |
| <!-- 9 API SKETCH --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK · API sketch</span> | |
| <h2 style="margin-top:10px">What the code looks like</h2> | |
| <pre><span class="c"># Wrap the model call. The SDK captures it opaquely, with no need to model the params.</span> | |
| response = ai_audit.capture( | |
| provider.chat, <span class="c"># the real call, passed through untouched</span> | |
| request, <span class="c"># captured as-is; redacted server-side</span> | |
| feature=<span class="s">"support_summarizer"</span>, | |
| actor=current_user.id, | |
| context={<span class="s">"ticket_id"</span>: 123, <span class="s">"channel"</span>: <span class="s">"email"</span>}, | |
| outcome=<span class="s">"draft_suggested"</span>, <span class="c"># business meaning, known only to the app</span> | |
| ) | |
| <span class="c"># provider.chat(request) runs directly, with no proxy and no added latency.</span> | |
| <span class="c"># the SDK stamps correlation + context and fires the event async to the local agent.</span> | |
| </pre> | |
| <ul style="margin-top:10px"> | |
| <li><strong>Non-blocking:</strong> a logging hiccup never touches the model call.</li> | |
| <li><strong>Stack-agnostic:</strong> a native wrapper where we have one, a thin HTTP contract everywhere else.</li> | |
| <li><strong>Same record</strong> whether emitted here by the SDK or, for control use cases, by the gateway.</li> | |
| </ul> | |
| </section> | |
| <!-- 10 SCHEMA --> | |
| <section class="slide"> | |
| <div class="kicker">The shared contract</div> | |
| <h2>The audit event: one schema for both paths</h2> | |
| <div class="schema"> | |
| <div class="field"><code>event_id</code><span>unique, immutable identifier</span></div> | |
| <div class="field"><code>correlation_id</code><span>joins context, wire, multi-step chains</span></div> | |
| <div class="field"><code>occurred_at</code><span>UTC timestamp</span></div> | |
| <div class="field"><code>feature_id / version</code><span>which internal AI feature</span></div> | |
| <div class="field"><code>actor</code><span>user/service identity (pseudonymized)</span></div> | |
| <div class="field"><code>model_provider</code><span>OpenAI · Anthropic · internal</span></div> | |
| <div class="field"><code>model / model_version</code><span>exact model used</span></div> | |
| <div class="field"><code>input / input_hash</code><span>prompt, or hash if not retained</span></div> | |
| <div class="field"><code>output / output_hash</code><span>completion, or hash</span></div> | |
| <div class="field"><code>token_usage / cost</code><span>usage accounting</span></div> | |
| <div class="field"><code>policy_decisions</code><span>redactions / filters / blocks applied</span></div> | |
| <div class="field"><code>human_oversight</code><span>override / approval / none</span></div> | |
| <div class="field"><code>outcome</code><span>business decision or action taken</span></div> | |
| <div class="field"><code>prev_hash</code><span>links to prior event (tamper-evident chain)</span></div> | |
| </div> | |
| <div class="callout"><p>Because the SDK and the gateway emit the <strong>same schema to the same store</strong>, a feature can move from one path to the other later without changing its audit footprint.</p></div> | |
| </section> | |
| <!-- 11 GATEWAY --> | |
| <section class="slide"> | |
| <span class="tag b">The gateway · we're building this too</span> | |
| <h2 style="margin-top:10px">The high-control path</h2> | |
| <p>The gateway routes model calls through a central service. Reach for it when a use case needs more than visibility, when you need to <strong>actively govern</strong> what the model does:</p> | |
| <div class="three"> | |
| <div class="stat"><h4>Model selection control</h4><p>Enforce which models may be used, centrally, with no unapproved models in scope.</p></div> | |
| <div class="stat"><h4>Block dangerous content</h4><p>Inspect and stop unsafe prompts or responses in-line, before they land.</p></div> | |
| <div class="stat"><h4>Strongest auditability</h4><p>Capture is structural and can fail closed: no call proceeds unrecorded.</p></div> | |
| </div> | |
| <div class="flow" style="margin-top:14px"> | |
| <div class="node app">AI Feature</div> | |
| <span class="arrow">→</span> | |
| <div class="node gw">Gateway<small>govern · block · record</small></div> | |
| <span class="arrow">→</span> | |
| <div class="node">Providers</div> | |
| </div> | |
| <div class="callout"><p>The trade: it's in the call path (a hop), and it must be highly available. So we apply it <strong>where the control is worth it</strong>, not to every feature.</p></div> | |
| </section> | |
| <!-- 12 CHOOSING THE LANE --> | |
| <section class="slide"> | |
| <div class="kicker">Choosing the lane</div> | |
| <h2>Which path for a given feature?</h2> | |
| <table> | |
| <thead><tr><th> </th><th>SDK: start here</th><th>Gateway: when needed</th></tr></thead> | |
| <tbody> | |
| <tr><td>Primary need</td><td>Auditability / visibility</td><td>Control + enforcement</td></tr> | |
| <tr><td>In the model call path?</td><td><span class="pill g">No</span></td><td>Yes</td></tr> | |
| <tr><td>Latency</td><td><span class="pill g">None</span></td><td>Adds a hop</td></tr> | |
| <tr><td>Enforce model selection</td><td><span class="pill n">n/a</span></td><td><span class="pill g">Yes</span></td></tr> | |
| <tr><td>Block prompts / responses</td><td><span class="pill n">n/a</span></td><td><span class="pill g">Yes</span></td></tr> | |
| <tr><td>Audit completeness</td><td>Verified (CI + reconciliation)</td><td><span class="pill g">Structural / fail-closed</span></td></tr> | |
| <tr><td>Adoption effort</td><td><span class="pill g">Low (days)</span></td><td>Higher (route & govern)</td></tr> | |
| <tr><td>Default for</td><td>Most AI features</td><td>High-risk · regulated · content-sensitive</td></tr> | |
| </tbody> | |
| </table> | |
| <div class="callout"><p>Same audit schema and store either way. Choosing a lane is about <strong>how much control</strong> a use case needs, never about whether it's audited.</p></div> | |
| </section> | |
| <!-- 13 COVERAGE --> | |
| <section class="slide"> | |
| <div class="kicker">Assurance · the SDK path</div> | |
| <h2>How we know SDK-path features are actually logged</h2> | |
| <p class="muted">The SDK keeps egress to providers open, so coverage is enforced at build time and verified at runtime.</p> | |
| <div class="two" style="margin-top:6px"> | |
| <div class="card a"> | |
| <h4>Preventive (build-time)</h4> | |
| <ul> | |
| <li><strong>CI / dependency policy:</strong> the build fails if a provider client is used outside the approved SDK.</li> | |
| <li><strong>Central key issuance:</strong> provider keys go only to onboarded features; any key we didn't issue is shadow AI.</li> | |
| </ul> | |
| </div> | |
| <div class="card b"> | |
| <h4>Detective (runtime)</h4> | |
| <ul> | |
| <li><strong>Egress reconciliation:</strong> connections to provider domains are logged (destination only) and matched against audit events; an unmatched call is a detected gap.</li> | |
| <li><strong>Billing reconciliation:</strong> provider usage vs. logged volume.</li> | |
| <li><strong>Heartbeats:</strong> catch a silently disabled SDK.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>Features routed through the <strong>gateway</strong> need none of this; there, capture is structural. Self-hosted models are captured <strong>server-side at the endpoint</strong>.</p></div> | |
| </section> | |
| <!-- 14 PRIVACY --> | |
| <section class="slide"> | |
| <div class="kicker">For privacy & legal</div> | |
| <h2>Where redaction happens, and what that means</h2> | |
| <p>Parsing and redaction run on the <strong>logging server</strong>, which keeps the SDK tiny and stack-agnostic. The trade-off: raw prompts/responses, including any PII, pass through the pipeline before they're scrubbed, so the path into the store is in privacy scope, not just the store itself.</p> | |
| <div class="two"> | |
| <div class="card"> | |
| <h4>Containment</h4> | |
| <ul> | |
| <li>Encrypt in transit and at rest along the path.</li> | |
| <li>Least-privilege access; short retention before redaction.</li> | |
| <li>Redact as early in the pipeline as possible.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <h4>At the store</h4> | |
| <ul> | |
| <li>Hash-or-store per field: keep content only where lawful and necessary.</li> | |
| <li>Access is least-privilege and itself logged.</li> | |
| <li>Retention to the legal schedule; immutable until defensible disposal.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>For the most sensitive regulated features, the <strong>gateway path</strong> can redact and block in-line, another reason those use cases route through it.</p></div> | |
| </section> | |
| <!-- 15 ROLLOUT --> | |
| <section class="slide"> | |
| <div class="kicker">Rollout · both/and, phased</div> | |
| <h2>SDK first to prove it out, with the gateway in parallel or right after</h2> | |
| <div class="phase"><div class="n">0</div><div><h4>Foundation</h4><p>Ratify the audit event schema. Stand up the shared agent + logging service + immutable store. Build the SDK. Stand up the feature registry and central key issuance.</p></div></div> | |
| <div class="phase"><div class="n">1</div><div><h4>Prove the SDK</h4><p>Onboard AI features to the SDK; turn on the coverage controls. Broad, low-friction auditability across the portfolio, fast.</p></div></div> | |
| <div class="phase"><div class="n alt">2</div><div><h4>Gateway for control use cases</h4><p>Build the gateway for features that need model governance, content blocking, or fail-closed capture. <strong>Can run in parallel with Phase 1</strong>, or follow once the SDK is proven. A resourcing call, not an architectural one.</p></div></div> | |
| <div class="callout"><p>The shared schema makes either order safe: nothing built on the SDK has to be unwound when the gateway arrives.</p></div> | |
| </section> | |
| <!-- 16 DECISIONS --> | |
| <section class="slide"> | |
| <div class="kicker">What we need to settle</div> | |
| <h2>Open decisions & owners</h2> | |
| <table> | |
| <thead><tr><th>Decision</th><th colspan="2">Primary owners</th></tr></thead> | |
| <tbody> | |
| <tr><td>Gateway timing: in parallel with the SDK, or Phase 2 once it's proven</td><td colspan="2">Engineering leadership</td></tr> | |
| <tr><td>Which use cases require the gateway's control (model governance / content blocking / fail-closed)</td><td colspan="2">Legal + feature owners</td></tr> | |
| <tr><td>Redaction placement: server-side default vs. in-line at the gateway for regulated features</td><td colspan="2">Privacy + App devs</td></tr> | |
| <tr><td>Schema ratification: stored-raw vs. hashed, per field</td><td colspan="2">Legal + Architecture</td></tr> | |
| <tr><td>Ownership: SDK, agent/logger, store, registry, key issuance, gateway</td><td colspan="2">Engineering leadership</td></tr> | |
| </tbody> | |
| </table> | |
| <div class="callout pick"><p><strong>Proposed next step:</strong> approve Phase 0 so SDK auditability starts flowing within weeks, and decide gateway timing in parallel.</p></div> | |
| </section> | |
| </div> | |
| <div class="nav"> | |
| <button id="prev">‹ Prev</button> | |
| <span class="counter" id="counter">1 / 16</span> | |
| <button id="next">Next ›</button> | |
| </div> | |
| <script> | |
| const slides=[...document.querySelectorAll('.slide')]; | |
| let i=0; | |
| const counter=document.getElementById('counter'); | |
| const prog=document.getElementById('progress'); | |
| const prev=document.getElementById('prev'); | |
| const next=document.getElementById('next'); | |
| function show(n){ | |
| i=Math.max(0,Math.min(slides.length-1,n)); | |
| slides.forEach((s,k)=>s.classList.toggle('active',k===i)); | |
| counter.textContent=(i+1)+' / '+slides.length; | |
| prog.style.width=((i+1)/slides.length*100)+'%'; | |
| prev.disabled=i===0;next.disabled=i===slides.length-1; | |
| window.scrollTo({top:0,behavior:'smooth'}); | |
| } | |
| prev.onclick=()=>show(i-1); | |
| next.onclick=()=>show(i+1); | |
| document.addEventListener('keydown',e=>{ | |
| if(e.key==='ArrowRight'||e.key==='PageDown'){show(i+1);} | |
| if(e.key==='ArrowLeft'||e.key==='PageUp'){show(i-1);} | |
| if(e.key==='Home'){show(0);} | |
| if(e.key==='End'){show(slides.length-1);} | |
| }); | |
| show(0); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment