<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://ethos71.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ethos71.github.io/" rel="alternate" type="text/html" /><updated>2026-06-12T08:43:46-04:00</updated><id>https://ethos71.github.io/feed.xml</id><title type="html">Dominick A. Campbell</title><subtitle>Principal Engineer &amp; AI Architect · 4 Patent-Pending AI Inventions · 25+ Years</subtitle><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><entry><title type="html">The Strangler Fig Pattern: Modernizing Without Ripping Out</title><link href="https://ethos71.github.io/engineering/leadership/2026/06/06/strangler-fig-modernization.html" rel="alternate" type="text/html" title="The Strangler Fig Pattern: Modernizing Without Ripping Out" /><published>2026-06-06T00:00:00-04:00</published><updated>2026-06-06T00:00:00-04:00</updated><id>https://ethos71.github.io/engineering/leadership/2026/06/06/strangler-fig-modernization</id><content type="html" xml:base="https://ethos71.github.io/engineering/leadership/2026/06/06/strangler-fig-modernization.html"><![CDATA[<p>I joined Connect Your Care in Hunt Valley in May of 2019. HRCommand — the flagship — was a J2EE/EJB monolith running on WebLogic, ten years of consumer HR product baked into it. The brief was straightforward: modernize it, don’t break it, and ship enough new product surface that a strategic acquirer would care.</p>

<p>Twenty-three months later UnitedHealth/Optum Financial acquired the company, and the modernized HRCommand architecture was sitting on the table in the due-diligence room. We never did a cutover weekend. We never had a release outage. Five engineers, two-week loop, two years.</p>

<p>We didn’t rewrite it. We ran the <strong>strangler fig</strong> pattern, and we ran it boring.</p>

<pre><code class="language-mermaid">graph LR
    M1[Monolith] --&gt; M2[Monolith&lt;br/&gt;shrinks]
    M2 --&gt; M3[Microservices&lt;br/&gt;grow]
    S[New service 1] --&gt; M2
    M3 --&gt; S2[New service N]
</code></pre>
<p><em>Figure: the strangler-fig pattern — new grows around old as old shrinks.</em></p>

<h2 id="why-i-wont-sign-up-for-a-full-rewrite">Why I won’t sign up for a full rewrite</h2>

<p>I’ve sat in the meeting at five companies now. New VP, new deck, same line: the monolith is the problem, we need a full rewrite. Four of those rewrites shipped late, shipped broken, or got killed at 60% with a half-built parallel system and a monolith nobody had improved.</p>

<p>A decade-old monolith is not a code problem. It’s a <em>running business</em> — integration contracts, regulatory commitments, a long list of undocumented behaviors that customer support has been quietly accommodating for years. The day you announce the rewrite, the old team stops shipping. The new team rediscovers undocumented behavior the hard way. Leadership rotates. The Q4 board deck reads differently than the Q1 one. None of that is exotic. It happens every time.</p>

<h2 id="what-we-did-at-cyc">What we did at CYC</h2>

<p>Thin proxy in front of HRCommand. Day one, zero new behavior. Pick the smallest bounded context with a clean data-ownership boundary — for us, that was a benefit-eligibility surface nobody wanted to touch. Build it as a Spring Boot service. Route traffic behind a per-endpoint feature flag. Watch error rates and the business KPIs that actually mattered for two weeks. If anything moved wrong, the flag flipped back in seconds. Peel the old code path out. Pick the next.</p>

<p>In parallel, the UI rebuilt itself the same way — React replacing the old JSP screens slice by slice, Figma-to-code components landing in a shared library that the rest of the consumer-facing product line eventually adopted.</p>

<h2 id="the-boring-parts-that-decide-whether-it-works">The boring parts that decide whether it works</h2>

<p>The pattern is simple. The discipline is the part teams skip, because it doesn’t feel like progress on the new system:</p>

<ol>
  <li><strong>Anti-corruption layer at every seam.</strong> New service owns its own data model and translates in one file. When the monolith changes shape, one file changes.</li>
  <li><strong>Idempotency keys on every cross-seam write.</strong> The proxy will retry. Without idempotency you get duplicate benefits records and a very bad Monday.</li>
  <li><strong>Outbox pattern for events.</strong> State change and event write commit in the same transaction; a drainer publishes. You never lose an event, never publish one that didn’t happen.</li>
  <li><strong>Feature flags per endpoint, not per release.</strong> Thirty-second rollback instead of a war room.</li>
  <li><strong>Commit to the loop, not the order.</strong> Which context moves next falls out of where the pain is, not out of a Gantt chart drawn in March.</li>
</ol>

<p>None of these are exotic. They’re what teams pretend they’ll add later and then don’t.</p>

<h2 id="when-id-actually-entertain-a-rewrite">When I’d actually entertain a rewrite</h2>

<p>One case: the monolith genuinely cannot scale and the runway is funded for a parallel build to completion. That case is rarer than people think. Most monoliths that “can’t scale” scale fine after two focused months on the three hot paths. Test that hypothesis before you spend a year of a five-person team on a parallel build that may not finish.</p>

<p>The pattern is just the vehicle. The thing I’m proudest of from those two years isn’t the architecture diagram — it’s that the team shipped boring, disciplined two-week increments until they compounded into an acquisition.</p>

<p>More soon.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Engineering" /><category term="Leadership" /><category term="modernization" /><category term="microservices" /><category term="monolith" /><category term="strangler-fig" /><category term="enterprise-architecture" /><summary type="html"><![CDATA[Rip-and-replace is malpractice when the monolith is paying the bills. Here's the pattern that actually works — and why the discipline matters more than the diagram.]]></summary></entry><entry><title type="html">Week Notes — June 4: Rebuilding the Fantasy Baseball AI</title><link href="https://ethos71.github.io/notes/engineering/ai/2026/06/04/week-notes-fantasy-baseball.html" rel="alternate" type="text/html" title="Week Notes — June 4: Rebuilding the Fantasy Baseball AI" /><published>2026-06-04T00:00:00-04:00</published><updated>2026-06-04T00:00:00-04:00</updated><id>https://ethos71.github.io/notes/engineering/ai/2026/06/04/week-notes-fantasy-baseball</id><content type="html" xml:base="https://ethos71.github.io/notes/engineering/ai/2026/06/04/week-notes-fantasy-baseball.html"><![CDATA[<p>The waiver wire went empty and nothing complained about it.</p>

<p>That’s the bug I hate most. My fantasy baseball AI — the thing I build on weekends to tell me who to start and which trade is a fleece — kept rendering a clean, confident, empty list of waiver targets. No error. No stack trace. A recommendation engine quietly recommending nothing.</p>

<p>The cause was dumb, the way these always are. The pipeline was writing to two places at once: a real database and a pile of CSV files left over from an earlier design. One job stopped writing the CSVs. The waiver code still read them. Empty file, empty list, no exception thrown. <strong>A silent failure is worse than a loud one.</strong> The loud one at least tells you to come look.</p>

<p>So most of the week went into ripping the CSVs out.</p>

<h2 id="one-source-of-truth">One source of truth</h2>

<p>The data path had thirteen spots where something read or wrote a CSV. It’s now zero. Everything goes through the database, and I added a gate to the test suite that fails the build if a CSV ever creeps back in. That part matters more than the cleanup. A one-time fix that nothing enforces is a fix with an expiration date.</p>

<h2 id="the-pipeline-got-honest-about-time">The pipeline got honest about time</h2>

<p>The nightly job that recomputes every lineup recommendation took seventy-seven minutes. This week it takes a hundred and nineteen seconds.</p>

<p>I’d love to tell you I found an elegant algorithm. I didn’t. The job was running the full factor-analysis pass, then running most of it again a step later on the same data. I taught the second step to reuse what the first one already wrote. The fanciest optimization is usually noticing you’re doing the work twice. That run now resolves 8,061 of 8,386 players to real projections instead of silently dropping the ones whose names don’t match cleanly.</p>

<h2 id="names-are-a-terrible-primary-key">Names are a terrible primary key</h2>

<p>Match a player on his name and you’re one accent or nickname away from dropping him silently. So the back half of the week moved the joins that feed recommendations off player names and onto stable IDs.</p>

<p>Underneath that was an older sin: a past identity bug had stamped three different fantasy teams onto one team ID. The repair is self-healing now — it overwrites the corrupted values from the authoritative roster instead of politely filling in the blanks, and coverage went from around ten percent to ninety. The nightly cron also stopped false-failing on “database is locked,” which turned out to be three steps colliding with the midday stats scrape. The fix was a longer timeout. Patience, not cleverness.</p>

<h2 id="the-front-end-is-finally-react">The front end is finally React</h2>

<p>For a while the UI was server-rendered HTML held together by a Python framework I’d outgrown. It’s now a real React app: twenty-eight pages covering rosters, trades, the waiver wire, draft prep, and live matchup projections, cold-loading in about a second and a half. The trade view has a proper evaluator; the roster page flags buy-low and sell-high targets off the skill-score percentiles.</p>

<p>I won’t pretend a side project needed React. It didn’t. But I wanted real client-side state and an honest API contract between the front and back ends, and I wanted my hands in the framework most of the people I interview with are using. Both things are true. I’ll own it.</p>

<p>It also writes its own column now. A morning job drafts a weekly recap of the league — who’s heating up, who you should be worried about — and the site serves it like any other page. The AI covering the league it also runs. That one makes me laugh.</p>

<h2 id="the-model-stayed-benched">The model stayed benched</h2>

<p>A couple of weeks ago I wrote here about the model’s honest limits. This week I acted on it. There’s a machine-learning ensemble in the codebase, fully built, and it loses: a plain blend of public projections and percentile skill scores beats it on the board. So it stays benched. Shipping the ML <em>because it’s the ML</em> is exactly the trend-chasing I spend half my time talking other people out of, and it’s a lot harder to take that advice when you’re the one who wrote the losing model.</p>

<p>The boring projection that wins is the one in production.</p>

<p>More next week.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Notes" /><category term="Engineering" /><category term="AI" /><category term="dev log" /><category term="react" /><category term="fantasy-baseball" /><category term="side project" /><summary type="html"><![CDATA[The waiver recommender went quietly empty and never complained. Most of a week went into making the data pipeline stop lying — plus a real React front end and a model I left benched on purpose.]]></summary></entry><entry><title type="html">$830B in Fraud Prevented: Building Voice Biometric Auth at 10M Scale</title><link href="https://ethos71.github.io/engineering/case%20studies/2026/05/30/voice-biometric-fraud.html" rel="alternate" type="text/html" title="$830B in Fraud Prevented: Building Voice Biometric Auth at 10M Scale" /><published>2026-05-30T00:00:00-04:00</published><updated>2026-05-30T00:00:00-04:00</updated><id>https://ethos71.github.io/engineering/case%20studies/2026/05/30/voice-biometric-fraud</id><content type="html" xml:base="https://ethos71.github.io/engineering/case%20studies/2026/05/30/voice-biometric-fraud.html"><![CDATA[<p>The number I think about from this project is 1,300.</p>

<p>That’s how many JPMorgan Chase customers opted out of voice biometric authentication during the first three months. <strong>Ten million accounts in. 1,300 out. A 99.87% adoption rate</strong> on a security feature.</p>

<p>I’ve shipped a lot of systems in 25 years and that’s the highest voluntary adoption I’ve ever seen on anything touching account security. The headline metric is the ~$830B in fraud losses prevented across the JPMC consumer banking cohort, and that’s the one that gets quoted. The 99.87% is the one I think about, because we didn’t get there by being clever about the security model.</p>

<pre><code class="language-mermaid">graph LR
    A[10M JPMC&lt;br/&gt;accounts] --&gt; B[Voice fingerprint&lt;br/&gt;opt-in]
    B --&gt; O1[99.87%&lt;br/&gt;adopted]
    B --&gt; O2[0.13%&lt;br/&gt;opted out]
</code></pre>
<p><em>Figure: opt-in adoption that didn’t look like opt-in adoption.</em></p>

<h2 id="what-we-were-trying-to-solve">What we were trying to solve</h2>

<p>I was an Infrastructure Developer at JPMC’s Wilmington office from February 2018 to February 2019, embedded with the TARA Fraud Busters group. The problem was call-center fraud. Attacker calls in pretending to be the account holder. Rep authenticates with knowledge-based questions — mother’s maiden name, last four of social, last transaction amount. Every one of those answers was sitting in a breached database somewhere on the open web. Rep authenticates the attacker, fraud goes through.</p>

<p>Knowledge-based authentication was finished. The fraud team knew it. What nobody had was a clean replacement that customers would actually adopt.</p>

<h2 id="why-we-didnt-ship-a-passphrase">Why we didn’t ship a passphrase</h2>

<p>The default fix in the literature is a voice passphrase. Customer enrolls a phrase, says it on every call, system matches the voiceprint. It works as a security control. As a customer experience it’s a slow disaster — fifteen seconds on every call, a confusion vector when people forget the phrase, and an explicit opt-in moment where the customer has to choose to enroll. That moment is where security features die.</p>

<p>So we asked a different question: what if enrollment is the call they were already making?</p>

<h2 id="what-we-built">What we built</h2>

<p>Passive voice biometric fingerprinting, Python and ML on the matcher side. Customer calls about a disputed charge, a lost card, a balance question, whatever. The system captures a fingerprint silently during the natural conversation. Thirty seconds of normal call and a voiceprint accumulates in the background.</p>

<p>On the next call, the system matches the new voice against the enrolled one and surfaces a confidence score before the rep starts knowledge questions. High confidence — skip them, authenticate immediately. Low confidence — fall back to the old flow plus extra fraud checks. We fed all of it into the JPMC CAT tool, an Angular dashboard pulling aggregated REST APIs across the fraud surface, with a Sapiens rules engine applying policy in real time.</p>

<p>The customer never saw any of this. They just noticed their calls went faster.</p>

<h2 id="the-hard-parts">The hard parts</h2>

<p>Voiceprint matching itself was the easy part — mature libraries exist. The work was in the parts around it.</p>

<ol>
  <li><strong>The capture pipeline.</strong> Call-center audio is not studio audio. Mid-call noise, multiple speakers, partial captures. Every fingerprint carried a quality score and the matcher gated on it.</li>
  <li><strong>The opt-out path.</strong> One sentence, on the call, no forms. “I’d rather you didn’t use voice on my account” — done, flag flipped, respected on every subsequent call. <strong>The 1,300 customers who opted out used this path.</strong></li>
  <li><strong>The fraud-ops feedback loop.</strong> Rep flags went straight into the training set. Model got better every week.</li>
</ol>

<h2 id="the-numbers">The numbers</h2>

<p>Three months in: 10,000,000 accounts enrolled passively, no opt-in click. 1,300 opt-outs — the number that proved the opt-out path actually worked. Twenty seconds off the average authenticated call, which at call-center scale translated to roughly 25 more customers per rep per day. The post-deployment analysis pegged the fraud-loss plateau across JPMC consumer banking at ~$830B prevented.</p>

<h2 id="what-id-tell-someone-building-the-next-one">What I’d tell someone building the next one</h2>

<p>Security features get treated as if customer experience is a tax you pay for safety. Frame the problem that way and you get small-percentage adoption and a postmortem.</p>

<p>Flip it. Build the security feature so the customer’s life gets <em>better</em> at the moment it engages. 99.87% is what happens when you frame the design problem correctly.</p>

<p>Back to work.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Engineering" /><category term="Case Studies" /><category term="fintech" /><category term="biometric" /><category term="fraud-prevention" /><category term="authentication" /><category term="scale" /><category term="jpmorgan" /><summary type="html"><![CDATA[99.87% of 10 million JPMC accounts opted in to voice biometric authentication during the first three months. About 1,300 opted out. The interesting number is not the 99.87%.]]></summary></entry><entry><title type="html">How I Built an ML Model That Knows Its Own Limits</title><link href="https://ethos71.github.io/engineering/ai/2026/05/23/ml-model-honest-limits.html" rel="alternate" type="text/html" title="How I Built an ML Model That Knows Its Own Limits" /><published>2026-05-23T00:00:00-04:00</published><updated>2026-05-23T00:00:00-04:00</updated><id>https://ethos71.github.io/engineering/ai/2026/05/23/ml-model-honest-limits</id><content type="html" xml:base="https://ethos71.github.io/engineering/ai/2026/05/23/ml-model-honest-limits.html"><![CDATA[<p>The most useful number in this model is the gap between two other numbers.</p>

<p><strong>Training MAE: 1.765 fantasy points. Test MAE: 3.079 fantasy points.</strong></p>

<p>If you’ve done any ML in production you know what that gap means. The model fits its training data tighter than it fits the world. It’s overfit. Some level of overfitting is almost always happening; the question is whether you measured it and can say out loud why it’s there.</p>

<p>Most of the production “AI” I’ve seen in the wild can’t.</p>

<pre><code class="language-mermaid">graph LR
    T[April 1-25&lt;br/&gt;training] --&gt; M[Model]
    V[April 25 - May 2&lt;br/&gt;test] --&gt; M
    M --&gt; E[Train MAE 1.765&lt;br/&gt;Test MAE 3.079]
</code></pre>
<p><em>Figure: the train/test split that exposed the honest gap.</em></p>

<h2 id="what-i-built">What I built</h2>

<p>A daily player-performance predictor for fantasy baseball — my side project, <a href="https://github.com/ethos71/fantasy-baseball-ai">github.com/ethos71/fantasy-baseball-ai</a>. XGBoost regression, Streamlit UI on top. Target is how many fantasy points a given MLB batter scores the next day, standard rotisserie scoring, about 150 batters in play on any given slate.</p>

<p>Training data was 2,300+ real game logs from April 2026, engineered into ten features per player-day. Rolling averages at 5, 10, and 20 games. Standard deviations across the same windows. Trend deltas. Binary flags for hot streaks and cold streaks.</p>

<p>Ten hand-crafted, domain-informed features. That part matters more than which gradient-boosted library you reached for.</p>

<h2 id="why-xgboost">Why XGBoost</h2>

<p>I’m not religious about it. I picked it for boring reasons. Mixed feature types without preprocessing gymnastics. 200 trees train in seconds on a laptop. Feature importance falls out of the model for free. And when a friend in my league asks “why six points?”, I can answer in English instead of waving at gradients.</p>

<p>A neural network wouldn’t have helped here. 4,800 samples isn’t enough to make a deep architecture stable, and “the gradients converged” isn’t an answer that survives a Sunday-morning text thread, let alone a stakeholder room.</p>

<h2 id="the-validation-choice">The validation choice</h2>

<p>Most fantasy-sports ML projects random-split their data. Random splits look great in notebooks and lie about reality. If a model trains on May 15 data and tests on April 20 data, you’ve leaked the future into the past. The reported accuracy is fiction.</p>

<p>So I did temporal validation. <strong>Train on April 1–25. Test on April 25–May 2.</strong> No shuffling. The test set is strictly later than the training set, the way the model would have to operate if I deployed it. That’s the choice that produced the gap. A random split would have buried it.</p>

<h2 id="what-the-honest-number-means">What the honest number means</h2>

<p>Train MAE 1.765 says the model learned the patterns in the April window. Test MAE 3.079 says they don’t fully generalize a week forward. The reason is in the features. Mine are all about <em>the batter</em>. Nothing about who he’s facing, weather, ballpark, rest, lineup spot. A hot hitter against a Triple-A call-up is a different distribution from a hot hitter against an ace, and the model has no way to tell them apart.</p>

<p>About 40% of predictions land within ±2 FP, useful for relative ranking. The worst errors are 15+ FP and they cluster in exactly the games my features can’t see. A slumping batter detonates against a rookie spot-starter; of course the model missed it.</p>

<p>80% of ML accuracy comes from the domain features. Most projects invert that ratio and wonder why the pipeline doesn’t get better in production.</p>

<h2 id="what-id-ship">What I’d ship</h2>

<p>I wouldn’t ship this as autonomous predictions. Not yet. What I’d ship is the model as a tool an analyst uses, paired with Vegas lines, FanGraphs projections, and somebody who knows Ohtani isn’t on waivers no matter what the database says.</p>

<p>Next iteration adds opponent ERA/OPS-allowed, pitcher handedness, and rest days. That should close the gap and beat the FanGraphs baseline this version underperforms by about 10%. Then weekly retrains and drift monitoring against the baseline.</p>

<p>I’ve sat in too many rooms where someone presented a 99% accurate model that was 99% leaked. The hard part of production ML isn’t moving the metric. It’s knowing what the model doesn’t know, and being willing to put that gap on the slide.</p>

<p>The model doesn’t know who’s pitching tomorrow. I do. That’s the partnership.</p>

<p>More soon.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Engineering" /><category term="AI" /><category term="ml" /><category term="xgboost" /><category term="modeling" /><category term="overfitting" /><category term="fantasy-baseball" /><summary type="html"><![CDATA[Train MAE 1.765. Test MAE 3.079. That gap is not a bug to hide — it's the whole point of the post. A model that knows what it doesn't know is more useful than one that pretends.]]></summary></entry><entry><title type="html">Week Notes — May 18: The Week the Toolkit Earned Its Keep</title><link href="https://ethos71.github.io/notes/engineering/ai/2026/05/18/week-notes-toolkit-week.html" rel="alternate" type="text/html" title="Week Notes — May 18: The Week the Toolkit Earned Its Keep" /><published>2026-05-18T00:00:00-04:00</published><updated>2026-05-18T00:00:00-04:00</updated><id>https://ethos71.github.io/notes/engineering/ai/2026/05/18/week-notes-toolkit-week</id><content type="html" xml:base="https://ethos71.github.io/notes/engineering/ai/2026/05/18/week-notes-toolkit-week.html"><![CDATA[<h2 id="what-i-shipped">What I shipped</h2>

<p>Most of the week went into <strong><code class="language-plaintext highlighter-rouge">dom</code></strong>, the AI cost-cutting toolkit. The premise is simple: most coding tasks don’t need a $2 Opus call. Haiku at one cent does it, and a third of the time a local Ollama model does it for free. <code class="language-plaintext highlighter-rouge">dom</code> routes the task to the cheapest model that can actually do it. One curl command installs it into any project; an eval policy gates every change.</p>

<p>Three things landed this week:</p>

<ol>
  <li>
    <p><strong>Polyglot smoke matrix.</strong> Three full compose stacks proving the toolkit scaffolds any combination of UI × API × DB: React+Spring+H2, React+Python+H2, and Node+C#+Oracle+Ollama. Same Karate feature runs against all three and must return the literal string <code class="language-plaintext highlighter-rouge">hello world</code> end-to-end. Three different language runtimes, four database vendors, and one assertion. That’s a contract.</p>
  </li>
  <li>
    <p><strong>Edit-everywhere, today.</strong> As of an hour ago, every stack now has a working edit button — UI fires a <code class="language-plaintext highlighter-rouge">PUT /hello</code>, the API tier proxies to the AI tier, the AI tier detects edit intent via a deterministic regex (no LLM for the parse — too expensive, too unreliable), and the underlying DB row gets updated. The byte-exact <code class="language-plaintext highlighter-rouge">hello world</code> contract still passes for any non-edit input. Five files, three languages, one consistent pattern.</p>
  </li>
  <li>
    <p><strong>A <code class="language-plaintext highlighter-rouge">@dom</code> orchestrator agent</strong> with hard rules about what it routes versus what it doesn’t touch. It’s the front door for “how do I do X in <code class="language-plaintext highlighter-rouge">dom</code>?” and it doesn’t write code — that’s the next agent down the chain.</p>
  </li>
</ol>

<p><code class="language-plaintext highlighter-rouge">dom</code> is going to underwrite everything I build for the next year. I’d rather spend a Saturday once than $200/mo on tokens forever.</p>

<h2 id="what-else-moved">What else moved</h2>

<ul>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">@job</code></strong> got rebuilt. Scope cut to job-hunt only, outplacement and separation docs moved out, validated-only pipeline, dashboard cleanup. The agent was carrying too much; I trimmed it to the one thing it has to do.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">smartballz</code></strong>, my fantasy-football XGBoost project, got a silent-failure sweep — banned a class of broad-except handlers that were masking real DB errors as “bad credentials.” Also fixed two actual model bugs (Ohtani showing on waivers when he shouldn’t, mid-tier trade values flattening out). The kind of week where you stop and notice the model is wrong before the league does.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">nyx-crm</code></strong> got a CI shell-injection fix and a FastMCP server with 19 verification tools — branch protection, audit logs, AI-call routing, skill search, diff, prisma studio. Boring infrastructure week. Boring infrastructure is good.</p>
  </li>
</ul>

<p>If you’re keeping score: that’s four repos with substantive commits in seven days, all while running an active job search. The fact that I can do that is the toolkit doing its job.</p>

<h2 id="the-other-layer">The other layer</h2>

<p>I’m between roles. Anyone who’s followed along knows that. Family stuff in the mix means I’m deliberate about fit right now — and “deliberate” doesn’t mean “slow,” it means I know exactly what I’m looking for and I won’t sign for less. Senior engineering roles where the AI work is real, the team is serious, the problem is hard. Not AI-strategy-document jobs.</p>

<p>My kid had a great week at his Challenger sports program — the league for kids of all abilities. Every week I’m reminded that the people who run those programs are doing harder work than most engineering teams I’ve been on, with a fraction of the resources, and they show up cheerful every Saturday. I think about that a lot.</p>

<h2 id="whats-next">What’s next</h2>

<p>Two threads. On the engineering side: <code class="language-plaintext highlighter-rouge">dom</code> gets a release tag this week and I start dogfooding it across all the side projects — already doing that, but now with versioned install instructions. On the job-search side: several real conversations in motion. Not naming names; the right ones are good shape.</p>

<p>If you’re here from a posting or recruiter intro — what I write here is what I think.</p>

<p>More next week.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Notes" /><category term="Engineering" /><category term="AI" /><category term="dev log" /><category term="dom" /><category term="smartballz" /><category term="job search" /><summary type="html"><![CDATA[First of a weekly cadence. Less essay, more field notes — what shipped, what surprised me, where the week actually went.]]></summary></entry><entry><title type="html">Five Systems I Shipped: A Production Case Study Catalog</title><link href="https://ethos71.github.io/engineering/ai/case%20studies/2026/05/09/five-systems-case-studies.html" rel="alternate" type="text/html" title="Five Systems I Shipped: A Production Case Study Catalog" /><published>2026-05-09T00:00:00-04:00</published><updated>2026-05-09T00:00:00-04:00</updated><id>https://ethos71.github.io/engineering/ai/case%20studies/2026/05/09/five-systems-case-studies</id><content type="html" xml:base="https://ethos71.github.io/engineering/ai/case%20studies/2026/05/09/five-systems-case-studies.html"><![CDATA[<p>People ask what I’ve actually shipped. The deep-dive posts cover the systems one at a time; this is the consolidated version. Five systems from the last decade, each one in production, each one moved a number the business cared about. Where there’s a deeper post, I link to it. Where there isn’t, I go a little deeper here.</p>

<pre><code class="language-mermaid">graph TB
    A[Robby&lt;br/&gt;Vertex]
    B[Mort AI Nexus&lt;br/&gt;Vertex]
    C[Data Cake&lt;br/&gt;Vertex]
    D[Voice biometric&lt;br/&gt;JPMC]
    E[Strangler-fig&lt;br/&gt;Connect Your Care]
</code></pre>
<p><em>Figure: five systems, five domains.</em></p>

<hr />

<h2 id="1-robby--multi-agent-sdlc-system">1. Robby — Multi-Agent SDLC System</h2>

<p><strong>Where it ran:</strong> Vertex Inc., Data &amp; Insights value stream
<strong>My role:</strong> Inventor, lead engineer
<strong>Year:</strong> 2024–2026</p>

<p>The premise was the super-chicken problem. Teams stacked with high individual performers were producing less, not more. People were spending half their day in process — Jira hygiene, status updates, sprint planning, design reviews — and the half they had left wasn’t enough to do the actual work.</p>

<p>Robby is a patent-pending multi-agent AI system for SDLC orchestration. The bet was that an AI layer could absorb the process work eating my team’s day and give the humans back the hours they came here for. It paid out. The afternoons that used to vanish into Jira hygiene started going back into engineering.</p>

<p><strong>Tech:</strong> multi-agent AI tooling, ArgoCD, GitHub Actions, Datadog
<strong>Outcome:</strong> Adopted across multiple teams; the “Raise the Boats” workshop trained ~50 engineers in the live cohort on how to extend the same approach
<strong>Deeper read:</strong> <a href="/ai/engineering/leadership/2026/02/19/robby-ai-sdlc-system.html">Robby: I Built an AI System to Kill the Super Chicken Problem</a></p>

<hr />

<h2 id="2-mort-ai-nexus--multi-state-economic-nexus-detection">2. Mort AI Nexus — Multi-State Economic Nexus Detection</h2>

<p><strong>Where it ran:</strong> Vertex Inc., Indirect Tax Intelligence
<strong>My role:</strong> Inventor, principal engineer
<strong>Year:</strong> 2024–2026
<strong>Status:</strong> Patent pending</p>

<p>The Wayfair ruling in 2018 changed sales-tax compliance for every company doing business across state lines. Each state set its own thresholds — typically $100K in revenue or 200 transactions per year — and once you crossed the line you owed sales tax in that state. The catch: most companies didn’t know they’d crossed until a state notice arrived months later, with penalties and interest stacked on top.</p>

<p>The existing approach was reactive. Tax teams reviewed quarterly reports and chased compliance after the fact. Financial exposure for a single missed state could run $100K–$500K.</p>

<p>Mort AI Nexus is a patent-pending AI system that shifts nexus discovery from reactive to predictive — so compliance teams can register and configure tax calculation ahead of crossing a state’s threshold, instead of catching up after a state notice arrives. Customers stopped finding out about exposure from state notices and started finding out from the platform, weeks before the line.</p>

<p><strong>Tech:</strong> Java, Spring Boot, AWS
<strong>Outcome:</strong> Customers shifted from reactive quarterly reviews to forward-looking nexus monitoring; preventable penalty exposure reduced</p>

<hr />

<h2 id="3-voice-biometric-fingerprinting--jp-morgan-chase">3. Voice Biometric Fingerprinting — JP Morgan Chase</h2>

<p><strong>Where it ran:</strong> JPMC TARA Fraud Busters, retail banking
<strong>My role:</strong> Lead developer
<strong>Year:</strong> 2018–2019</p>

<p>Knowledge-based authentication was a broken control. Every breached database in the prior decade had handed the answers — mother’s maiden name, last four of the social — to whoever wanted them. A rep could ask all the right questions and authenticate the wrong person.</p>

<p>We built a voice biometric fingerprinting service inside JPMC’s TARA Fraud Busters group. The service captured a passive voice fingerprint during the natural course of a customer call, matched it against the enrolled fingerprint for that customer, and returned a confidence score the rep saw before authenticating. The customer didn’t have to say a passphrase. They just had to talk for a few seconds, which they were going to do anyway.</p>

<p>The deployment numbers told the story. <strong>10 million unique JPMC accounts opted in during the first three months. Only 1,300 customers opted out.</strong> That’s a 99.87% adoption rate. The pilot shortened the average authenticated call by 20 seconds because reps weren’t grinding through knowledge-based questions any more — which translated to 25 more customers serviced per rep per day.</p>

<p>The fraud-prevention number is the headline (~$830B in losses prevented across the deployment cohort). The customer-experience side was the quieter win. Security that made the customer’s day shorter instead of longer is the kind of control people don’t opt out of.</p>

<p><strong>Tech:</strong> Python, ML/biometrics, REST APIs, Sapiens rules engine, Angular dashboard, JavaScript
<strong>Outcome:</strong> ~10M accounts onboarded in 90 days; 20-second call reduction per authenticated call; ~$830B in fraud losses prevented across the deployment cohort</p>

<hr />

<h2 id="4-data-cake--nlp-synthetic-tax-data-generation">4. Data Cake — NLP Synthetic Tax Data Generation</h2>

<p><strong>Where it ran:</strong> Vertex Inc., AI research
<strong>My role:</strong> Inventor, principal engineer
<strong>Year:</strong> 2024–2026
<strong>Status:</strong> Patent pending</p>

<p>You can’t train tax AI on real customer transactions. The data is PII-laden, regulated, contractually restricted. You also can’t train tax AI without realistic transactional data — synthetic data that doesn’t reflect the statistical properties of real tax events produces models that fall apart in production.</p>

<p>Data Cake is a patent-pending system for generating realistic synthetic tax data that ML projects can train against without putting real customer transactions at risk. Synthetic outputs respect tax-law validity, so downstream models train on something that actually behaves like the production world.</p>

<p>What changed when we deployed it: model training stopped being a regulatory negotiation. New ML projects could spin up training data in days instead of quarters, without ever touching real customer information.</p>

<p><strong>Tech:</strong> Python, NLP-driven generation
<strong>Outcome:</strong> Removed the data-access bottleneck for AI model training; enabled tax ML projects that previously couldn’t be greenlit</p>

<hr />

<h2 id="5-connect-your-care--monolith-to-microservices">5. Connect Your Care — Monolith to Microservices</h2>

<p><strong>Where it ran:</strong> Connect Your Care, HRCommand product
<strong>My role:</strong> Architect &amp; lead engineer
<strong>Year:</strong> 2019–2021</p>

<p>Connect Your Care was a benefits-administration company sitting on a J2EE/EJB monolith built across the better part of a decade. HRCommand was the flagship product. The monolith worked. It served customers. It also blocked every strategic initiative the company wanted to ship — new product surfaces, new payer integrations, modern UX, all of it.</p>

<p>Standard advice for a monolith of that age is rip-and-replace. Standard outcome is a multi-year project that ships nothing while leadership rotates and the rewrite gets killed.</p>

<p>We didn’t do that. We picked the strangler-fig pattern. Identified the bounded contexts inside the EJB monolith that were ready to come out — usually the ones with the most volatility or the clearest data ownership boundary. Built each one as a Spring Boot microservice running alongside the legacy WebLogic/Puppet stack. Routed live traffic to the new service through a thin proxy that fell back to the monolith on failure. Validated for two weeks per service. Then peeled it off the monolith. Repeat.</p>

<p>Five-person team. The React rewrite of the HRCommand UI shipped on Figma-to-code component delivery, so design and engineering were never out of sync on what was being built. We never broke production. We never took the platform down for a release. We did decompose enough of the monolith — and ship enough new product surface on top of the new architecture — that the company became attractive to acquirers in a way it hadn’t been before.</p>

<p><strong>UnitedHealth / Optum Financial acquired Connect Your Care in 2021.</strong> The architecture work was a direct contributor to the acquisition thesis. That’s the part of this story I’m proudest of, and the part I’d repeat if I had a stable, profitable platform that needed to be modernized without being broken.</p>

<p><strong>Tech:</strong> Spring Boot, J2EE/EJB, WebLogic, Puppet, React, Figma-to-code
<strong>Outcome:</strong> Modernized core product platform without downtime; contributed to UnitedHealth/Optum Financial acquisition</p>

<hr />

<p>If you’re working on something with the same shape and want to talk it through, I’m at <a href="mailto:Dominick.do.Campbell@gmail.com">Dominick.do.Campbell@gmail.com</a>, or <a href="https://www.linkedin.com/in/dominick-campbell-70b3619b/">LinkedIn</a>.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Engineering" /><category term="AI" /><category term="Case Studies" /><category term="case studies" /><category term="production" /><category term="ai" /><category term="patents" /><category term="tax tech" /><category term="fintech" /><category term="architecture" /><summary type="html"><![CDATA[Five production systems from the last decade. Patents, platform rewrites, fraud prevention at scale. Each one shipped, each one moved a number that mattered.]]></summary></entry><entry><title type="html">25 Years In, Here’s What I Actually Know About Building Systems</title><link href="https://ethos71.github.io/engineering/2026/04/29/25-years-what-i-know.html" rel="alternate" type="text/html" title="25 Years In, Here’s What I Actually Know About Building Systems" /><published>2026-04-29T00:00:00-04:00</published><updated>2026-04-29T00:00:00-04:00</updated><id>https://ethos71.github.io/engineering/2026/04/29/25-years-what-i-know</id><content type="html" xml:base="https://ethos71.github.io/engineering/2026/04/29/25-years-what-i-know.html"><![CDATA[<p>I started writing software professionally when <code class="language-plaintext highlighter-rouge">Y2K</code> was a genuine existential threat and COBOL was
a sensible career choice. I’ve since shipped systems in Java, JavaScript, Python, C#, COBOL,
and things I’d rather not admit to in polite company.</p>

<p>Nine jobs, mainframe to AI. A handful of things have held true across all of them. None of them are
in the architecture books.</p>

<pre><code class="language-mermaid">graph LR
    M[Mainframe] --&gt; J[J2EE]
    J --&gt; S[Microservices]
    S --&gt; C[Cloud]
    C --&gt; A[AI]
</code></pre>
<p><em>Figure: every era. Same fundamentals underneath.</em></p>

<h2 id="1-the-database-outlives-everything">1. The database outlives everything</h2>

<p>You will rewrite the application 4 times. The schema you shipped in 2008 will still be there in
2026, quietly haunting every new engineer who joins the team. I’ve watched it happen on Oracle, on
DB2 over an IBM AS/400, on Postgres, on Snowflake. Different decade, same schema, different
application sitting on top of it.</p>

<p>Design the data model like it’s permanent. It basically is.</p>

<h2 id="2-observability-is-a-feature-not-a-tax">2. Observability is a feature, not a tax</h2>

<p>Every system I’ve seen fail catastrophically failed silently first. The tax close pipeline at
Vertex processing 50M–100M transactions a day didn’t fall over loudly. It drifted for hours
before anyone noticed. In every case I can think of, the dashboards came after the outage, when
they should have come before the launch.</p>

<p>Build the dashboards before you build the features.</p>

<h2 id="3-ai-doesnt-change-the-fundamentals-it-raises-the-stakes">3. AI doesn’t change the fundamentals, it raises the stakes</h2>

<p>I hold 4 patent-pending AI inventions now. I’ve built LLM-backed audit defense tools, a synthetic
data generator, and a multi-agent SDLC system. The most important thing I’ve learned from any of it:</p>

<p class="notice--info"><strong>AI doesn’t eliminate the need for good system design. It punishes bad system design faster.</strong></p>

<p>A traditional service with a weak design degrades. An AI service with a weak design starts inventing
answers, and it sounds confident doing it.</p>

<h2 id="4-the-best-engineers-ive-met-are-fundamentally-teachers">4. The best engineers I’ve met are fundamentally teachers</h2>

<p>At Vertex I built and delivered the “Raise the Boats” curriculum: 200+ engineers and analysts
through the program, ~50 through the live cohort I taught myself. The engineers who treated
teaching as overhead were the same ones whose systems left with them when they left the company.</p>

<h2 id="5-every-great-product-ive-shipped-had-a-clear-owner">5. Every great product I’ve shipped had a clear owner</h2>

<p>HRCommand at Connect Your Care drove the Optum acquisition because one architect owned the
EJB-to-Spring-Boot decomposition and one team knew who was making the calls. The voice biometric
fraud system at JPMC hit 10 million accounts in three months with 1,300 opt-outs because someone
took the heat for the design and stayed with it. Committees come later, after the thing already
works.</p>

<hr />

<p>Twenty-five years and the lessons keep coming from the same place: the data, the boring dashboards,
the person who owns the thing. If any of this lands, find me on
<a href="https://www.linkedin.com/in/dominick-campbell-70b3619b/">LinkedIn</a> or
<a href="https://github.com/ethos71">GitHub</a>.</p>

<p>More soon.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Engineering" /><category term="career" /><category term="architecture" /><category term="AI" /><category term="leadership" /><summary type="html"><![CDATA[After 25+ years shipping systems from COBOL mainframes to AI agents, here's the unvarnished truth about what makes software last — and what kills it.]]></summary></entry><entry><title type="html">What a Senior Engineer’s Job Search Actually Looks Like in 2026</title><link href="https://ethos71.github.io/career/2026/04/24/senior-engineer-job-search-2026.html" rel="alternate" type="text/html" title="What a Senior Engineer’s Job Search Actually Looks Like in 2026" /><published>2026-04-24T00:00:00-04:00</published><updated>2026-04-24T00:00:00-04:00</updated><id>https://ethos71.github.io/career/2026/04/24/senior-engineer-job-search-2026</id><content type="html" xml:base="https://ethos71.github.io/career/2026/04/24/senior-engineer-job-search-2026.html"><![CDATA[<p>I’m between roles for the first time since 2022. Four years off this side of the table is a long time in tech, and the ground moved while I wasn’t looking.</p>

<p>I’m a Principal Engineer with 25+ years of experience and four patent-pending AI inventions, and I’m still relearning how to do this. A few things from the first few weeks.</p>

<pre><code class="language-mermaid">graph LR
    A[Apply] --&gt; S[Recruiter screen]
    S --&gt; H[Hiring manager]
    H --&gt; T[Technical loop]
    T --&gt; O[Offer]
    T -.most candidates exit here.-&gt; X[No]
</code></pre>
<p><em>Figure: the senior-engineer funnel — and where it actually filters.</em></p>

<h2 id="the-ats-problem-is-worse-than-you-think">The ATS problem is worse than you think</h2>

<p>I knew ATS (Applicant Tracking Systems) existed. I didn’t appreciate how aggressively they filter until I started testing my own resume against job descriptions.</p>

<p>If your resume isn’t formatted for machine parsing, a human may never read it. I rebuilt mine from scratch in LaTeX to get clean pdftotext output, and good thing. My original version had a font artifact: the small-caps rendering was mapping the letter ‘I’ in “Principal” to a lowercase glyph in the extracted text. ATS was reading “PRiNCiPAL ENGiNEER.” Nobody told me. I caught it because I checked.</p>

<p>Run <code class="language-plaintext highlighter-rouge">pdftotext</code> on your resume and read what it outputs. That’s what the system sees.</p>

<h2 id="the-ai-will-take-your-job-narrative-is-backwards-for-senior-engineers-right-now">The “AI will take your job” narrative is backwards for senior engineers right now</h2>

<p>The engineers getting squeezed by AI are the ones who were doing work that was always a bit mechanical: boilerplate CRUD apps, basic data pipelines, junior ticket work. That’s real, and I’m not dismissing it.</p>

<p>But for senior engineers who can architect a system, weigh the tradeoffs, and lead a team through an ambiguous problem, the demand is higher than I expected. Companies are building AI products faster than they can find people who know how to build them responsibly.</p>

<p>The principal and staff descriptions I’m seeing ask for multi-agent system design, LLM observability, and the reliability patterns that keep an AI transformation from blowing up in production. Narrow pool. I happen to be in it.</p>

<h2 id="the-conversation-thats-changed">The conversation that’s changed</h2>

<p>In 2022, most senior technical interviews were about system design: scale, tradeoffs, distributed systems. That’s still there. Now there’s an overlay.</p>

<p><em>How would you AI-enable this?</em> shows up everywhere. Fine question. What’s telling is how wildly the interviewers vary in their own understanding. Some are genuinely sophisticated. Some are fishing to see whether you’ll bolt an LLM onto everything, which is the answer they’re hoping you won’t give.</p>

<p>So be honest about what AI is good at and where it falls down. The interviewers who matter respect that more than enthusiasm without nuance.</p>

<h2 id="what-im-looking-for">What I’m looking for</h2>

<p>I want to build something real. Not a proof-of-concept, not an “AI strategy” document, but a production system that solves a hard problem for people who need it solved.</p>

<p>I know tax, compliance, and fintech. I’m open to any technically hard problem where the stakes are real and the team is serious.</p>

<p>If that’s you, <a href="https://www.linkedin.com/in/dominick-campbell-70b3619b/">find me on LinkedIn</a>.</p>

<p>More soon.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="Career" /><category term="job search" /><category term="senior engineer" /><category term="AI" /><category term="hiring" /><summary type="html"><![CDATA[I'm between roles after four years at Vertex. Here's what's the same, what's completely different, and what I wish someone had told me before I started.]]></summary></entry><entry><title type="html">The Agentic AI Hype Is Real. The Timelines Are Not.</title><link href="https://ethos71.github.io/ai/2026/04/08/agentic-ai-hype-is-real-timelines-are-not.html" rel="alternate" type="text/html" title="The Agentic AI Hype Is Real. The Timelines Are Not." /><published>2026-04-08T00:00:00-04:00</published><updated>2026-04-08T00:00:00-04:00</updated><id>https://ethos71.github.io/ai/2026/04/08/agentic-ai-hype-is-real-timelines-are-not</id><content type="html" xml:base="https://ethos71.github.io/ai/2026/04/08/agentic-ai-hype-is-real-timelines-are-not.html"><![CDATA[<p>The last three years of my working life have been multi-agent systems in production. crewAI, AutoGen, LangChain, LangGraph — I’ve shipped against all of them, watched all of them break, and patched all of them at 11pm. Four patent-pending AI inventions came out of that stretch. I’m not standing in the way of the freight train.</p>

<p>So this isn’t a bubble post. It’s a post about how fast it’s actually moving, because the keynote version and the 11pm version are not the same conversation.</p>

<pre><code class="language-mermaid">graph LR
    I[Inflated&lt;br/&gt;expectations] --&gt; D[Disillusionment]
    D --&gt; P[Productivity&lt;br/&gt;plateau]
    P --&gt; V[Real value]
</code></pre>
<p><em>Figure: agentic AI follows the curve — the value at the end is real; the timeline isn’t.</em></p>

<h2 id="the-capability-is-there">The capability is there</h2>

<p>The foundation models are good. GPT-4-class models reason across multi-step problems, synthesize large document sets, write production code, chain tool calls in ways that would have looked like science fiction five years ago when I was still doing AWS Solutions Architect study cards on a Sunday morning. crewAI matured. AutoGen matured. LangGraph gives you proper state management for non-trivial flows, which the early versions absolutely did not.</p>

<p>If you want an agent that researches a topic, drafts a report, validates sources, and formats the output — that works today. Genuinely. I’ve watched a non-engineer at Vertex build a RAG over an audit knowledge base in four hours during a workshop I taught, and that workshop is part of why ~200 employees got trained on this stuff in two years. The capability floor has fallen far enough that the bottleneck is no longer “can the model do it.” It’s “do you know what to ask it to do.”</p>

<h2 id="where-the-production-version-diverges">Where the production version diverges</h2>

<p>The keynote demos show the agent <em>taking action</em> — submitting filings, modifying records, moving money. In tax, finance, and healthcare, you cannot let an agent autonomously do any of those without a verification layer in front of it. The reason is the legal and operational reality of regulated domains, not a hole in what the model can do. Build for human-in-the-loop by default, not as the thing you bolt on after compliance asks.</p>

<p>Reliability is the second thing the demos don’t show. A single agent call has maybe a 2–3% failure rate on a complex task — hallucination, tool error, context-window weirdness. Chain five and that compounds into something nobody wants to look at on a Monday. You need retry logic, fallback paths, observable failure states. The pretty demos have none of it, which is why they don’t survive contact with a real workload.</p>

<p>Context windows are the third. Yes, they’re huge now. Large context is not the same as <em>coherent</em> context. I’ve watched 128K-window models quietly forget early constraints around the 90K-token mark, with no warning and a confidence score that looks identical to the runs that didn’t forget. Chunk and retrieve. Don’t stuff the window and hope.</p>

<h2 id="the-shape-that-holds-up">The shape that holds up</h2>

<p>Small agents with clear contracts. Not one big orchestrator trying to be everything — a pipeline of focused agents, each with one job, explicit inputs and outputs, and its own observability. Closer to microservices than monoliths. I’ve watched both shapes ship and only one of them is still running.</p>

<p>Prompts are code. Version them, test them, review them before they go to production. I’ve seen production incidents that traced back to a prompt edit nobody reviewed because it was “just text.” Treat them like the load-bearing strings they are.</p>

<p>The companies that win this cycle won’t be the ones with the most impressive demos. They’ll be the ones who figured out how to run agents reliably, observably, and safely at the scale a real business needs. That’s an engineering problem, and engineers who’ve been doing this for a few years right now have a real edge. I’d rather spend that edge building things that work than shipping a demo that hallucinates a tax filing.</p>

<p>More soon.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="AI" /><category term="agents" /><category term="architecture" /><category term="LLMs" /><category term="production" /><summary type="html"><![CDATA[Everyone is shipping 'AI agents' right now. Having actually built them in production for three years, I have some thoughts on what's real and what's going to hurt people.]]></summary></entry><entry><title type="html">I Ran the AI Curiosity Workshop at Vertex. Here’s What I Learned.</title><link href="https://ethos71.github.io/ai/leadership/2026/03/18/teaching-200-people-to-build-ai-agents.html" rel="alternate" type="text/html" title="I Ran the AI Curiosity Workshop at Vertex. Here’s What I Learned." /><published>2026-03-18T00:00:00-04:00</published><updated>2026-03-18T00:00:00-04:00</updated><id>https://ethos71.github.io/ai/leadership/2026/03/18/teaching-200-people-to-build-ai-agents</id><content type="html" xml:base="https://ethos71.github.io/ai/leadership/2026/03/18/teaching-200-people-to-build-ai-agents.html"><![CDATA[<p>Four hours in, an analyst with no Python background shipped a working RAG tool over our internal audit knowledge base. It pre-drafted answers to the questions her team got asked most often. She had never written a line of Python before that morning.</p>

<p>That was week two. The moment I knew the curriculum worked.</p>

<p>By the time we wrapped, 200+ Vertex employees across engineering, product, data science, and finance had been through the <strong>AI Curiosity Workshop</strong> — internally called “Raise the Boats.” About 50 came through the live cohort I taught. The rest worked through the curriculum around it.</p>

<pre><code class="language-mermaid">graph TB
    W[Workshop&lt;br/&gt;graduates] --&gt; R[Higher waterline]
    R --&gt; T[Team operating&lt;br/&gt;higher]
</code></pre>
<p><em>Figure: what “raise the boats” means in practice.</em></p>

<h2 id="where-the-framing-kept-failing">Where the framing kept failing</h2>

<p>Most of the engineers I worked with at Vertex are sharp. So I assumed the early sessions would land. They didn’t. I opened with how transformers work, with token windows, with embeddings. People nodded politely and walked out unable to picture what they would actually <em>do</em> with one of these things on Monday morning.</p>

<p>The shift came when I rewrote the opener. Instead of starting with the machinery, I started by asking what each person hated about their week. The thing they avoided. The thing that made them want to throw their laptop.</p>

<p>Then we built something that handled that. The analyst’s audit RAG was one of those. So was a product manager chaining three tools together to triage a support backlog she’d been staring at for months. So was the data analyst who got tired of waiting on engineering and shipped her own first prompt template by Wednesday.</p>

<p>The framework was never the barrier. Permission to imagine was.</p>

<h2 id="what-i-told-them-worked-and-what-didnt">What I told them worked, and what didn’t</h2>

<p>We used crewAI and AutoGen heavily. Both are solid. The honest cut between what shipped to production and what looked great in a demo:</p>

<p>What works in production:</p>

<ul>
  <li>Multi-agent pipelines for research and synthesis (summarize, validate, format)</li>
  <li>RAG over structured internal data — policies, audit histories, transaction logs</li>
  <li>Code review and doc-quality tooling</li>
</ul>

<p>What doesn’t, yet:</p>

<ul>
  <li>Fully autonomous decisions on anything with financial consequence</li>
  <li>Agents that “just handle it” with no human-in-the-loop step somewhere</li>
  <li>Anything where the failure mode is silent</li>
</ul>

<p>That last one is the bit I hammered on every session. A traditional service throws a 500. An agent confidently gives you a wrong answer with excellent grammar. Those aren’t the same failure mode and they don’t get caught by the same monitoring.</p>

<h2 id="the-unexpected-win">The unexpected win</h2>

<p>The best outcome wasn’t the tools people built. It was the language they started using.</p>

<p>Teams began having different conversations. Instead of “we need a developer to build a script for this,” it was “can we agent this?” Product managers were writing prompt templates. Finance analysts were chaining tools together. The vocabulary changed, and what felt possible to ask for changed with it.</p>

<p>That’s what the name actually meant. Not everyone becomes an ML engineer. The whole team operates at a higher waterline.</p>

<p>Back to work.</p>]]></content><author><name>Dominick A. Campbell</name><email>Dominick.do.Campbell@gmail.com</email></author><category term="AI" /><category term="Leadership" /><category term="agents" /><category term="teaching" /><category term="crewai" /><category term="autogen" /><summary type="html"><![CDATA[Running the AI Curiosity Workshop — internally branded 'Raise the Boats' — at Vertex taught me more about how people actually learn AI than any framework documentation ever could.]]></summary></entry></feed>