<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: James Sanderson</title>
    <description>The latest articles on DEV Community by James Sanderson (@jam-techcirkle).</description>
    <link>https://dev.to/jam-techcirkle</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3924233%2Fda0f94b8-9b3b-46d6-8e8d-385565e5705a.webp</url>
      <title>DEV Community: James Sanderson</title>
      <link>https://dev.to/jam-techcirkle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jam-techcirkle"/>
    <language>en</language>
    <item>
      <title>Build the Retrieval Layer Before the Sales Agent</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Mon, 07 Sep 2026 06:31:40 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/build-the-retrieval-layer-before-the-sales-agent-27h1</link>
      <guid>https://dev.to/jam-techcirkle/build-the-retrieval-layer-before-the-sales-agent-27h1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F38wk9wjud0vqr02li7k2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F38wk9wjud0vqr02li7k2.jpg" alt="Sales team reviewing pipeline data together before a client meeting" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent is the easy part. A research agent that pulls context, reasons over it, and drafts a brief is maybe two weeks of work if the context is available.&lt;/p&gt;

&lt;p&gt;The context is never available. That is the project, and it is roughly three months.&lt;/p&gt;

&lt;p&gt;Teams that invert this order build an impressive demo on curated data in week two, then spend six months discovering that production data does not resolve, does not chunk usefully, and does not have access controls the assistant can respect. Here is the build order that works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 1: Ingestion
&lt;/h2&gt;

&lt;p&gt;Connectors for CRM, email, calendar, call recordings, support, product telemetry, and billing.&lt;/p&gt;

&lt;p&gt;Design choices that matter more than they look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incremental sync with a replayable event log.&lt;/strong&gt; You will change your chunking strategy. You will change your embedding model. Both mean reprocessing everything, and you do not want to re-pull from every source API to do it. Land raw payloads first, transform downstream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserve raw payloads.&lt;/strong&gt; Whatever you discard now is what you need in month four. Storage is cheaper than a re-integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limits are the schedule.&lt;/strong&gt; CRM APIs will not let you backfill three years of activity quickly. Plan the backfill as a multi-day job with checkpointing, not a script someone runs on a Friday.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diarised transcripts, not merged text.&lt;/strong&gt; A transcript that does not distinguish the rep from the buyer is close to useless for the questions you actually want to ask. Speaker attribution is not a nice-to-have.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layer 2: Entity resolution
&lt;/h2&gt;

&lt;p&gt;This is where the schedule goes wrong, and it goes wrong for everyone.&lt;/p&gt;

&lt;p&gt;The same account is &lt;code&gt;Acme Corp&lt;/code&gt; in the CRM, &lt;code&gt;acme.com&lt;/code&gt; in product telemetry, &lt;code&gt;Acme Corporation Ltd&lt;/code&gt; in billing, and &lt;code&gt;ACME&lt;/code&gt; in the support system. The same person is a user ID, an email hash, a phone number, and a LinkedIn URL.&lt;/p&gt;

&lt;p&gt;Retrieval quality is bounded by this mapping. A brief that misses half an account's history because two records never joined is worse than no brief, because the rep trusts it.&lt;/p&gt;

&lt;p&gt;What actually helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic matching first — exact domain, verified email, external ID. Cheap, high precision, and it handles most of the volume.&lt;/li&gt;
&lt;li&gt;Probabilistic matching for the remainder, with a &lt;strong&gt;review queue rather than an auto-merge&lt;/strong&gt;. Silent bad merges are the worst failure mode here, because they surface as one customer seeing another customer's information.&lt;/li&gt;
&lt;li&gt;Watch transitive merges. A resolves to B, B resolves to C, and the A-to-C link is wrong. Cap chain depth and require higher confidence for transitive links.&lt;/li&gt;
&lt;li&gt;Persist the resolution as a graph, not as a one-off join. You will need it for privacy work too — rights requests need exactly this mapping.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layer 3: Chunking and indexing
&lt;/h2&gt;

&lt;p&gt;Generic chunking strategies perform poorly on sales data, because the semantically meaningful unit is not a fixed token window.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;call transcripts&lt;/strong&gt;, chunk by topic segment, not by turn or by token count. An objection spans several exchanges — the buyer raises it, the rep responds, the buyer clarifies. Split that across a boundary and retrieval returns half an objection, which reads as agreement.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;email threads&lt;/strong&gt;, the thread is the unit. A single message out of context is frequently misleading, especially short ones.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;CRM records&lt;/strong&gt;, generate a natural-language summary at write time and embed that alongside structured filters. Embedding a raw record dump wastes most of the context window on field names.&lt;/p&gt;

&lt;p&gt;Hybrid retrieval — semantic plus keyword — outperforms pure vector search noticeably here, because sales queries contain exact tokens that must match: competitor names, product SKUs, contract terms. Semantic similarity will happily return a passage about a different competitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 4: Access control at query time
&lt;/h2&gt;

&lt;p&gt;Non-negotiable, and much easier to build now than to add later.&lt;/p&gt;

&lt;p&gt;A rep's assistant must not surface a deal they are not entitled to see. Enterprise customers will ask about this in security review, and "the UI filters it" is not an answer, because the UI is not where the retrieval happened.&lt;/p&gt;

&lt;p&gt;Filter at the retrieval layer, before results enter the context window. Once a passage is in the prompt, it is in the answer, and no amount of instruction reliably prevents the model from using it. Post-hoc filtering of generated output is not a control.&lt;/p&gt;

&lt;p&gt;Practically: encode ACLs as metadata on every chunk and apply them as a pre-filter in the vector query, not as a post-processing step.&lt;/p&gt;

&lt;h2&gt;
  
  
  The validation gate
&lt;/h2&gt;

&lt;p&gt;Before building anything user-facing, ask the system this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What were the three most common objections in lost deals last quarter, in the buyer's own language?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If it cannot answer, do not proceed to the agent. The answer requires working transcript ingestion, correct entity resolution across CRM and calls, chunking that keeps objections intact, and retrieval that can filter by outcome and date.&lt;/p&gt;

&lt;p&gt;It is a single query that exercises every layer. Teams that pass it ship agents that work. Teams that skip it ship agents that hallucinate confidently, which is worse than shipping nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then, and only then, the agent
&lt;/h2&gt;

&lt;p&gt;Once retrieval works, the patterns come quickly: pre-call research briefs with citations, constrained outreach drafting against an approved evidence library, questionnaire response generation, deal-risk signals.&lt;/p&gt;

&lt;p&gt;Two things to carry into all of them. Every factual claim about the buyer needs a citation the rep can check in two seconds — an unsourced claim that turns out wrong costs more trust than ten correct ones earn. And log every prompt, retrieval set, and completion, because after your first model upgrade you will need to explain why quality changed.&lt;/p&gt;

&lt;p&gt;The full engineering treatment — the five production patterns, guardrails, measurement, cost ranges, and a ninety-day rollout — is here: &lt;strong&gt;&lt;a href="https://techcirkle.com/blog/generative-ai-for-sales" rel="noopener noreferrer"&gt;Generative AI for Sales: The Engineering Guide for 2026&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fay8cwamu1mo29p4kbv6e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fay8cwamu1mo29p4kbv6e.jpg" alt="Diverse business team in a working meeting reviewing account strategy" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We build these as &lt;a href="https://techcirkle.com/llm-integration" rel="noopener noreferrer"&gt;LLM integration&lt;/a&gt; and &lt;a href="https://techcirkle.com/agentic-workflow-development" rel="noopener noreferrer"&gt;agentic workflow&lt;/a&gt; engagements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why build retrieval before the agent?
&lt;/h3&gt;

&lt;p&gt;Because the agent is roughly two weeks of work and the retrieval layer is three months. Building the agent first produces a demo on curated data, followed by months of discovering that production data does not resolve, chunk, or filter the way the demo assumed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What makes entity resolution hard in sales data?
&lt;/h3&gt;

&lt;p&gt;The same account and person appear under different identifiers in every system — CRM, billing, telemetry, support. Retrieval quality is bounded by that mapping, and a silent bad merge surfaces as one customer's data appearing in another customer's context, which is a confidentiality incident rather than a quality bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  How should call transcripts be chunked for retrieval?
&lt;/h3&gt;

&lt;p&gt;By topic segment rather than by turn or fixed token count. An objection spans several exchanges — raised, answered, clarified — and splitting it across a chunk boundary returns half an objection, which frequently reads as agreement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is vector search alone enough for sales retrieval?
&lt;/h3&gt;

&lt;p&gt;No. Hybrid retrieval combining semantic and keyword search performs noticeably better, because sales queries contain exact tokens that must match — competitor names, SKUs, contract terms. Pure semantic similarity will return a passage about a different competitor.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you enforce access control in a RAG system?
&lt;/h3&gt;

&lt;p&gt;Filter at the retrieval layer, before results enter the context window, using ACL metadata as a pre-filter on the vector query. Once a passage is in the prompt it is available to the answer, and instruction-based restrictions are not a reliable control.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a good readiness test for a sales retrieval layer?
&lt;/h3&gt;

&lt;p&gt;Ask it for the three most common objections in lost deals last quarter, in the buyer's own words. Answering requires working transcript ingestion, correct entity resolution, objection-preserving chunking, and outcome filtering — one query that exercises every layer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to Delete Data From an Immutable Backup</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Mon, 07 Sep 2026 06:31:32 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/how-to-delete-data-from-an-immutable-backup-1n48</link>
      <guid>https://dev.to/jam-techcirkle/how-to-delete-data-from-an-immutable-backup-1n48</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc8nlagsraszp7tsquimk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc8nlagsraszp7tsquimk.jpg" alt="Engineer reviewing encrypted data protection controls on a laptop" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a contradiction that shows up in almost every architecture review with a privacy component.&lt;/p&gt;

&lt;p&gt;The right to erasure assumes data can be removed on request. Modern data architecture is built on the opposite assumption. Append-only event logs. Immutable object storage with object-lock enabled. Replicated backups across regions. Warehouse snapshots retained for year-over-year analysis. Derived models that encode information about individuals without storing a row.&lt;/p&gt;

&lt;p&gt;Deleting a user row from Postgres takes one statement. Deleting that user from the system takes an architecture decision you probably made three years ago without knowing it.&lt;/p&gt;

&lt;p&gt;Three patterns actually work. They are not equivalent, and the cost of picking one is almost entirely a function of &lt;em&gt;when&lt;/em&gt; you pick it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 1: Crypto-shredding
&lt;/h2&gt;

&lt;p&gt;Encrypt every subject's personal data under a key unique to that subject. Store keys in a KMS. On erasure, destroy the key.&lt;/p&gt;

&lt;p&gt;Every copy of the ciphertext — the primary database, last quarter's backup, the object-locked archive, the warehouse snapshot nobody remembers creating — becomes permanently unreadable. You did not delete the data. You deleted the ability of anyone, including you, to read it, which is functionally equivalent and vastly easier to prove.&lt;/p&gt;

&lt;p&gt;What it actually requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A per-subject key hierarchy. Typically a per-subject data key wrapped by a rotating master key, so key rotation does not mean re-encrypting everything.&lt;/li&gt;
&lt;li&gt;Envelope encryption at the field or record level, not full-disk. Disk encryption gives you nothing here — one key protecting everything means erasing one subject erases all of them.&lt;/li&gt;
&lt;li&gt;A key-destruction audit trail. The destruction event &lt;em&gt;is&lt;/em&gt; your evidence of erasure, so it must be immutable and timestamped.&lt;/li&gt;
&lt;li&gt;Query planning that survives encryption. This is the real cost: you can no longer filter or join on encrypted fields. Deterministic encryption for equality lookups helps and leaks frequency information; blind indexes are usually the better tradeoff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adopt early or regret it.&lt;/strong&gt; Greenfield, this is a week of design and mostly ordinary work. Retrofitted onto a system with ten years of plaintext personal data across forty tables, it is a multi-quarter migration where the hard part is not encryption but finding every field that needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 2: Tombstone-and-compact
&lt;/h2&gt;

&lt;p&gt;For event streams, deletion is a write, not a removal.&lt;/p&gt;

&lt;p&gt;Publish a tombstone — a null-payload record keyed to the subject — and let a compaction process physically remove prior records for that key on a defined cycle.&lt;/p&gt;

&lt;p&gt;Kafka's log compaction does exactly this natively. The failure mode is entirely operational:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compaction is not immediate. There is a window between the tombstone and physical removal, and your retention documentation needs to state it honestly rather than imply instant deletion.&lt;/li&gt;
&lt;li&gt;Every downstream consumer must handle tombstones correctly. A consumer that ignores null payloads and keeps its own materialised view has silently defeated the whole mechanism. This is worth an integration test per consumer.&lt;/li&gt;
&lt;li&gt;Topics without a compacted cleanup policy will not compact. Someone will create one. Enforce the policy in your topic provisioning code, not in a wiki page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tombstoning composes well with crypto-shredding. Shred the key for correctness and immediate unreadability; tombstone-and-compact for actual space reclamation and to keep the streams honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 3: Reference indirection
&lt;/h2&gt;

&lt;p&gt;Keep personal data in exactly one deletable store. Everywhere else — events, logs, warehouse, caches, search indices — holds only an opaque subject identifier.&lt;/p&gt;

&lt;p&gt;Erasure becomes a single operation in a single place. Every other system keeps referring to a subject ID that no longer resolves to anything, which is usually fine: your analytics still count the event, it just cannot be tied back to a person.&lt;/p&gt;

&lt;p&gt;This is architecturally the cleanest option and the one with the largest ongoing tax. Every read path that needs personal data becomes a join or a service call. Latency goes up. You will be tempted to denormalise "just this one field" into the event payload, and the moment someone does, the guarantee is gone.&lt;/p&gt;

&lt;p&gt;The mitigation is enforcement rather than discipline: schema validation in CI that rejects event definitions containing personal-data-typed fields. Make the wrong thing fail the build, because it will not fail review reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking one
&lt;/h2&gt;

&lt;p&gt;Rough decision rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Greenfield?&lt;/strong&gt; Crypto-shredding plus reference indirection. The combination is cheap now and eliminates most of the cost of every other privacy capability later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Existing system, event-stream heavy?&lt;/strong&gt; Tombstone-and-compact first, since it delivers immediate improvement, then reference indirection for new event types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Existing system, monolith and warehouse?&lt;/strong&gt; Reference indirection for new writes, crypto-shredding scoped to the highest-risk fields. A full retrofit is rarely worth it; a targeted one usually is.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The model layer, honestly
&lt;/h2&gt;

&lt;p&gt;None of these patterns cover trained models. If a model was trained on a subject's data, deleting the source record does not remove their influence on the weights. Machine unlearning research exists; production-grade machine unlearning largely does not.&lt;/p&gt;

&lt;p&gt;The currently defensible position is documented retraining cadences plus exclusion lists, stated plainly in your impact assessment. Do not claim erasure from model weights. Regulators are increasingly informed on this point, and a claim you cannot substantiate is worse than a limitation you disclosed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deletion as a tested contract
&lt;/h2&gt;

&lt;p&gt;Whichever pattern you choose, make deletion a first-class API on every service that stores personal data, and test it in CI like any other contract.&lt;/p&gt;

&lt;p&gt;A service that cannot delete becomes permanent compliance debt, and you want to discover that at merge time rather than during a rights request with a statutory deadline attached.&lt;/p&gt;

&lt;p&gt;The wider engineering context — discovery, consent enforcement, rights-request pipelines, generated registers, and where this sits in a full stack — is in the complete guide: &lt;strong&gt;&lt;a href="https://techcirkle.com/blog/gdpr-software" rel="noopener noreferrer"&gt;GDPR Software in 2026: A CTO's Build vs Buy Playbook&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdtrxsk8h9q9t61wrsjal.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdtrxsk8h9q9t61wrsjal.jpg" alt="Data protection and privacy controls illustrated across connected systems" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We build this as part of &lt;a href="https://techcirkle.com/development/custom-software-development" rel="noopener noreferrer"&gt;custom software development&lt;/a&gt; work, usually alongside the &lt;a href="https://techcirkle.com/blog/cloud-application-development-guide" rel="noopener noreferrer"&gt;cloud architecture&lt;/a&gt; decisions that constrain which pattern is even available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is crypto-shredding?
&lt;/h3&gt;

&lt;p&gt;Storing personal data encrypted under a key unique to each data subject, then destroying that key on an erasure request. Every copy of the ciphertext — including immutable backups and object-locked archives — becomes permanently unreadable without deleting or rewriting the copies themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does full-disk encryption satisfy the right to erasure?
&lt;/h3&gt;

&lt;p&gt;No. One key protecting everything means you cannot erase a single subject without destroying access to all data. Crypto-shredding requires per-subject keys with envelope encryption at field or record level.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you delete from a Kafka topic?
&lt;/h3&gt;

&lt;p&gt;Publish a tombstone — a null-payload record with the subject's key — on a topic configured for log compaction. Compaction physically removes earlier records for that key on its cycle. Verify that every downstream consumer honours tombstones, since a consumer maintaining its own materialised view will otherwise retain the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can you delete personal data from a trained machine learning model?
&lt;/h3&gt;

&lt;p&gt;Not reliably in production today. Deleting the source record does not remove its influence on the weights. The defensible approach is documented retraining cadences plus exclusion lists, disclosed as a limitation in your impact assessment rather than claimed as erasure.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the performance cost of encrypting personal data per subject?
&lt;/h3&gt;

&lt;p&gt;The encryption itself is negligible; the query cost is not. You cannot filter or join on encrypted fields directly. Deterministic encryption enables equality lookups but leaks frequency information; blind indexes are usually the better tradeoff. Budget for query redesign, not for CPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should deletion be tested in CI?
&lt;/h3&gt;

&lt;p&gt;Yes. Treat deletion as a contract on every service that stores personal data and test it like any other API contract. Services that cannot delete become permanent compliance debt, and merge time is a much cheaper moment to discover that than a rights request with a statutory deadline.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>security</category>
      <category>database</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Offline-First POS — Event Streams, Client IDs and Merging Divergent Terminals</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Wed, 02 Sep 2026 16:03:03 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/offline-first-pos-event-streams-client-ids-and-merging-divergent-terminals-g5k</link>
      <guid>https://dev.to/jam-techcirkle/offline-first-pos-event-streams-client-ids-and-merging-divergent-terminals-g5k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq9vvxjqm0gaxi8iw3b8a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq9vvxjqm0gaxi8iw3b8a.jpg" alt="Point of sale terminal at a restaurant counter" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A restaurant POS is one of the few consumer-scale products where offline operation is not a nice-to-have. The venue's network is consumer broadband shared with a card terminal and a guest wi-fi network, and it will fail during service. When it does, the software has to keep taking orders and firing tickets or the business physically stops.&lt;/p&gt;

&lt;p&gt;This post covers the concrete architecture: what lives locally, how identifiers work, how divergent terminals merge, and which operations genuinely cannot be merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first writes
&lt;/h2&gt;

&lt;p&gt;The terminal holds a local database containing the current menu, open checks, the session's orders, and an outbound operation queue.&lt;/p&gt;

&lt;p&gt;Every user action writes locally and synchronously. Nothing in the interaction path waits on a network call — an action that blocks on a round trip is a defect that will be discovered at peak service, when a queue of actual people is forming.&lt;/p&gt;

&lt;p&gt;Synchronisation is a background process reading the outbound queue and reconciling with the server. It has no bearing on whether the user can proceed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-generated identifiers
&lt;/h2&gt;

&lt;p&gt;All identifiers are generated on the terminal. Universally unique values, never server-assigned sequences.&lt;/p&gt;

&lt;p&gt;This matters more than it first appears. A server-assigned identifier means an order created offline has no identity until it syncs, so every local reference is provisional and must be rewritten afterwards. Every relationship becomes a two-phase problem, and the bugs that result are subtle and hard to reproduce.&lt;/p&gt;

&lt;p&gt;Client generation makes an offline-created order a first-class entity from the moment it exists. Human-facing order numbers can still be assigned per-venue per-day locally, with a terminal prefix to avoid collisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checks as operation streams, not documents
&lt;/h2&gt;

&lt;p&gt;Here is the core modelling decision.&lt;/p&gt;

&lt;p&gt;Do not represent a check as a mutable document that terminals overwrite. Represent it as an append-only sequence of operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ id, checkId, terminalId, seq, ts, type: 'ADD_ITEM',    payload: { itemId, qty, seat, modifiers } }
{ id, checkId, terminalId, seq, ts, type: 'VOID_ITEM',   payload: { lineId, reason } }
{ id, checkId, terminalId, seq, ts, type: 'APPLY_DISCOUNT', payload: { ... } }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current state of a check is a fold over its operations. Two terminals that diverged offline are merged by unioning their streams and replaying, which is commutative for most operation types.&lt;/p&gt;

&lt;p&gt;Compare this with the naive approach. Last-write-wins on a whole check produces a specific, expensive bug: the bar terminal added a drink, the till voided a starter, and whichever version arrives second silently discards the other terminal's work. One direction is uncharged revenue; the other is a customer billed for something they sent back. Both destroy operator trust faster than nearly any other defect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7zzf11aeu9tsuwudvaq2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7zzf11aeu9tsuwudvaq2.jpg" alt="Restaurant manager with a payment terminal" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Operations that cannot be merged
&lt;/h2&gt;

&lt;p&gt;A small set genuinely requires arbitration, and it is better to be explicit than to pretend otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Settling a check.&lt;/strong&gt; Two terminals settling concurrently must not both succeed. This requires a server round trip, or a venue-local coordinator when the cloud is unreachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voiding an item already served.&lt;/strong&gt; A void that arrives after the kitchen has fired and served the item is a business decision, not a data merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything with an external side effect&lt;/strong&gt; — refund issued, loyalty points redeemed — where reversing costs real money.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Define this list explicitly, surface the requirement in the interface, and design the fallback deliberately. Telling a server that payment needs connectivity is much better than allowing two payments to land and reconciling through support tickets a week later.&lt;/p&gt;

&lt;p&gt;Visible failure beats silent failure in this environment. Staff need to know the terminal is offline and orders are queued; ambiguity produces double-fired tickets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The local real-time layer
&lt;/h2&gt;

&lt;p&gt;Kitchen displays are a local problem, not a cloud one. A fired course needs to appear on the correct station within about a second.&lt;/p&gt;

&lt;p&gt;Terminals and kitchen screens on the same venue network should communicate directly, with the cloud as a synchronisation channel rather than as the message bus. Routing a ticket from a till to a screen four metres away via a remote data centre is one dropped connection away from a service failure, and that is a design choice rather than bad luck.&lt;/p&gt;

&lt;p&gt;Also budget for printers. Every venue has thermal printers, and escape codes, network discovery, per-model quirks and paper-out handling form a deeper body of work than anyone plans for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data model decision that matters later
&lt;/h2&gt;

&lt;p&gt;Store operations, not summaries. Item-level, timestamped, with modifiers and voids preserved rather than collapsed into settled totals.&lt;/p&gt;

&lt;p&gt;The reason is that the highest-value features arrive later and all depend on this history: demand forecasting at item level to drive prep and ordering, labour scheduling derived from those forecasts, and anomaly detection on voids and discounts. A team that stores only check totals has thrown away the input those features require, and it cannot be reconstructed.&lt;/p&gt;

&lt;p&gt;This is the single cheapest decision to make correctly in week three and the most expensive to regret in year two. More on the applied-model side in our work on &lt;a href="https://techcirkle.com/ai-development-services" rel="noopener noreferrer"&gt;AI development services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Full build guide covering the domain model, modifier design, payments, tenancy, hardware and costs: &lt;a href="https://techcirkle.com/blog/cloud-based-restaurant-pos-systems" rel="noopener noreferrer"&gt;Cloud Based Restaurant POS Systems: The 2026 Build Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is this just event sourcing?
&lt;/h3&gt;

&lt;p&gt;It shares the mechanism but applies it locally for a specific reason: enabling deterministic merges between devices that diverged without coordination. You do not need a full event-sourced backend to benefit — the operation stream can be a local concern that projects into conventional server-side storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  What storage should the terminal use?
&lt;/h3&gt;

&lt;p&gt;Anything durable with transactional writes and reasonable query support — SQLite on native platforms, IndexedDB in the browser. What matters far more than the choice is that writes are synchronous from the user's perspective and never block on the network.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you handle clock skew between terminals?
&lt;/h3&gt;

&lt;p&gt;Do not rely on wall-clock time for ordering. Use per-terminal sequence numbers plus a logical clock, keeping timestamps for display and audit only. Terminal clocks drift, and merges that depend on them produce non-deterministic results.&lt;/p&gt;

&lt;h3&gt;
  
  
  How large can an operation stream get before it needs compaction?
&lt;/h3&gt;

&lt;p&gt;A single check rarely exceeds a few dozen operations, so per-check folding is trivial. Compaction matters at the venue-day level for archival — snapshot the settled state and retain the operation history separately, keeping it rather than discarding it, since it is the input to later analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if a terminal is offline for days?
&lt;/h3&gt;

&lt;p&gt;Bound it. Define a maximum divergence window, typically a single service day, after which the terminal requires reconciliation before accepting new work. Unbounded divergence produces merges nobody can reason about and staff cannot explain to a customer.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>offlinefirst</category>
      <category>distributedsystems</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Seven Technical Questions I Ask Every Fintech Development Agency</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Wed, 02 Sep 2026 16:00:02 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/seven-technical-questions-i-ask-every-fintech-development-agency-2mg9</link>
      <guid>https://dev.to/jam-techcirkle/seven-technical-questions-i-ask-every-fintech-development-agency-2mg9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60ljcueh97zc8bw47cne.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F60ljcueh97zc8bw47cne.jpg" alt="Fintech digital banking and payments technology" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every agency has a fintech case study now, because almost every app touches money somewhere. That makes portfolios close to useless as a filter. What does work is a twenty-minute technical conversation with the engineers who would actually do the build — not the account team — built around questions that cannot be answered from a sales script.&lt;/p&gt;

&lt;p&gt;Here are the seven I use, and what the answers tell you.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. How do you represent money?
&lt;/h2&gt;

&lt;p&gt;The correct answers are minor units as integers, or a fixed-scale decimal type, with a reason attached. What you are listening for is whether they have opinions about rounding, about where currency conversion happens, and about how fees are represented relative to the principal amount.&lt;/p&gt;

&lt;p&gt;Floating point ends the conversation. It sounds obvious. It still shows up.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A payment succeeds at the provider and your service times out before recording it. What happens?
&lt;/h2&gt;

&lt;p&gt;This is the single best question on the list because there is no way to answer it plausibly without having lived through it.&lt;/p&gt;

&lt;p&gt;The answer you want includes an idempotency key generated before the outbound call, a persisted intent record written before the request rather than after the response, a reconciliation job that reads the provider's settlement file and closes the gap, and a bounded window with alerting for anything unresolved.&lt;/p&gt;

&lt;p&gt;The answer you do not want is any variation on retry logic alone. Retry without idempotency is how duplicate charges happen, and it happens precisely under the network conditions you have no control over.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. How does a support agent correct a wrong transaction?
&lt;/h2&gt;

&lt;p&gt;If the answer involves updating a row, they have not operated a regulated system.&lt;/p&gt;

&lt;p&gt;The correct pattern is a compensating entry: a new record that reverses the effect of the original while leaving the original intact and linked. The original transaction remains queryable forever. The correction has its own actor, timestamp and reason code.&lt;/p&gt;

&lt;p&gt;This matters because destructive corrections are invisible in aggregate and catastrophic in an audit. You cannot explain a balance whose history has been edited.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Where does the ledger live, and is the balance stored or derived?
&lt;/h2&gt;

&lt;p&gt;There are several defensible architectures — ledger inside the service, ledger as a separate service, ledger as an event-sourced projection. Having no view is not defensible.&lt;/p&gt;

&lt;p&gt;The property to insist on is that balances are derivable from immutable double-entry records. Storing a balance as a cache is fine. Storing it as the truth is not, because it means a lost update is silently permanent.&lt;/p&gt;

&lt;p&gt;Watch specifically for how they handle the gap between authorisation and capture, and how a currency conversion produces entries. Naive designs fall apart at both.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9o0iwh2acuo5py4z38j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9o0iwh2acuo5py4z38j.jpg" alt="Mobile financial technology and secure payments" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Which parts of PCI scope do you keep, and which do you push out?
&lt;/h2&gt;

&lt;p&gt;The right answer draws a boundary. Tokenising provider or semi-integrated terminal handles card data; your application never sees a PAN; your scope collapses to a much smaller self-assessment.&lt;/p&gt;

&lt;p&gt;Teams who cannot draw that boundary on request will discover it during an assessment, at which point moving it is a refactor rather than a design choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. How do you test a risk or fraud model before it goes live, and how do you roll it back?
&lt;/h2&gt;

&lt;p&gt;Baseline answers: shadow deployment where the new model scores traffic without acting, champion-challenger comparison on live traffic, a kill switch that reverts to the previous version or to rules alone, and stored decision records containing inputs and model version so any decision can be replayed.&lt;/p&gt;

&lt;p&gt;The follow-up is more revealing: how long would it take, in your architecture, to add a new signal to the fraud model and get it safely into production? If the answer is weeks, then during an actual attack your losses accrue for weeks.&lt;/p&gt;

&lt;p&gt;This is also the question that separates AI-as-architecture from AI-as-vendor-logo. Anyone can call a scoring API. Owning the features, versioning the model and being able to explain a decline is engineering, and it is what the &lt;a href="https://techcirkle.com/llm-integration" rel="noopener noreferrer"&gt;LLM integration&lt;/a&gt; and applied-AI side of this work actually consists of.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. What have you had to rebuild on a previous fintech project, and why?
&lt;/h2&gt;

&lt;p&gt;An engineer who has shipped will have an answer immediately, usually with some feeling attached. The most common honest answers are the ledger, the onboarding state machine, and the notification system.&lt;/p&gt;

&lt;p&gt;No answer means either not enough shipping, or not enough candour. Both are disqualifying for different reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the AI answers matter more than they used to
&lt;/h2&gt;

&lt;p&gt;The operational economics of fintech shifted over the last two years, and it is worth being precise about how. Document review, sanctions alert triage, transaction monitoring and case handling used to scale linearly with headcount. They now scale substantially with compute, provided the system is built so automated decisions carry a stored input, a model version, a confidence score and a defined escalation threshold.&lt;/p&gt;

&lt;p&gt;That is an architectural requirement, not a procurement one. A case management layer that treats model output as evidence — with a human adjudicating the flagged minority — is what turns automation into a saving rather than a compliance exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of it
&lt;/h2&gt;

&lt;p&gt;The full write-up covers how to read a fintech portfolio, ledger design in more depth, the four-part cost model, engagement structures and the proposal red flags: &lt;a href="https://techcirkle.com/blog/fintech-app-development-company" rel="noopener noreferrer"&gt;How to Choose a Fintech App Development Company in 2026&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Should these questions go to the sales team or the engineers?
&lt;/h3&gt;

&lt;p&gt;The engineers who would be assigned to your build, named in the contract. Answers from an account lead are second-hand and tell you nothing about who writes your data layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if an agency answers well but has no fintech portfolio?
&lt;/h3&gt;

&lt;p&gt;Strong answers to questions 2, 3 and 4 are worth more than a portfolio. The failure modes described in those answers only get internalised by teams who have operated systems under real conditions, whether or not the domain was labelled fintech.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is idempotency really necessary if we use a major payment provider?
&lt;/h3&gt;

&lt;p&gt;Yes. Providers give you the mechanism — idempotency keys — but nothing enforces that you use it correctly, and the failure happens on your side of the call when a response is lost. The provider's reliability does not cover your write path.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we verify a claimed audit trail?
&lt;/h3&gt;

&lt;p&gt;Ask to see a query that answers a concrete question: who accessed a specific customer record on a given date, and what changed. If the answer requires log grepping rather than a queryable event store, the audit trail is aspirational.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do we need our own ledger if the payment provider tracks balances?
&lt;/h3&gt;

&lt;p&gt;Yes. The provider records movement through their system, not your fees, holds, splits or accounting treatment. More importantly, with only one record you cannot reconcile — a discrepancy is undetectable by definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does the ledger design actually cost upfront?
&lt;/h3&gt;

&lt;p&gt;Typically a few weeks of senior engineering time in the first phase. The alternative is a four-to-six month rebuild later, run in parallel with production, reconstructing history from settlement files. The ratio is not close.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>architecture</category>
      <category>payments</category>
      <category>ai</category>
    </item>
    <item>
      <title>Modelling a Music Catalogue Without Regretting It Later</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Tue, 01 Sep 2026 16:11:18 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/modelling-a-music-catalogue-without-regretting-it-later-24e7</link>
      <guid>https://dev.to/jam-techcirkle/modelling-a-music-catalogue-without-regretting-it-later-24e7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnaw2kjvk0b8n2ngndzzr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnaw2kjvk0b8n2ngndzzr.jpg" alt="Music streaming app on a phone next to headphones" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are building anything that plays licensed music, the schema you choose in week two determines whether accurate royalty attribution is even possible. Not difficult — possible. You cannot report a split you have nowhere to store.&lt;/p&gt;

&lt;p&gt;This is a walkthrough of what breaks in the obvious model and what to do instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model everyone starts with
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tracks(id, title, artist_name, album_name, duration, audio_url, isrc)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is clean, it demos beautifully, and it fails on contact with a real catalogue. Here is the sequence, which happens in roughly this order every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3.&lt;/strong&gt; A track has three writers, one performer and a producer, all with different rights and different splits. There is one &lt;code&gt;artist_name&lt;/code&gt; column. You add &lt;code&gt;artists&lt;/code&gt; as a many-to-many and feel clever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 5.&lt;/strong&gt; The same recording arrives from a second distributor with slightly different metadata and a different local identifier. You now have two rows for one recording, and any play count you report is split across both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 7.&lt;/strong&gt; A compilation arrives. The recording already exists on its original album. Your model conflates recording with release, so you either duplicate the recording or lose the compilation context. Both are wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 9.&lt;/strong&gt; Explicit and clean versions. Different audio, same composition, sometimes the same ISRC in practice because someone was careless upstream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 12.&lt;/strong&gt; Territory restrictions differ per release, per recording and per agreement. There is no column for it, and geo-enforcement is now a client-side check somebody can bypass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 6.&lt;/strong&gt; A rights split is corrected and backdated. You have stored aggregates. You cannot recompute.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model that survives
&lt;/h2&gt;

&lt;p&gt;Separate the concepts that the industry separates. The vocabulary exists for a reason.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Work&lt;/strong&gt; — the underlying composition. Writers and publishers attach here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recording&lt;/strong&gt; — a specific performance of a work. Performers, producers and the master rights holder attach here. This is what actually gets streamed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release&lt;/strong&gt; — a package containing recordings: album, single, compilation. Territory and availability windows attach here, not to the recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributor&lt;/strong&gt; — a party with a role (&lt;code&gt;writer&lt;/code&gt;, &lt;code&gt;performer&lt;/code&gt;, &lt;code&gt;producer&lt;/code&gt;, &lt;code&gt;publisher&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;) and a &lt;em&gt;time-bounded&lt;/em&gt; rights share on a work or a recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identifier&lt;/strong&gt; — an external id (&lt;code&gt;isrc&lt;/code&gt;, &lt;code&gt;iswc&lt;/code&gt;, distributor-local) attached to a work or recording, with the source recorded, many-to-one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three properties fall out of this that you cannot get from the flat model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deduplication becomes possible.&lt;/strong&gt; Two deliveries of the same recording resolve to one recording entity with two identifier rows, rather than two competing rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribution becomes expressible.&lt;/strong&gt; A split is a relationship with a validity window, not a column that gets overwritten.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Territory lives at the right level.&lt;/strong&gt; Availability is a property of a release in a market, which is how the agreements are actually written.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2e8khp2z53s6ooznb88y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2e8khp2z53s6ooznb88y.jpg" alt="Studio mixing console" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Splits must be time-bounded
&lt;/h2&gt;

&lt;p&gt;This is the single most commonly missed detail, and it is what makes retroactive corrections survivable.&lt;/p&gt;

&lt;p&gt;Do not store a contributor share as a current value. Store it as a record with &lt;code&gt;valid_from&lt;/code&gt; and &lt;code&gt;valid_to&lt;/code&gt;. When a split is corrected and backdated, you insert a new period rather than overwriting anything, and the historical calculation for any past month remains reproducible from the data as it applied then.&lt;/p&gt;

&lt;p&gt;If you overwrite, you have silently destroyed your ability to explain a past statement. That conversation with a rights holder does not go well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events, not aggregates
&lt;/h2&gt;

&lt;p&gt;The corollary on the reporting side: plays are immutable events, and every aggregate is a derived artefact that can be rebuilt from them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;play_events(id, recording_id, user_id, started_at, ms_played,
            qualified, client, country, session_id, ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store enough to apply whatever definition of a qualifying stream your agreements specify — including one you might renegotiate later — and enough for fraud detection to distinguish genuine listening from synthetic patterns. You cannot reconstruct signal you never captured.&lt;/p&gt;

&lt;p&gt;Then every monthly statement is a function over events plus the rights model as it stood, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A backdated split correction is a recomputation, not an archaeology project&lt;/li&gt;
&lt;li&gt;Fraud identified after payout can be excluded and the period restated&lt;/li&gt;
&lt;li&gt;A disputed statement can be reproduced line by line&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Teams that store aggregates and drop raw events save a little storage and lose the ability to answer the only questions that ever really matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do not trust ISRCs to be unique.&lt;/strong&gt; They are supposed to be. In real catalogues they are not. Treat them as one identifier among several, with a source attached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model unknown contributors explicitly.&lt;/strong&gt; Deliveries arrive with missing credits constantly. A null is not the same as "we know there is a writer we cannot identify", and only one of those can be resolved later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep &lt;code&gt;qualified&lt;/code&gt; as a derived, recomputable flag,&lt;/strong&gt; not something written at ingest. The definition changes when agreements change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version the rights model itself.&lt;/strong&gt; Not just the splits — the rules for applying them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this is worth the upfront cost
&lt;/h2&gt;

&lt;p&gt;Remodelling a catalogue after launch means migrating every playlist, every recommendation index and every historical royalty record simultaneously, while continuing to report accurately throughout. It is one of the more painful migrations available in consumer software, and it is entirely avoidable by spending a fortnight on the model before writing the player.&lt;/p&gt;

&lt;p&gt;When you evaluate a build partner for this kind of product, ask to see their catalogue model and ask what happens when two distributors deliver the same recording with conflicting credits. The answer tells you whether they have ingested a real catalogue or a test fixture.&lt;/p&gt;

&lt;p&gt;Full guide, including build budgets, discovery cost economics and the questions to ask on a shortlisting call: &lt;a href="https://techcirkle.com/blog/music-streaming-app-development-company" rel="noopener noreferrer"&gt;Music Streaming App Development Company&lt;/a&gt;. Related: how we approach &lt;a href="https://techcirkle.com/development/custom-software-development" rel="noopener noreferrer"&gt;custom software development&lt;/a&gt; for systems like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is a relational database the right choice for a music catalogue?
&lt;/h3&gt;

&lt;p&gt;Generally yes for the catalogue and rights model, where relationships and constraints matter and correctness beats flexibility. Play events are usually better served by an append-only store or event log, with aggregates materialised into whatever your reporting layer queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I dedupe recordings arriving from multiple distributors?
&lt;/h3&gt;

&lt;p&gt;Match on identifiers first, then fall back to fuzzy matching on title, contributors and duration, with a human review queue for anything below a confidence threshold. Store every source identifier rather than picking a winner, so a bad merge is reversible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should territory restrictions live on the recording or the release?
&lt;/h3&gt;

&lt;p&gt;On the release, in almost all cases, because that is how agreements are written. A recording can be available in one market on one release and unavailable there on another.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the minimum I should capture in a play event?
&lt;/h3&gt;

&lt;p&gt;Recording, user, start time, duration played, client, country, session, and enough context to apply a qualifying-stream rule you might change later. Fraud detection needs pattern signal too, so do not sample aggressively.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I handle a split correction backdated a year?
&lt;/h3&gt;

&lt;p&gt;Insert a new time-bounded split period rather than updating the existing one, then recompute affected statements from play events. This only works if you never overwrote history and never discarded the events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need this level of rigour for a small niche platform?
&lt;/h3&gt;

&lt;p&gt;The catalogue and rights model, yes, because the cost of getting it wrong scales with how long you run rather than how large you are. Discovery sophistication and platform tooling can absolutely wait.&lt;/p&gt;

</description>
      <category>database</category>
      <category>architecture</category>
      <category>backend</category>
      <category>datamodelling</category>
    </item>
    <item>
      <title>Five Interview Questions That Separate AI Engineers From Demo Builders</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Tue, 01 Sep 2026 16:09:58 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/five-interview-questions-that-separate-ai-engineers-from-demo-builders-58j8</link>
      <guid>https://dev.to/jam-techcirkle/five-interview-questions-that-separate-ai-engineers-from-demo-builders-58j8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdl552ih2pcet63f1ubg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdl552ih2pcet63f1ubg.jpg" alt="Engineer reviewing AI model code on multiple monitors" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are running interviews for AI roles and your process is a LeetCode round plus a chat about transformers, you are measuring almost nothing that predicts performance. Attention mechanics are memorisable and rarely relevant to application work. Graph traversal has never told anyone whether a candidate can keep an inference bill under control.&lt;/p&gt;

&lt;p&gt;What actually predicts success is judgement under production constraints. Here are the five questions we use, what a strong answer sounds like, and the take-home format we have found genuinely discriminating.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Describe an AI feature you shipped that did not work
&lt;/h2&gt;

&lt;p&gt;You are listening for a failure signature, not an apology.&lt;/p&gt;

&lt;p&gt;Strong answers are specific about how the failure showed up: a class of inputs that silently degraded, a retrieval step that returned plausible but wrong documents, latency that only broke under concurrency, a tool call that fired on untrusted user input. They usually include what the fix cost and what they would do differently.&lt;/p&gt;

&lt;p&gt;Weak answers are either "we iterated on the prompt" or a story about something that was really a product disagreement. Neither tells you the candidate has watched a probabilistic component misbehave at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. How did you know it was getting better between releases?
&lt;/h2&gt;

&lt;p&gt;This is the highest-signal question in the set, and most candidates have no real answer.&lt;/p&gt;

&lt;p&gt;What you want to hear, unprompted: a golden dataset of representative cases including deliberately hard ones, an automated scoring method appropriate to the task, a regression run wired into CI, and traces in production that link a user complaint back to exact inputs and model version.&lt;/p&gt;

&lt;p&gt;Follow up on the details, because that is where experience shows. How many cases? Who labelled them? What did you do when two labellers disagreed? What happened when the automated score and human judgement diverged? Candidates who have really built this have opinions and war stories. Candidates who have not will describe an observability vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Walk a request through your system, including the timeout
&lt;/h2&gt;

&lt;p&gt;A straightforward architecture question with a specific trap in it. Most people describe the happy path fluently and stop.&lt;/p&gt;

&lt;p&gt;Push on failure. What happens when the model call times out — retry, fallback model, degraded response, queue? Is the retry idempotent? If the request had already triggered a tool call with a side effect, what undoes it? What does the user see meanwhile, and how does streaming interact with a mid-stream failure?&lt;/p&gt;

&lt;p&gt;This is ordinary distributed systems thinking applied to a component that fails in unusual ways, which is why strong backend engineers often outperform AI specialists here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwaconzljbnqqtzg77kdz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwaconzljbnqqtzg77kdz.jpg" alt="Technical interview in progress" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. What did it cost per thousand requests, and what did you do about it?
&lt;/h2&gt;

&lt;p&gt;The economics question, and close to binary in its discriminating power.&lt;/p&gt;

&lt;p&gt;In conventional software the marginal cost of a request rounds to zero, so engineers are trained not to think about it. In AI products it is real money, varies by an order of magnitude with design, and scales with success. Routing everything to a frontier model is the default that quietly destroys margins.&lt;/p&gt;

&lt;p&gt;Good answers reach for cheap intent classification, caching, small models for the easy majority, escalation only where it matters, and trimming what goes into the context window. They usually come with a number and a story about the optimisation that was rejected as premature and later turned out not to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Where did you decide not to use a model?
&lt;/h2&gt;

&lt;p&gt;The maturity question, and my personal favourite.&lt;/p&gt;

&lt;p&gt;Experienced engineers have a ready list: a rules engine that was cheaper and testable, a database query that was exact, a well-designed form that removed the ambiguity entirely, a search index that beat a retrieval pipeline on both latency and accuracy. They explain it without defensiveness.&lt;/p&gt;

&lt;p&gt;Candidates who answer every problem with an LLM, including ones a SQL query would solve, will build you an expensive and fragile architecture. This question surfaces that in about ninety seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The take-home that actually works
&lt;/h2&gt;

&lt;p&gt;Do not ask for a chatbot. Everyone can build a chatbot and you will learn nothing.&lt;/p&gt;

&lt;p&gt;Give them thirty real examples of a classification or extraction task from your domain, including several genuinely ambiguous ones and — this is the important part — a few that are mislabelled. Ask for a working solution, an evaluation harness, and a short written analysis of where it fails. Cap it at four hours and say so explicitly.&lt;/p&gt;

&lt;p&gt;The accuracy number barely matters. What you are grading is the analysis. Did they notice the bad labels and say so? Did they characterise the failure modes rather than just reporting a score? Did they explain what they would need to push it further?&lt;/p&gt;

&lt;p&gt;Assume AI coding assistants will be used, because that is how the job is done now. Screening for their absence selects for the wrong thing. What you are testing is whether the candidate can critically review generated output — whether the harness measures the right thing, whether edge cases are covered, whether they caught the plausible-looking helper that quietly drops nulls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red flags worth encoding into your process
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A portfolio of demos with nothing operated behind any of them&lt;/li&gt;
&lt;li&gt;No answer at all to how quality was measured&lt;/li&gt;
&lt;li&gt;Framework fluency substituting for systems reasoning&lt;/li&gt;
&lt;li&gt;Reflexive model-first thinking on problems that do not need a model&lt;/li&gt;
&lt;li&gt;Vagueness about cost, which usually means nobody ever asked&lt;/li&gt;
&lt;li&gt;No instinct around prompt injection, cross-tenant leakage, or tool calls triggered by untrusted input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full guide — including rate benchmarks by market, the four AI developer archetypes, and a framework for choosing between in-house hiring and a build partner — is here: &lt;a href="https://techcirkle.com/blog/hire-ai-developer" rel="noopener noreferrer"&gt;Hire AI Developer in 2026&lt;/a&gt;. If you would rather not run the search at all, this is roughly how we structure &lt;a href="https://techcirkle.com/llm-integration" rel="noopener noreferrer"&gt;LLM integration work&lt;/a&gt; for teams in that position.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Should I still run an algorithms round for AI roles?
&lt;/h3&gt;

&lt;p&gt;A short one is fine as a general coding filter, but do not weight it heavily. It measures nothing specific to AI engineering. The take-home plus the five questions above will give you far more signal per hour of interviewer time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I test for agentic systems experience?
&lt;/h3&gt;

&lt;p&gt;Ask what happens on step seven of a multi-step workflow when a tool returns something unexpected. Look for timeouts, idempotency, compensating actions and human handoff. It is distributed systems failure design, so engineers from that background pick it up fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is prompt engineering still a real skill to hire for?
&lt;/h3&gt;

&lt;p&gt;Not as a standalone one. Modern models are robust to phrasing and structured output modes removed most of the parsing tricks. It has collapsed into ordinary craft, the way writing good SQL did.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if a candidate has no production AI experience at all?
&lt;/h3&gt;

&lt;p&gt;Frequently fine, sometimes preferable. A strong senior engineer with cost discipline and a measuring habit ramps up quickly, and their fundamentals do not decay the way model-specific knowledge does. Screen the fundamentals hard and be explicit that ramp-up time is budgeted.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should the take-home be?
&lt;/h3&gt;

&lt;p&gt;Four hours, capped and stated. Longer exercises select for people with free time rather than people with skill, and they materially reduce your acceptance rate among strong senior candidates who are already employed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the most common hiring mistake you see?
&lt;/h3&gt;

&lt;p&gt;Writing a job description that lists all four AI archetypes at once — product engineer, ML engineer, platform engineer, agentic systems engineer. It attracts generalists who are shallow in each. Pick one, and hire a team or a partner if you genuinely need coverage across several.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hiring</category>
      <category>career</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Building a Local Evaluation Harness for Clinical AI</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Mon, 31 Aug 2026 08:12:25 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/building-a-local-evaluation-harness-for-clinical-ai-1agh</link>
      <guid>https://dev.to/jam-techcirkle/building-a-local-evaluation-harness-for-clinical-ai-1agh</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqp0wc0i42ke9znx1sbbp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqp0wc0i42ke9znx1sbbp.jpg" alt="Clinical AI data interface" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every clinical AI vendor shows you validation results. Almost none of them were produced on your population. This post is about the infrastructure that closes that gap, and why it has to be yours rather than theirs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why vendor validation does not transfer
&lt;/h2&gt;

&lt;p&gt;Model performance in healthcare is unusually sensitive to three things that vary enormously between institutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case mix.&lt;/strong&gt; Prevalence changes the positive predictive value of a fixed-sensitivity model directly. A sepsis model validated in a tertiary referral centre encounters a different base rate at a community hospital, and the same threshold produces a different alert burden.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation practice.&lt;/strong&gt; Models trained on free text or structured fields inherit the conventions of the site that produced the training data. Different templates, different macro usage, different specialty conventions — all shift the input distribution in ways that are invisible until measured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coding behaviour.&lt;/strong&gt; Local code sets, mapping decisions, and the ten percent that did not map cleanly and got assigned something adjacent. This is the least discussed and frequently the largest source of divergence.&lt;/p&gt;

&lt;p&gt;None of these are vendor failures. They are why local evaluation is not optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  The components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. A held-out local sample with defined ground truth
&lt;/h3&gt;

&lt;p&gt;The hard part is ground truth, not sampling. For some tasks a downstream coded outcome is adequate. For most, you need adjudicated labels — clinicians reviewing a sample against a written rubric, with a second reviewer on a subset to measure agreement.&lt;/p&gt;

&lt;p&gt;Budget for this honestly. A few hundred adjudicated cases is usually enough for a first read and is typically the most expensive line in the whole exercise. It is also the line most likely to be cut, which is how organisations end up evaluating against a proxy outcome that answers a different question.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Stratified performance reporting
&lt;/h3&gt;

&lt;p&gt;Report performance overall and separately for the subgroups where failure would be most consequential. At minimum: age bands, sex, race and ethnicity as recorded, primary language, payer class, and site of care.&lt;/p&gt;

&lt;p&gt;This is not a compliance exercise. Aggregate performance can be entirely acceptable while a subgroup with a different base rate or different documentation patterns is being systematically failed, and the aggregate number will never show it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Operating point selection with the alert burden attached
&lt;/h3&gt;

&lt;p&gt;A model is deployed at a threshold, not at an area-under-curve. Pick the operating point against the burden it produces — alerts per clinician per shift — and involve the people who will receive those alerts in choosing it.&lt;/p&gt;

&lt;p&gt;Alert fatigue is the dominant failure mode for clinical decision support, and it is a threshold decision made by someone who never sees the consequence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F80tz0umx8w3albd7yr0j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F80tz0umx8w3albd7yr0j.jpg" alt="Clinician using a tablet" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Scheduled re-evaluation
&lt;/h3&gt;

&lt;p&gt;Model drift in healthcare is real and its failure mode is silent. Performance degrades gradually while clinician trust remains at the original level, because nothing is designed to notice.&lt;/p&gt;

&lt;p&gt;Schedule the re-run — quarterly is a reasonable default — on a fresh local sample, with the same stratification. Define in advance what degradation triggers a review and who has the authority to withdraw the tool. If nobody has that authority, the monitoring is decorative.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Data plumbing
&lt;/h3&gt;

&lt;p&gt;Practically, this means a reproducible extract, a stable identifier strategy that survives de-identification, and a mapping layer that reconciles local codes to standard terminologies with the unmapped remainder made explicit rather than silently dropped. Bulk FHIR export handles a lot of this now, with the caveat that any extract without a defined retention policy, access model and de-identification standard is a liability that grows with every run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to demand at contract time
&lt;/h2&gt;

&lt;p&gt;Put these in the agreement, because retrofitting them is much harder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The right to evaluate on your own data before full deployment&lt;/li&gt;
&lt;li&gt;Access to model outputs at a granularity that supports subgroup analysis&lt;/li&gt;
&lt;li&gt;Notification when the vendor updates the model, with a defined re-evaluation window&lt;/li&gt;
&lt;li&gt;A documented statement on whether your inputs are retained or used for training&lt;/li&gt;
&lt;li&gt;An exit path that returns your data and does not strand the workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fourth is a business associate agreement question and is frequently answered vaguely. Push for specificity.&lt;/p&gt;

&lt;p&gt;Longer piece covering data readiness, interoperability, governance and engagement models: &lt;a href="https://techcirkle.com/blog/healthcare-it-consulting-services" rel="noopener noreferrer"&gt;Healthcare IT Consulting Services: What Actually Moves the Needle in 2026&lt;/a&gt;. General ML engineering context in our &lt;a href="https://techcirkle.com/blog/machine-learning-development-services" rel="noopener noreferrer"&gt;machine learning development services&lt;/a&gt; guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many labelled cases do we need?
&lt;/h3&gt;

&lt;p&gt;For a first read on a binary classification task, a few hundred adjudicated cases usually suffices, with more needed for rare outcomes or for meaningful subgroup precision. Power the subgroup analysis deliberately rather than hoping the sample covers it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can we use retrospective data or does it need to be prospective?
&lt;/h3&gt;

&lt;p&gt;Retrospective is fine for initial evaluation and much cheaper. Prospective silent-mode running — the model produces predictions nobody acts on — is the stronger design for the deployment decision, because it exercises the real data pipeline rather than a curated extract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who adjudicates the ground truth?
&lt;/h3&gt;

&lt;p&gt;Clinicians in the relevant specialty, working from a written rubric, with a second reviewer on a subset so you can report inter-rater agreement. Without that agreement number, a disappointing model result cannot be distinguished from noisy labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  What drift threshold should trigger a review?
&lt;/h3&gt;

&lt;p&gt;Define it as a relative degradation from your local baseline rather than an absolute value, set it before deployment, and set it separately for the subgroups you care about. The specific number matters less than agreeing it in advance and naming who acts on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does this apply to ambient documentation tools too?
&lt;/h3&gt;

&lt;p&gt;Yes, with different measures. Note quality against a rubric, blinded review, and error categories that matter clinically — fabricated content, omitted findings, incorrect attribution — rather than a single accuracy score.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is bulk FHIR export enough to build this?
&lt;/h3&gt;

&lt;p&gt;It covers a lot of the extraction, but not terminology reconciliation, ground truth, or governance. Treat it as the plumbing rather than the solution, and do not build an extract pipeline before deciding its retention and access policy.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>healthcare</category>
      <category>mlops</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Your CI Bill Tripled Because Your Team Started Using AI</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Mon, 31 Aug 2026 08:12:19 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/your-ci-bill-tripled-because-your-team-started-using-ai-4606</link>
      <guid>https://dev.to/jam-techcirkle/your-ci-bill-tripled-because-your-team-started-using-ai-4606</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm4pnmi7sr36zdsuoc5xd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm4pnmi7sr36zdsuoc5xd.jpg" alt="DevOps pipeline monitoring" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your continuous integration spend jumped in the last eighteen months and nobody changed the pipeline, the explanation is probably sitting in your editor. AI assistants made producing code cheap. They did nothing for the systems that verify and ship it, and those systems bill by the minute.&lt;/p&gt;

&lt;p&gt;This is a practical post about what breaks, in what order, and what to change first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The arithmetic
&lt;/h2&gt;

&lt;p&gt;CI cost tracks merge volume, not headcount. If merges doubled, expect build spend to roughly double even with an unchanged configuration. That part is expected.&lt;/p&gt;

&lt;p&gt;What is not expected is that per-merge duration also degrades. More merges means more contention for runners, more queueing, and — critically — more encounters with tests that fail intermittently. A test failing one run in twenty is background noise at ten merges a day. At forty it fires twice a day, someone re-runs the pipeline, and you have paid twice for the same verification.&lt;/p&gt;

&lt;p&gt;So the bill grows faster than the linear expectation, and the loop gets slower at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to fix, in order of return
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Test selection
&lt;/h3&gt;

&lt;p&gt;Running the full suite on every commit is the single largest recoverable cost in most repositories. Map which tests exercise which modules and run only the affected set on pull requests, keeping the full suite for the main branch and a nightly run.&lt;/p&gt;

&lt;p&gt;Most language ecosystems have tooling for this now, and even a crude version — directory-based mapping — captures most of the benefit. The reason it does not get done is that it is a week of unglamorous work, not that it is hard.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Verify your cache actually helps
&lt;/h3&gt;

&lt;p&gt;Dependency caching is frequently configured once, never measured, and occasionally slower than a cold build because the restore is fetching a large archive over a slow link. Time a cached run against a cold run before assuming the cache is helping. This takes an hour and surprises people regularly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Right-size the runners
&lt;/h3&gt;

&lt;p&gt;Runner class is typically chosen during a debugging session and inherited forever. Compile-heavy jobs may want more CPU; test jobs are often memory-bound and over-provisioned on cores. Measure a representative job at two or three sizes and pick deliberately.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Prune the matrix
&lt;/h3&gt;

&lt;p&gt;Every matrix build multiplies cost. Check which combinations of runtime version and OS your customers actually run and which your support policy actually covers. The intersection is usually smaller than the matrix.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Shut down idle environments
&lt;/h3&gt;

&lt;p&gt;Non-production environments running twenty-four hours a day for a team that works eight is a scheduled-shutdown problem, not an architecture problem. It is an afternoon of work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6vhppjob1l3xejbu5h0a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6vhppjob1l3xejbu5h0a.jpg" alt="Engineers reviewing code" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem that is not a cost problem
&lt;/h2&gt;

&lt;p&gt;Once the pipeline is efficient, the remaining bottleneck is usually human: pull request review capacity did not scale with generation capacity.&lt;/p&gt;

&lt;p&gt;Measure two numbers separately — time from PR opened to first review, and time from first review to merge. If the first dominates, you have a capacity problem, and no amount of pipeline tuning will fix it. Options that actually work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically splitting large changes, since review time scales worse than linearly with diff size&lt;/li&gt;
&lt;li&gt;Defining categories of change that do not require two human reviewers, explicitly rather than by convention&lt;/li&gt;
&lt;li&gt;Using model-assisted review for the mechanical pass — style, obvious null handling, missing test coverage — so humans spend attention on design and correctness&lt;/li&gt;
&lt;li&gt;Setting an explicit queue-length threshold that triggers a team conversation, so the constraint is visible rather than ambient&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dependency drift
&lt;/h2&gt;

&lt;p&gt;Worth a specific note because it is new. Generated code adds dependencies more casually than humans do — asked to parse a date, a model reaches for a library rather than writing four lines. It has no opinion about maintenance status, licence compatibility, or whether the package was published last week by an anonymous account.&lt;/p&gt;

&lt;p&gt;Enforce this at merge time rather than in an audit: policy on new dependencies with a clear exception path, a software bill of materials generated on every build, and secrets scanning that runs before the commit lands rather than after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring whether it worked
&lt;/h2&gt;

&lt;p&gt;Track cost per merge and duration per merge as trends. Track PR cycle time split into the two phases above. Track flake rate honestly — count re-runs, not just failures. And keep the four delivery metrics as the spine: deployment frequency, lead time from merge to production, change failure rate, and time to restore.&lt;/p&gt;

&lt;p&gt;The longer version, covering platform engineering, engagement models, and how to vet a vendor for this work, is at &lt;a href="https://techcirkle.com/blog/devops-services-company" rel="noopener noreferrer"&gt;DevOps Services Company: How to Choose the Right Partner in the AI Era&lt;/a&gt;. If you are building the agent-assisted side of this, our &lt;a href="https://techcirkle.com/agentic-workflow-development" rel="noopener noreferrer"&gt;agentic workflow development&lt;/a&gt; work covers how to scope those loops safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I find which tests to skip on a pull request?
&lt;/h3&gt;

&lt;p&gt;Start with a directory-based mapping from changed paths to test suites — crude but effective. Language-specific tooling for precise coverage-based selection exists in most ecosystems and is worth adopting once the crude version proves the value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is model-assisted code review actually useful?
&lt;/h3&gt;

&lt;p&gt;For the mechanical pass, yes: style violations, missing error handling, absent test coverage, obvious null cases. It is not reliable for design judgement or for spotting the subtle logic error, so treat it as a first filter that reduces what a human must attend to, not as a replacement reviewer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should flaky tests be quarantined or fixed?
&lt;/h3&gt;

&lt;p&gt;Quarantine to unblock, then fix on a schedule with an owner. Permanent quarantine is how a suite loses its meaning — after a year of accumulation, nobody trusts a failure and the suite stops functioning as a gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does self-hosting runners reduce cost?
&lt;/h3&gt;

&lt;p&gt;Sometimes, but it converts a variable cost into a maintenance obligation. Exhaust configuration wins first; they are cheaper, reversible, and do not add a system someone has to own.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much CI spend is typically recoverable?
&lt;/h3&gt;

&lt;p&gt;Thirty to fifty percent on a neglected pipeline, mostly from test selection and caching. Ten to fifteen on a well-maintained one. Measure your own baseline before believing any number, including this one.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a reasonable pipeline duration target?
&lt;/h3&gt;

&lt;p&gt;Under ten minutes for the feedback a developer actively waits on. Beyond that, people context-switch away and return to failures they have to reconstruct, which degrades change size and recovery time in ways the invoice never shows.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>ai</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your Eight-Step Agent Is Wrong a Third of the Time</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Sat, 29 Aug 2026 05:55:30 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/your-eight-step-agent-is-wrong-a-third-of-the-time-4lk9</link>
      <guid>https://dev.to/jam-techcirkle/your-eight-step-agent-is-wrong-a-third-of-the-time-4lk9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxkruiz3cwdt27zzvbsqz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxkruiz3cwdt27zzvbsqz.jpg" alt="Engineering team reviewing an AI agent workflow" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start with arithmetic, because the arithmetic is the entire post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Single step accuracy:  0.95
Chain of 8 steps:      0.95 ^ 8  =  0.663
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A model call that is right 95% of the time is a genuinely good component. Chain eight of them, each consuming the previous output, and your end-to-end success rate is about 66%.&lt;/p&gt;

&lt;p&gt;That is a coin flip with extra latency. And it gets worse, because the failures are &lt;strong&gt;silent&lt;/strong&gt; — every individual step returned something structurally valid and semantically plausible. Nothing threw. Your logs look clean.&lt;/p&gt;

&lt;p&gt;This is the failure mode that caught a lot of teams in the middle of 2026, after agentic scaffolding matured enough that people started shipping chains rather than single calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the failures are silent
&lt;/h2&gt;

&lt;p&gt;In deterministic software, a broken step throws. You get a stack trace pointing at the line.&lt;/p&gt;

&lt;p&gt;In an agent chain, step 3 misidentifies which customer record is relevant. It returns a perfectly well-formed record. Steps 4 through 8 then execute flawlessly against the wrong record. The output is coherent, confident, correctly formatted, and about a different customer.&lt;/p&gt;

&lt;p&gt;There is no exception anywhere in that trace. Everything succeeded. The system is simply wrong, and it will be wrong at scale until a human notices something odd about a specific case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four things that actually help
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Shorten the chain
&lt;/h3&gt;

&lt;p&gt;The single most effective intervention, and the least fashionable, because "we replaced the agent with three deterministic steps and one model call" does not make a good demo.&lt;/p&gt;

&lt;p&gt;Every step you can make deterministic is a step that cannot compound error. If step 4 is "look up the customer by ID", that is a database query, not a model call. A surprising proportion of agent chains in the wild contain model calls doing work a function could do — usually because the agent framework made it easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.95 ^ 8 = 0.663
0.95 ^ 3 = 0.857   ← same task, 5 steps made deterministic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Validate between steps
&lt;/h3&gt;

&lt;p&gt;Not "did it return JSON" — schema validation is table stakes and catches almost none of the real failures. Validate the &lt;em&gt;semantics&lt;/em&gt; at each boundary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the returned ID exist in the source system?&lt;/li&gt;
&lt;li&gt;Is the amount within the range this account can produce?&lt;/li&gt;
&lt;li&gt;Does the retrieved record's owner match the requesting user?&lt;/li&gt;
&lt;li&gt;Is the classification one of the fourteen permitted values, or did the model invent a fifteenth?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each check is a few lines and converts a silent wrong answer into a loud failure you can handle.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Constrain the action space hard
&lt;/h3&gt;

&lt;p&gt;The instinct when building an agent is to give it every tool it might need. This is backwards.&lt;/p&gt;

&lt;p&gt;Fewer tools, tighter schemas, narrower parameter ranges. Every tool you expose is a branch the agent can take incorrectly, and the failure rate scales with the branching factor rather than with model quality. The teams that succeeded with agents this year all did the same unglamorous thing: they cut the tool list down and made the remaining schemas strict.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Human checkpoint at the irreversible step
&lt;/h3&gt;

&lt;p&gt;Find the point in the chain where an action becomes hard to undo — money moves, an email sends, a record is deleted, a customer-visible state changes — and put a human there.&lt;/p&gt;

&lt;p&gt;This is not a failure of ambition. It is the same design principle as a payments system, and it is the correct mental model for agents generally: closer to how you design a transaction boundary than how you design a chatbot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The heuristic for whether to build an agent at all
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An agent is a good fit where the task has a verifiable output and a bounded set of actions.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reconciling invoices against a ledger — verifiable. The numbers either match or they do not.&lt;/li&gt;
&lt;li&gt;Triaging support tickets into a fixed taxonomy — verifiable. There are fourteen categories and a right answer.&lt;/li&gt;
&lt;li&gt;"Managing" a process with no definition of correct — not a project. An aspiration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot state, in one sentence, how a program would check the output was right, you do not have an agent task. You have a demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to instrument from day one
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-step success rate&lt;/strong&gt;, not just end-to-end. You cannot fix a chain you cannot see inside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where chains terminate&lt;/strong&gt;, and why. Distinguish "completed" from "gave up" from "hit the retry ceiling".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost per resolved task&lt;/strong&gt;, not per token. A chain that retries three times is expensive regardless of how cheap the model is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Divergence between validation failures and user complaints.&lt;/strong&gt; If users complain about cases your validators pass, your validators are checking the wrong things.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does a better model fix compounding error?
&lt;/h3&gt;

&lt;p&gt;Only marginally. Going from 95% to 97% per step takes an eight-step chain from 66% to 78% — better, still not shippable for most purposes. Shortening the chain from eight steps to three does more than any model upgrade available.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I know how accurate each step is?
&lt;/h3&gt;

&lt;p&gt;Build an evaluation set per step: 200 or so real inputs with known correct outputs at that boundary. Most teams evaluate only end-to-end, which tells you that something is broken but not where.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are agent frameworks the problem?
&lt;/h3&gt;

&lt;p&gt;Not inherently, but they make adding steps and tools frictionless, and friction was doing useful work. Whatever framework you use, treat every additional model call and every additional exposed tool as a cost that must be justified.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where exactly should the human checkpoint go?
&lt;/h3&gt;

&lt;p&gt;At the last reversible point before an irreversible action. Not at the start (you gain nothing) and not after the action (too late). If the chain has several irreversible actions, that is itself a design smell — batch them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about multi-agent systems?
&lt;/h3&gt;

&lt;p&gt;The same arithmetic applies, usually worse, because inter-agent communication adds boundaries where meaning degrades. Multi-agent architectures are justified when subtasks are genuinely independent, not when a single chain felt too long.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we validate outputs without a ground truth?
&lt;/h3&gt;

&lt;p&gt;Use constraint checks rather than correctness checks: does the ID exist, is the value in range, does the referenced entity belong to this user, is the category in the permitted set. These catch most real failures without needing a known right answer.&lt;/p&gt;




&lt;p&gt;The wider 2026 picture — cost curves, evaluation, retrieval, regulation, org structure — is here: &lt;a href="https://techcirkle.com/blog/top-ai-developments-for-business-2026" rel="noopener noreferrer"&gt;Top AI Developments for Business in 2026: What Actually Changed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We build &lt;a href="https://techcirkle.com/agentic-workflow-development" rel="noopener noreferrer"&gt;agentic workflows&lt;/a&gt; and &lt;a href="https://techcirkle.com/llm-integration" rel="noopener noreferrer"&gt;LLM integrations&lt;/a&gt; for production use. &lt;a href="https://techcirkle.com/contact-us" rel="noopener noreferrer"&gt;Get in touch&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>engineering</category>
    </item>
    <item>
      <title>What an Architecture Review Should Actually Hand You</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Sat, 29 Aug 2026 05:54:18 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/what-an-architecture-review-should-actually-hand-you-3ef4</link>
      <guid>https://dev.to/jam-techcirkle/what-an-architecture-review-should-actually-hand-you-3ef4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ooombetxfqjc5pjydjc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ooombetxfqjc5pjydjc.jpg" alt="Engineering team reviewing system architecture during a working session" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Someone above you has decided to bring in consultants to review your system. You have opinions about this. Most of them are correct.&lt;/p&gt;

&lt;p&gt;But you also have leverage you probably are not using, because the deliverable specification is usually written by someone who does not know what a good one looks like. This post is the list I would hand any engineer whose employer is about to buy an architecture review — the artefacts to demand up front, while the statement of work is still editable.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Findings that are specific enough to be wrong
&lt;/h2&gt;

&lt;p&gt;This is the whole test and everything else follows from it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ "The data layer presents scalability concerns."
✅ "The single Postgres primary serves both transactional writes and the
    finance team's month-end analytics queries. At the projected 4x volume
    this becomes a write-latency incident in ~2 quarters. Fix: read replica
    + query routing at the ORM layer. Est. 3 engineer-weeks."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first is unfalsifiable. Nobody can check it in six months. It survives any outcome, which is precisely why it gets written.&lt;/p&gt;

&lt;p&gt;The second stakes a position. It might be wrong — the volume projection could be off, the finance query might get killed for unrelated reasons — and that is what makes it worth the fee. Someone put judgement on the table where reality can hit it.&lt;/p&gt;

&lt;p&gt;Since 2023 this test has become the only one that works. Fluent technical prose is free now; anyone can generate forty pages of well-organised assessment about a codebase they skimmed. Count the falsifiable claims per page and you have a quality metric that AI cannot inflate.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A blast radius per finding, not a severity label
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;HIGH / MEDIUM / LOW&lt;/code&gt; is a way of avoiding the question. What you want per finding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What breaks first&lt;/li&gt;
&lt;li&gt;Under what condition (load, data volume, concurrency, a specific date)&lt;/li&gt;
&lt;li&gt;Who notices — internal team, one customer segment, everyone&lt;/li&gt;
&lt;li&gt;Whether it degrades or fails hard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A finding without a blast radius cannot be prioritised against the rest of your backlog, which means it will not be actioned, which means the review produced nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Effort estimates attached to every recommendation
&lt;/h2&gt;

&lt;p&gt;Not T-shirt sizes. Engineer-weeks, with the assumptions written down.&lt;/p&gt;

&lt;p&gt;This one clause does more work than any other, because it forces the reviewer to have thought concretely about implementation instead of gesturing at a target state. "Adopt event-driven architecture" survives contact with a slide. It does not survive "estimate that in engineer-weeks against this repository, listing what you assumed."&lt;/p&gt;

&lt;p&gt;Expect and accept ranges. Reject the absence of numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. An explicit list of what is fine
&lt;/h2&gt;

&lt;p&gt;Demand this one. Ask for the section titled &lt;em&gt;decisions we would not change&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A review returning twenty problems and zero acceptable decisions is not a review, it is a scoping document for the remediation contract that follows it. Real systems contain choices that were correct, and choices that are wrong in ways that will not matter for three years. Naming them proves the reviewer is ranking by impact rather than cataloguing against a reference architecture from a cloud vendor's marketing site.&lt;/p&gt;

&lt;p&gt;It is also the part your team most needs. Being told the thing you built is defensible, in writing, by an outsider, is worth something the remediation list is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Proof they read the incident history
&lt;/h2&gt;

&lt;p&gt;Ask directly: which post-mortems did you read, and what did they change in your conclusions?&lt;/p&gt;

&lt;p&gt;Production incident history is the most honest artefact any engineering org produces, because nobody writes a post-mortem to impress a buyer. A reviewer who has read the code but not the incidents has read the fiction and skipped the documentary. Their findings will mirror the architecture diagram rather than the system's actual failure pattern — and those two things diverge in interesting ways in every codebase over about two years old.&lt;/p&gt;

&lt;p&gt;The same applies to the people who get paged. If nobody in the on-call rotation was interviewed, the review is incomplete regardless of how thorough the static analysis was.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The raw artefacts
&lt;/h2&gt;

&lt;p&gt;Scripts, query outputs, interview notes, the dependency graph in a machine-readable format. You paid for them.&lt;/p&gt;

&lt;p&gt;More importantly: the review is a snapshot and your system moves. If you have the scripts, you can re-run the analysis in six months for free. If you have only the PDF, you have bought a one-time observation and you will be buying it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. A walkthrough where you are allowed to argue
&lt;/h2&gt;

&lt;p&gt;Not a presentation to leadership. A working session with the engineers, scheduled, with time for objection.&lt;/p&gt;

&lt;p&gt;Two reasons. First, a finding that cannot survive informed challenge from the people who built the system was never solid — and you will find out in that room, not in production. Second, findings your team has argued with become findings your team owns. Findings delivered as a document from outside get treated as an external opinion, and external opinions do not make it into sprint planning.&lt;/p&gt;

&lt;p&gt;If a consultancy resists the challenge session, that is your answer about how much the findings are worth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line version
&lt;/h2&gt;

&lt;p&gt;An architecture review is an engagement to buy a &lt;em&gt;decision&lt;/em&gt;, not a document. If the artefacts above are not in the statement of work, what arrives will be a summary of things your team already knew, written more confidently than any of you would have dared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How long should an architecture review take?
&lt;/h3&gt;

&lt;p&gt;Two to four weeks for a system of ordinary complexity. Under two weeks generally means code was read but incident history was not and operators were not interviewed. Beyond six weeks the findings start going stale against a team that is still shipping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who should be interviewed during a review?
&lt;/h3&gt;

&lt;p&gt;The on-call rotation first, then the people who wrote the oldest surviving modules, then product. Interviewing only tech leads and architects produces a review of the intended system rather than the real one.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if we disagree with a finding?
&lt;/h3&gt;

&lt;p&gt;Argue it in the scheduled walkthrough with evidence. A good reviewer will change a conclusion when shown data, and will label which findings are high-confidence versus judgement calls under uncertainty. If nothing is ever labelled uncertain, the confidence is decorative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can we just run an AI model over the codebase instead?
&lt;/h3&gt;

&lt;p&gt;For the inventory layer, yes, and you should — dependency mapping and dead-code detection are close to free now. What a model cannot do is rank findings against your organisation's actual capacity, politics and roadmap, because none of that is in the repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should the reviewing firm also do the remediation?
&lt;/h3&gt;

&lt;p&gt;It can, and the context transfer is already paid for. Just make sure the assessment was contracted and priced separately, so the size of the recommended fix does not influence the fee for the diagnosis.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the single best clause to add to the SOW?
&lt;/h3&gt;

&lt;p&gt;Named individuals with a committed time percentage. The gap between the person who sold the engagement and the person who performs it is the oldest complaint in professional services and the easiest to close on paper.&lt;/p&gt;




&lt;p&gt;Full write-up with the other four engagement types, pricing models and the 30-day test: &lt;a href="https://techcirkle.com/blog/software-development-consulting-services" rel="noopener noreferrer"&gt;Software Development Consulting Services: What You Actually Get for the Money&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We do this work at &lt;a href="https://techcirkle.com/development/custom-software-development" rel="noopener noreferrer"&gt;TechCirkle&lt;/a&gt; alongside building products — &lt;a href="https://techcirkle.com/contact-us" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt; if you want a scoping call.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>devops</category>
      <category>career</category>
    </item>
    <item>
      <title>Build the Pilot Like It Has to Survive</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Wed, 26 Aug 2026 15:59:34 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/build-the-pilot-like-it-has-to-survive-4m7i</link>
      <guid>https://dev.to/jam-techcirkle/build-the-pilot-like-it-has-to-survive-4m7i</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlrpxl0yn3129rbejc8i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlrpxl0yn3129rbejc8i.jpg" alt="Team working through a technical problem on a glass wall" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pilot-to-production gap in AI projects gets discussed as if it were mysterious, or organisational, or a matter of change management. It is mostly none of those. It is five missing engineering artefacts, and they are the same five almost every time.&lt;/p&gt;

&lt;p&gt;A demo runs on curated data, handles the happy path, and is judged by a sympathetic audience in a meeting. A production system handles malformed input, upstream schema changes, adversarial users, latency budgets, cost ceilings, model deprecations, and the specific edge case that represents four percent of volume and eighty percent of your support tickets.&lt;/p&gt;

&lt;p&gt;Here is what to build from the first commit so the second thing is reachable from the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. An evaluation harness
&lt;/h2&gt;

&lt;p&gt;This is the one that matters most and gets skipped most.&lt;/p&gt;

&lt;p&gt;You need a held-out set of representative examples and an automated method of scoring output against them. Not a notebook where someone eyeballs twenty results — a scored, repeatable, version-controlled comparison you can run on every change.&lt;/p&gt;

&lt;p&gt;Without it, every subsequent decision about prompts, model versions, retrieval strategy, chunking, or thresholds is made on anecdote. Teams end up in an endless loop of subjective adjustment where "is it better now?" is genuinely unanswerable, because these systems fail in ways that are invisible without measurement.&lt;/p&gt;

&lt;p&gt;Build the evaluation set before building the system. It forces you to define what correct means, which is frequently where the real disagreement surfaces — and it is far better to surface it in week one than in month five.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. A real data connection
&lt;/h2&gt;

&lt;p&gt;Pilots run on CSVs. Production runs on a pipeline.&lt;/p&gt;

&lt;p&gt;The gap is not the extraction — it is everything the manual extract silently removed. Nulls someone dropped. Encoding problems someone fixed. Records that failed a filter nobody documented. Schema variations across the three years of history the sample did not span.&lt;/p&gt;

&lt;p&gt;Connect to the actual source early, even at reduced volume. Discovering that eleven percent of production records have a field format the pilot never saw is a week-two problem or a month-five problem, and it is exactly the same problem either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Explicit failure behaviour
&lt;/h2&gt;

&lt;p&gt;What does the system do when the model returns malformed output? When the provider times out? When input exceeds the context limit? When retrieval returns nothing relevant?&lt;/p&gt;

&lt;p&gt;A demo has no answer because these did not happen. A production system needs a defined answer for each, and the answer is often "escalate to a human" — which requires a path for that to happen, and someone on the other end of it.&lt;/p&gt;

&lt;p&gt;Define the confidence threshold below which the system declines to act. Systems without a decline path produce confident wrong output on inputs they should have refused, and that failure mode is more damaging than an outright error because nothing signals it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqj58bh2ovxxjb4959qlp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqj58bh2ovxxjb4959qlp.jpg" alt="Team reviewing analytics in a working session" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A cost model
&lt;/h2&gt;

&lt;p&gt;Token costs at a hundred requests a day tell you nothing about ten thousand.&lt;/p&gt;

&lt;p&gt;Instrument cost per request from the beginning, broken down by component — retrieval, generation, re-ranking, any evaluation running in production. Then project to realistic volume before committing to an architecture.&lt;/p&gt;

&lt;p&gt;This routinely changes design decisions. A pattern that makes three model calls per request is fine at demo volume and can be untenable at scale, and discovering that after the architecture is settled is expensive. Caching strategy, model tier selection, and whether to re-rank at all are all cost decisions disguised as quality decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. An owner
&lt;/h2&gt;

&lt;p&gt;Not an engineering artefact, and it kills more pilots than the other four combined.&lt;/p&gt;

&lt;p&gt;Systems built by a team that then disperses have no one to handle the model deprecation notice, the gradual quality drift, the new input pattern that started appearing in March. Name the owner before launch, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The drift problem specifically
&lt;/h2&gt;

&lt;p&gt;One production concern has no demo equivalent and deserves separate attention.&lt;/p&gt;

&lt;p&gt;These systems degrade without erroring. The input distribution shifts. An upstream system changes format. The provider updates the underlying model. Output quality drops and nothing raises an alarm, because from the infrastructure's perspective everything is healthy — requests are being served, latency is fine, error rate is zero.&lt;/p&gt;

&lt;p&gt;Uptime monitoring cannot see this. You need quality monitoring: run the evaluation set on a schedule against production configuration, track the score over time, and alert on degradation. This is why the evaluation harness is not merely a development tool. It is a production control, and it is the reason skipping it early is so hard to recover from.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this costs
&lt;/h2&gt;

&lt;p&gt;Roughly thirty percent more than a demo.&lt;/p&gt;

&lt;p&gt;That is the entire trade. Thirty percent more up front against a rewrite when the demo needs to become real — and the rewrite is where second-year AI budgets tend to disappear, usually while the team is also trying to deliver the next thing.&lt;/p&gt;

&lt;p&gt;The wider context — engagement models, use-case selection, build versus buy, governance, and cost ranges — is at &lt;a href="https://techcirkle.com/blog/ai-business-consulting" rel="noopener noreferrer"&gt;techcirkle.com/blog/ai-business-consulting&lt;/a&gt;. Most of what makes this work in practice is &lt;a href="https://techcirkle.com/llm-integration" rel="noopener noreferrer"&gt;LLM integration architecture&lt;/a&gt;: retrieval, evaluation, caching, and fallbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is an evaluation harness for an AI system?
&lt;/h3&gt;

&lt;p&gt;A held-out set of representative inputs with expected outputs or scoring criteria, plus an automated way to run the system against them and produce a comparable score. It is version-controlled and runs on every change. Without one, decisions about prompts, models, retrieval, and thresholds are made on anecdote, and quality becomes unmeasurable rather than merely uncertain.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you detect AI model quality drift in production?
&lt;/h3&gt;

&lt;p&gt;Run your evaluation set on a schedule against the production configuration and track the score over time, alerting on degradation. Standard uptime and error-rate monitoring cannot detect drift, because a degrading model still returns well-formed responses quickly. This is why the evaluation harness functions as a production control rather than only a development tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does connecting to real data early matter so much?
&lt;/h3&gt;

&lt;p&gt;Because manual extracts silently remove exactly the problems production will surface — dropped nulls, fixed encodings, filtered records, schema variation across years the sample did not span. Connecting to the actual source at reduced volume surfaces these in week two rather than month five, at which point the architecture has usually settled around assumptions that no longer hold.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should an AI system do when it is uncertain?
&lt;/h3&gt;

&lt;p&gt;Decline and escalate, which requires a defined confidence threshold and a human path on the other side. Systems without a decline path produce confident wrong output on inputs they should have refused. That failure mode is more damaging than an outright error because nothing signals it — the output looks exactly like a correct one.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much more does building a pilot properly cost?
&lt;/h3&gt;

&lt;p&gt;Roughly thirty percent more than a demo, covering the evaluation harness, a real data connection, explicit failure behaviour, and cost instrumentation. The comparison is against rewriting the system when the demo needs to become production, which typically costs considerably more and happens while the team is also committed to delivering the next thing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Ten Minutes or Nobody Reads the Result</title>
      <dc:creator>James Sanderson</dc:creator>
      <pubDate>Wed, 26 Aug 2026 15:57:38 +0000</pubDate>
      <link>https://dev.to/jam-techcirkle/ten-minutes-or-nobody-reads-the-result-561e</link>
      <guid>https://dev.to/jam-techcirkle/ten-minutes-or-nobody-reads-the-result-561e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fky3o53jhxvrof7tx5ki9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fky3o53jhxvrof7tx5ki9.jpg" alt="Engineer working amid continuous integration workflow icons" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pipeline duration gets treated as a performance metric — nice to improve, competing with other priorities. It is better understood as a hard design constraint, because there is a threshold past which continuous integration stops doing the job it exists to do.&lt;/p&gt;

&lt;p&gt;Under roughly ten minutes, a developer opens a pull request, stays in context, and acts on the result. Past twenty, they switch to something else. When they come back, the change is no longer loaded in their head, the fix costs a full re-context, and the tight feedback loop that justified building CI in the first place is gone.&lt;/p&gt;

&lt;p&gt;You still have a pipeline. You no longer have continuous integration in any meaningful sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the minutes actually are
&lt;/h2&gt;

&lt;p&gt;Four things account for most slow pipelines, roughly in order of how much they cost and how rarely they are addressed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency installation on every run.&lt;/strong&gt; Still remarkably common. If your pipeline resolves and downloads the full dependency tree on each execution, that is often two to four minutes of pure repetition. Lockfile-keyed caching is a small change with an outsized return.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serial test execution.&lt;/strong&gt; Test suites parallelise well and frequently are not parallelised at all, because the suite grew gradually and nobody ever revisited the assumption. Sharding across runners is usually the single largest available win.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running everything on every change.&lt;/strong&gt; A one-line documentation edit triggering the full integration suite is waste with a straight face. Test selection based on the dependency graph — running only what the change could plausibly affect — cuts typical run time substantially, with the caveat that the selection logic itself needs to be conservative and tested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slow work in the blocking path.&lt;/strong&gt; Anything genuinely slow — full end-to-end suites, performance benchmarks, container image scanning of large images — does not belong in front of a merge. Move it after merge, run it against a real environment, and page the owning team on failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should actually gate a merge
&lt;/h2&gt;

&lt;p&gt;The instinct is to gate on everything, and it backfires in a specific and predictable way.&lt;/p&gt;

&lt;p&gt;Gate on everything and the pipeline becomes slow and flaky. Slow and flaky means engineers learn that red does not necessarily mean broken. Once that is learned, the standard response to a failure is to re-run rather than investigate. At that point the gate is theatre: it delays every change and catches nothing, because failures are dismissed by default.&lt;/p&gt;

&lt;p&gt;A defensible policy gates on signals that are fast and deterministic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit tests&lt;/li&gt;
&lt;li&gt;Linting and formatting&lt;/li&gt;
&lt;li&gt;Type checking&lt;/li&gt;
&lt;li&gt;Dependency and secret scanning&lt;/li&gt;
&lt;li&gt;Contract tests against consumer expectations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything slow or inherently flaky runs post-merge against a real environment. This feels like lowering standards and does the opposite — the gate that remains actually means something, so people respond to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa2totnv7reg0yzk2flcu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa2totnv7reg0yzk2flcu.jpg" alt="Development team reviewing code together" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flaky tests are the real emergency
&lt;/h2&gt;

&lt;p&gt;Flakiness deserves more urgency than it usually gets, because it is not a nuisance — it is corrosive to the entire mechanism.&lt;/p&gt;

&lt;p&gt;One test that fails intermittently teaches the team that failures are sometimes noise. That lesson generalises immediately. Within a few weeks people are re-running failures reflexively rather than reading them, and the day a red build represents a genuine regression, it gets re-run too.&lt;/p&gt;

&lt;p&gt;The control that works is automated quarantine. Detect tests that fail non-deterministically across runs on the same commit, automatically move them out of the blocking path, and open an owned ticket. The suite stays green and meaningful while the underlying problem gets fixed properly rather than urgently.&lt;/p&gt;

&lt;p&gt;What does not work is asking people to be more diligent about investigating failures. That is a request to spend attention on a signal that has been demonstrated to be unreliable, and it loses to incentives every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy and release are different events
&lt;/h2&gt;

&lt;p&gt;The last structural change worth making is separating deployment from release with feature flags.&lt;/p&gt;

&lt;p&gt;Once shipping code and activating behaviour are decoupled, deploying stops being a decision that carries risk. Code goes to production dark; the behaviour turns on when someone chooses. Two things follow. Deployment becomes routine enough that continuous deployment is politically achievable in organisations that would otherwise refuse it. And rollback becomes a flag change measured in seconds instead of a redeploy measured in pipeline duration.&lt;/p&gt;

&lt;p&gt;The cost is flag debt. Long-lived flags multiply into state combinations nobody can reason about. The control is simple and must be enforced: every flag gets an owner and an expiry date, and a scheduled audit removes anything past it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pragmatic order of operations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Cache dependencies keyed on the lockfile.&lt;/li&gt;
&lt;li&gt;Shard the test suite across runners.&lt;/li&gt;
&lt;li&gt;Move slow and flaky suites out of the blocking path, with quarantine automated.&lt;/li&gt;
&lt;li&gt;Add change-based test selection once the suite is fast enough that correctness of selection is the main risk.&lt;/li&gt;
&lt;li&gt;Introduce feature flags and decouple deploy from release.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps one to three usually get a typical pipeline under ten minutes without any architectural change, which is why they come first.&lt;/p&gt;

&lt;p&gt;The full treatment — the seven layers of a delivery stack, infrastructure drift, where AI agents genuinely help, costs, and a 90-day roadmap — is at &lt;a href="https://techcirkle.com/blog/devops-automation" rel="noopener noreferrer"&gt;techcirkle.com/blog/devops-automation&lt;/a&gt;. We build delivery platforms alongside our &lt;a href="https://techcirkle.com/development/custom-software-development" rel="noopener noreferrer"&gt;custom software development&lt;/a&gt; work, which is why the advice here is shaped by systems we have had to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why is ten minutes the threshold for CI feedback?
&lt;/h3&gt;

&lt;p&gt;It approximates how long a developer will wait before switching tasks. Under ten minutes they stay in context and act on the result immediately. Past twenty they move on, and returning to the change costs a full re-context — which is what destroys the tight feedback loop CI exists to provide. The exact number varies by team, but the cliff is real and sits in that range.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should end-to-end tests block merges?
&lt;/h3&gt;

&lt;p&gt;Generally no. End-to-end suites are slow and inherently more flaky than lower tiers, and putting them in front of a merge is the most common cause of teams learning to re-run until green. Run them post-merge against a real environment with failures paging the owning team. The merge gate should hold only fast, deterministic checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you detect a flaky test automatically?
&lt;/h3&gt;

&lt;p&gt;Re-run failures against the identical commit. A test that passes on retry with no code change is non-deterministic by definition. CI platforms increasingly support this natively; where they do not, a retry-and-compare job plus a small history store is enough. The important part is that detection triggers automatic quarantine rather than a request for someone to investigate later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does test selection risk missing real failures?
&lt;/h3&gt;

&lt;p&gt;Yes, which is why the selection logic must be conservative — err toward running too much — and why it belongs after the basics rather than first. It also pairs naturally with a post-merge full run, so anything selection missed is caught shortly afterward rather than never. Do not adopt it as the first optimisation; adopt it once caching and sharding have already been done.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the downside of feature flags?
&lt;/h3&gt;

&lt;p&gt;Flag debt. Flags that are never removed accumulate into combinations of state that nobody can reason about or test, and this compounds quietly. The mitigation is treating every flag as temporary by default: an owner, an expiry date, and a scheduled audit that removes expired ones. The debt is real and manageable; coupling deployment to release is worse.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
