Skip to content

Instantly share code, notes, and snippets.

@twinge
Created June 30, 2026 21:32
Show Gist options
  • Select an option

  • Save twinge/bb4dd79bcad542ff4cca1a58d624f2b5 to your computer and use it in GitHub Desktop.

Select an option

Save twinge/bb4dd79bcad542ff4cca1a58d624f2b5 to your computer and use it in GitHub Desktop.
<!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 &amp; 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 &amp; 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>&nbsp;</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 &amp; 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 &amp; 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 &amp; 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