<?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://tosinowobo.com/ai-engineering/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tosinowobo.com/" rel="alternate" type="text/html" /><updated>2026-11-02T12:38:25+00:00</updated><id>https://tosinowobo.com/ai-engineering/feed.xml</id><title type="html">Tosin Owobo</title><subtitle>Systems administrator in Calgary. Azure, Microsoft 365 and the things I build.</subtitle><author><name>Tosin Owobo</name></author><entry><title type="html">Scoreline’s first weekend league: real players found what tests couldn’t</title><link href="https://tosinowobo.com/ai-engineering/2026/11/02/scoreline-first-weekend-league/" rel="alternate" type="text/html" title="Scoreline’s first weekend league: real players found what tests couldn’t" /><published>2026-11-02T00:00:00+00:00</published><updated>2026-11-02T00:00:00+00:00</updated><id>https://tosinowobo.com/ai-engineering/2026/11/02/scoreline-first-weekend-league</id><content type="html" xml:base="https://tosinowobo.com/ai-engineering/2026/11/02/scoreline-first-weekend-league/"><![CDATA[<p>This week <a href="https://scoreline.tosinowobo.com">Scoreline</a> went live. It’s the app I’ve been building with Claude to run FC 27 leagues and tournaments with friends. On the weekend we ran our first real league on it: <strong>8 players</strong>, real fixtures and a real deadline.</p>

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

<p>Before the weekend I added a new league format. Instead of me entering everyone’s results, each player records their own score before the deadline, and the other player confirms it. If there’s a disagreement, the organiser has the final say.</p>

<p>It all worked in testing. Then real people started using it.</p>

<p>Here’s the table as it stands. Names are hidden apart from mine, and you can see I’m not winning my own league:</p>

<figure class="post-figure">
  <img src="/assets/img/posts/scoreline-standings.png" alt="Scoreline league table with 8 players. Player 1 and Player 2 lead on 24 points; Teeowo is 6th on 3 points." width="902" height="528" loading="lazy" />
  <figcaption>The live league table on Scoreline. Other players' names are redacted.</figcaption>
</figure>

<h2 id="what-the-players-showed-me">What the players showed me</h2>

<p>You only learn some things when people are actually trying to get their game recorded before the deadline. Over the weekend players found a few bugs, and, more usefully, the spots where the app slowed them down. Some examples:</p>

<ul>
  <li><strong>Recording a game asked for too much.</strong> Now it just asks for the score.</li>
  <li><strong>Typing in scores was a chore.</strong> Now you can take a photo of the result on your screen and the app reads it.</li>
  <li><strong>A few features got in the way.</strong> I removed them. If something doesn’t help someone record a result, it doesn’t need to be on the screen.</li>
  <li><strong>People weren’t sure how long they had.</strong> The league page now says it plainly, like <em>“Ends tonight, 11:59 PM (21h left)”</em>, and the colour changes as the deadline gets close.</li>
  <li><strong>Almost everyone was on their phone.</strong> So I went through every screen on a phone: bigger buttons, long names that don’t break the layout, and your next game always easy to find.</li>
</ul>

<h2 id="fixing-data-in-the-database">Fixing data in the database</h2>

<p>Not every fix was on the screen. A few players had problems with the email addresses on their accounts, and they had to be corrected in the database itself.</p>

<p>This was my favourite part of the week. I described what needed to change, and Opus wrote the SQL scripts to find the affected accounts and update them. The scripts were clean and careful, and easy to read and check before running. It took me back to my time at SAIT, writing database scripts to pull information out and update records. I really enjoyed that work then, and I enjoyed it again here.</p>

<h2 id="fast-fixes-nothing-broken">Fast fixes, nothing broken</h2>

<p>Most fixes went out the same day the problem showed up. That only works because Scoreline has automatic checks: before anything goes live, the app is built and tested from scratch, including the main things a player does. If something breaks, it doesn’t ship.</p>

<p>Over the weekend I pushed thirteen updates, and <strong>none of them broke anything that already worked</strong>.</p>

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

<ul>
  <li><strong>Real users beat any amount of testing.</strong> Eight friends in one weekend found more friction than all my own testing, because they were trying to get something done, not trying the app out.</li>
  <li><strong>Fast is only good if it’s safe.</strong> Claude makes fixes quick to write. The automatic checks are what made me comfortable shipping in the middle of a live league.</li>
  <li><strong>Old skills still count.</strong> The SQL work reminded me that what I learned at SAIT still matters. It’s just faster now, with Claude doing the typing and me checking the logic.</li>
</ul>

<h2 id="next-week">Next week</h2>

<ul>
  <li>Run a second league and see how it goes when I’m not watching every game.</li>
  <li>Keep improving the score recording, based on what the players tell me.</li>
</ul>]]></content><author><name>Tosin Owobo</name></author><category term="Claude Code" /><category term="Production" /><category term="UX" /><category term="SQL" /><summary type="html"><![CDATA[This week Scoreline went live. It’s the app I’ve been building with Claude to run FC 27 leagues and tournaments with friends. On the weekend we ran our first real league on it: 8 players, real fixtures and a real deadline.]]></summary></entry><entry><title type="html">Teaching an agent to watch video, and keeping humans on the judgement calls</title><link href="https://tosinowobo.com/ai-engineering/2026/10/30/teaching-an-agent-to-watch-video/" rel="alternate" type="text/html" title="Teaching an agent to watch video, and keeping humans on the judgement calls" /><published>2026-10-30T00:00:00+00:00</published><updated>2026-10-30T00:00:00+00:00</updated><id>https://tosinowobo.com/ai-engineering/2026/10/30/teaching-an-agent-to-watch-video</id><content type="html" xml:base="https://tosinowobo.com/ai-engineering/2026/10/30/teaching-an-agent-to-watch-video/"><![CDATA[<p>This is the first entry in a weekly log of what I’m building and learning with AI. Two threads this week: a toolchain that lets an AI agent “watch” a video and prove what it saw, and a game build run almost entirely through AI agents, with review gates in the right places.</p>

<h2 id="teaching-an-agent-to-watch-video">Teaching an agent to watch video</h2>

<p>Agents are good at text and bad at video. I want mine to be able to watch a tutorial or one of my own explainers and come back with notes I can trust, so I built a small toolchain for it.</p>

<p>A run goes like this:</p>

<ol>
  <li><strong>An advisor picks the mode.</strong> Before spending anything, it recommends how to watch the video (transcript only, frames only, or a full video model) and estimates the cost.</li>
  <li><strong>Gemini watches the full video</strong>, while the toolchain pulls the transcript and extracts frames at 1024px.</li>
  <li><strong>Everything lands in an evidence pack</strong>: the model’s claims, the transcript and the frames, plus a checklist of claims that need checking.</li>
  <li><strong>Every claim gets a verdict</strong> against the frames and transcript: confirmed, corrected, dropped or unresolved. A <code>check</code> step has to pass, with at least 90% of the checklist resolved, before any notes get written.</li>
</ol>

<p>Here’s one real row from a run on a public <a href="https://www.youtube.com/watch?v=WMbXgtxTrBY">Cisco Packet Tracer VLAN tutorial</a>. Gemini named the switch’s trunk port correctly in its summary, then got it wrong in its step-by-step:</p>

<div class="table-scroll">
<table>
  <thead><tr><th>Gemini's claim</th><th>What the frame at 4:32 shows</th><th>Verdict</th></tr></thead>
  <tbody><tr>
    <td data-label="Gemini's claim"><code>Switch0</code> interface <code>FastEthernet0/0/5</code> set to <code>Trunk</code></td>
    <td data-label="What the frame at 4:32 shows">The config panel is titled <code>FastEthernet0/5</code>, and the IOS log reads <code>interface FastEthernet0/5</code></td>
    <td data-label="Verdict">✏️ Corrected to <code>FastEthernet0/5</code></td>
  </tr></tbody>
</table>
</div>

<p>That’s the kind of error that looks right to a reader and breaks a lab. Confirmed (✅), corrected (✏️) and dropped (❌) claims all count as resolved. Anything I can’t check either way is marked ❓ and stays in the note as a named caveat, not a fact. The 90% gate means the agent can’t write notes from a checklist that’s mostly unchecked.</p>

<p>This week I made the skill portable and added the toolchain as a git submodule to the two repos that produce my TechWithTosin videos, so the same “watch, then verify” loop runs wherever I need it.</p>

<h3 id="what-i-learned">What I learned</h3>

<p>The video model is very good at the gist and unreliable on exact strings. In testing, the details it got wrong were the ones that matter most in technical content: passwords, channel names, domain names and IP addresses. The fix wasn’t a better prompt. It was treating the model’s output as <strong>claims to verify</strong> against primary evidence (the actual frame, the actual transcript line), and refusing to write notes until enough of them were checked.</p>

<h2 id="running-a-game-milestone-with-ai-reviewers">Running a game milestone with AI reviewers</h2>

<p>I’m also building a browser-based life simulation game, and this week it moved through milestones M2.3 to M3.2 in 46 commits: a rent goal and per-profile economy, shift events that fire by seeded chance instead of on a fixed calendar, clearer feedback on every action, and a first “make it feel like a game” pass.</p>

<p>Two lines a player now sees, as examples of what “clearer feedback” meant in practice:</p>

<ul>
  <li>When a choice can’t be afforded, the card stays open and says why: <em>“Not enough to cover it yet. The other options are open.”</em></li>
  <li>The rent outlook does the maths from the game’s own payslip and fills in the real numbers: <em>“About $X by Feb 1, before bills. Gap: $Y. One more shift adds about $Z.”</em></li>
</ul>

<p>The interesting part is the process rather than the features. Each milestone follows the same loop:</p>

<ul>
  <li><strong>Plan first.</strong> An agent drafts the milestone plan before any code is written.</li>
  <li><strong>Separate reviewers.</strong> An architecture reviewer checks anything that touches the data model or save format, and an ethics reviewer pre-checks content about hardship (missed rent, losing a shift) so it’s handled with care, not played for drama.</li>
  <li><strong>I sign off on judgement calls.</strong> Sensitive content doesn’t ship until I’ve approved it, and the approved version is pinned in a test so it can’t drift later.</li>
  <li><strong>Playtest, then fix.</strong> A playtest pass on desktop and phone feeds the next round of fixes.</li>
</ul>

<h3 id="what-i-learned-1">What I learned</h3>

<p>Speed wasn’t the bottleneck. Judgement was. Agents will happily produce a week of features in a day, so the useful work moved to deciding where a human has to be in the loop and making that gate hard to skip. Pinning approved content in tests turned “I reviewed it once” into “it can’t silently change”.</p>

<h2 id="next-week">Next week</h2>

<ul>
  <li>Point the video toolchain at my own TechWithTosin episodes and use it as a QA pass before publishing.</li>
  <li>Keep pushing the AI Kubernetes troubleshooter towards something I can demo outside my laptop.</li>
</ul>]]></content><author><name>Tosin Owobo</name></author><category term="Agents" /><category term="Gemini" /><category term="Claude Code" /><category term="Verification" /><summary type="html"><![CDATA[This is the first entry in a weekly log of what I’m building and learning with AI. Two threads this week: a toolchain that lets an AI agent “watch” a video and prove what it saw, and a game build run almost entirely through AI agents, with review gates in the right places.]]></summary></entry></feed>