Last active
July 2, 2026 17:16
-
-
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) 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> | |
| <!-- 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 (merged: what + how) --> | |
| <section class="slide"> | |
| <span class="tag pick">The SDK</span> | |
| <h2 style="margin-top:10px">The low-friction path: capture the call, ship it out-of-band</h2> | |
| <p>A thin client your application embeds. It captures each model call, both the request and the model's response, 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">App + SDK<small>captures request + response</small></div> | |
| <span class="arrow">→<small>direct</small></span> | |
| <div class="node">Providers<small>no latency</small></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</small></div> | |
| <span class="arrow">→</span> | |
| <div class="node store">Immutable store</div> | |
| </div> | |
| <ul style="margin-top:6px"> | |
| <li><strong>Capture point 1, the model call:</strong> the SDK records the request and the model's response, then returns the response to your app untouched.</li> | |
| <li><strong>Capture point 2, the served output:</strong> when your app transforms the output before showing it (a safety gate, a rewrite), it records what the user actually saw. No post-processing? The model's response is the served output automatically.</li> | |
| <li>All async and non-blocking: the model call reaches the provider <strong>directly</strong>, with no proxy hop or added latency, and a logging hiccup never breaks the feature.</li> | |
| <li>The agent and logging service own <strong>delivery and parsing</strong>. The app does none of it.</li> | |
| </ul> | |
| <p class="muted" style="font-size:13px;margin-top:6px">Streaming responses are the one case needing per-provider handling: the SDK reassembles the stream to record the full completion.</p> | |
| <div class="callout pick"><p>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 and parsing. Not your team's problem.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <ul> | |
| <li class="good"><strong>No provider treadmill</strong>: calls are recorded as-is, without parsing the provider's parameters, 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>Consistent across the portfolio</strong>: every feature and provider produces the same record, so audit and reporting work the same way everywhere.</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> | |
| <!-- 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">If you post-process the output before showing it, record the served output (one more call).</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">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 in a block. The SDK invokes it, and records</span> | |
| <span class="c"># the request you pass plus the response the block returns.</span> | |
| response = <span class="k">AiAudit</span>.capture( | |
| feature: <span class="s">"support_summarizer"</span>, | |
| actor: current_user.id, | |
| request: request, <span class="c"># recorded as the audit input</span> | |
| context: { ticket_id: 123, channel: <span class="s">"email"</span> }, | |
| outcome: <span class="s">"draft_suggested"</span>, <span class="c"># business meaning, app-supplied</span> | |
| ) { provider.chat(request, model: <span class="s">"claude-sonnet-4-6"</span>) } | |
| <span class="c"># capture yields the block directly (no proxy, no added latency),</span> | |
| <span class="c"># records the request and the returned response, returns the response</span> | |
| <span class="c"># to you, and fires the audit 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> | |
| <!-- 10b SAMPLE SCHEMA (illustrative) --> | |
| <section class="slide"> | |
| <div class="kicker">Illustrative only · not the final schema</div> | |
| <h2>Roughly, what one captured record looks like</h2> | |
| <p class="muted">A sketch to make the idea concrete. The real field set, what is stored versus hashed, and retention all get defined and ratified later with legal.</p> | |
| <pre><span class="c">// illustrative example, names and shape are not final</span> | |
| { | |
| <span class="k">"event_id"</span>: <span class="s">"evt_9f2c4a…"</span>, | |
| <span class="k">"occurred_at"</span>: <span class="s">"2026-06-30T14:22:08Z"</span>, | |
| <span class="k">"feature"</span>: <span class="s">"support_summarizer"</span>, | |
| <span class="k">"actor"</span>: <span class="s">"user_4821"</span>, | |
| <span class="k">"model"</span>: <span class="s">"claude-sonnet-4-6"</span>, | |
| <span class="k">"input"</span>: <span class="s">"Summarize support ticket #123…"</span>, | |
| <span class="k">"model_output"</span>: <span class="s">"Draft reply suggested to agent…"</span>, <span class="c">// raw completion</span> | |
| <span class="k">"served_output"</span>: <span class="s">"Draft reply, after safety gate…"</span>, <span class="c">// what the user saw</span> | |
| <span class="k">"tokens"</span>: { <span class="k">"in"</span>: 1840, <span class="k">"out"</span>: 220 }, | |
| <span class="k">"context"</span>: { <span class="k">"ticket_id"</span>: 123, <span class="k">"channel"</span>: <span class="s">"email"</span> }, | |
| <span class="k">"outcome"</span>: <span class="s">"draft_suggested"</span> | |
| } | |
| </pre> | |
| <div class="callout"><p>The point is only that every feature emits a record in one shared shape. The exact fields are a later decision, not something we are approving here.</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>Because safety runs <strong>in-line</strong>, the response the gateway returns is exactly what the app serves, so no separate served-output capture is needed. The trade: it's in the call path and must be highly available, so we apply it where the control is worth it.</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 (registry + code scan)</td><td><span class="pill g">Structural / fail-closed</span></td></tr> | |
| <tr><td>Captures the served output</td><td>App records it when it post-processes</td><td><span class="pill g">In-line, automatic</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">We don't enforce this at the network layer. Two controls that are realistic for us:</p> | |
| <div class="two" style="margin-top:6px"> | |
| <div class="card a"> | |
| <h4>1 · Register the feature</h4> | |
| <ul> | |
| <li>Every internally-built AI feature must <strong>register with the central logging system</strong> before it ships.</li> | |
| <li>The registry is the roster of what should be reporting, and the denominator for coverage.</li> | |
| </ul> | |
| </div> | |
| <div class="card b"> | |
| <h4>2 · Periodic code scan</h4> | |
| <ul> | |
| <li>On a schedule, scan repositories to confirm <strong>no model calls are made outside the SDK wrapper</strong>.</li> | |
| <li>Any direct provider call is flagged and fixed; a registered feature with no wrapper usage stands out.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="callout"><p>Gateway-routed features <strong>still register</strong>, so their records carry feature context; what they skip is the code scan, since routing through the gateway makes capture structural.</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>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>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> | |
| </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