<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Arrange Act Assert</title><description>Jag Reehal&apos;s thoughts on things, mostly product development</description><link>https://arrangeactassert.com/</link><item><title>The Best Consultancies Make Themselves Less Necessary</title><link>https://arrangeactassert.com/posts/the-best-consultancies-make-themselves-less-necessary/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-best-consultancies-make-themselves-less-necessary/</guid><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I’m preparing for a talk with &lt;a href=&quot;https://www.equalexperts.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Equal Experts&lt;/a&gt;, and it’s got me thinking about consultancy.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My talk at EE about Magic vs Science: Making AI Coding Agents Prove Their Work&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 981px) 981px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;981&quot; height=&quot;453&quot; src=&quot;https://arrangeactassert.com/_astro/ee-talk.Coi117ix_1Vy7jx.webp&quot; srcset=&quot;/_astro/ee-talk.Coi117ix_AGCvr.webp 640w, /_astro/ee-talk.Coi117ix_Z1gHcY.webp 750w, /_astro/ee-talk.Coi117ix_1XURVS.webp 828w, /_astro/ee-talk.Coi117ix_1Vy7jx.webp 981w&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’ve worked for consultancies, alongside them, and inside companies while consultancies have come in to assess them.&lt;/p&gt;
&lt;p&gt;Some experiences have been brilliant.&lt;/p&gt;
&lt;p&gt;Others have made me uncomfortable.&lt;/p&gt;
&lt;p&gt;And the more I’ve seen, the more I think the difference between a good consultancy and a bad one often has little to do with technical ability.&lt;/p&gt;
&lt;p&gt;It comes down to culture, honesty, empathy and transparency.&lt;/p&gt;
&lt;p&gt;But above all, it comes down to incentives.&lt;/p&gt;
&lt;p&gt;Every consultancy has to make money. Of course it does.&lt;/p&gt;
&lt;p&gt;But how it makes that money matters.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-business-model-does-the-pulling&quot;&gt;The business model does the pulling&lt;/h2&gt;
&lt;p&gt;If more people, more billable days and longer engagements mean more revenue, there’s an obvious tension.&lt;/p&gt;
&lt;p&gt;An assessment can become a sales pipeline.&lt;/p&gt;
&lt;p&gt;A problem can become another engagement.&lt;/p&gt;
&lt;p&gt;A gap in a team can become an opportunity to place somebody.&lt;/p&gt;
&lt;p&gt;You don’t need bad people for this to happen.&lt;/p&gt;
&lt;p&gt;Sometimes the business model does the pulling for you.&lt;/p&gt;
&lt;h2 id=&quot;i-wouldnt-have-done-it-like-that&quot;&gt;I wouldn’t have done it like that&lt;/h2&gt;
&lt;p&gt;Years ago, I was part of a consultancy engagement that I still think about today.&lt;/p&gt;
&lt;p&gt;I can’t name the consultancy or the company involved, but our mandate was clear: go in, assess the organisation, find the problems, make recommendations and create openings to bring in more of our own people.&lt;/p&gt;
&lt;p&gt;I watched us do real damage.&lt;/p&gt;
&lt;p&gt;We found fault with the code, the testing, the processes, the architecture and then the people.&lt;/p&gt;
&lt;p&gt;But we had something they didn’t.&lt;/p&gt;
&lt;p&gt;Hindsight.&lt;/p&gt;
&lt;p&gt;We hadn’t lived through their deadlines, changing requirements, budget constraints, people leaving or the compromises that had got them there.&lt;/p&gt;
&lt;p&gt;It’s easy to arrive afterwards and say:&lt;/p&gt;
&lt;p&gt;“I wouldn’t have done it like that.”&lt;/p&gt;
&lt;p&gt;Of course you wouldn’t.&lt;/p&gt;
&lt;p&gt;You already know how the story ends.&lt;/p&gt;
&lt;p&gt;That’s why Norm Kerth’s Prime Directive has stuck with me: start from the belief that people did the best they could with the information, skills, resources and circumstances they had at the time.&lt;/p&gt;
&lt;p&gt;You can still call out bad decisions.&lt;/p&gt;
&lt;p&gt;You start with curiosity rather than judgement.&lt;/p&gt;
&lt;h2 id=&quot;he-wasnt-full-stack&quot;&gt;He wasn’t full stack&lt;/h2&gt;
&lt;p&gt;One example from that engagement has always stayed with me.&lt;/p&gt;
&lt;p&gt;There was a backend engineer who was good at what he did. He knew the system, cared about the product and delivered value.&lt;/p&gt;
&lt;p&gt;We invented a problem: he wasn’t “full stack”.&lt;/p&gt;
&lt;p&gt;There was no problem to solve.&lt;/p&gt;
&lt;p&gt;The company already had people doing the frontend work. He was a backend engineer, enjoyed being one and was good at it.&lt;/p&gt;
&lt;p&gt;He left.&lt;/p&gt;
&lt;p&gt;That left a gap.&lt;/p&gt;
&lt;p&gt;A gap a consultancy could fill.&lt;/p&gt;
&lt;p&gt;I’ve written about that engineer before, from the team’s side, in &lt;a href=&quot;https://arrangeactassert.com/posts/good-products-die-when-people-become-resources/&quot;&gt;good products die when people become resources&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That bothered me then.&lt;/p&gt;
&lt;p&gt;It bothers me even more now.&lt;/p&gt;
&lt;h2 id=&quot;sometimes-the-best-solution-is-boring&quot;&gt;Sometimes the best solution is boring&lt;/h2&gt;
&lt;p&gt;I’ve seen the same thing with technology.&lt;/p&gt;
&lt;p&gt;A straightforward problem needs microservices, CQRS, event sourcing or whatever happens to be interesting at the time.&lt;/p&gt;
&lt;p&gt;It looks like CV-driven development.&lt;/p&gt;
&lt;p&gt;I love new technology. Our job as engineers is to solve problems, though, and a clever system is not the same as a solved problem.&lt;/p&gt;
&lt;p&gt;Sometimes the best solution is boring.&lt;/p&gt;
&lt;p&gt;The same instinct hires a scrum master for a team that’s already working, or adopts a framework nobody asked for. I’ve seen &lt;a href=&quot;https://arrangeactassert.com/posts/velocity-theatre-and-the-people-who-measure-the-wrong-thing/&quot;&gt;what that did to one team&lt;/a&gt;, and I’ve written about why you should &lt;a href=&quot;https://arrangeactassert.com/posts/before-you-change-the-process-understand-the-problem/&quot;&gt;understand the problem before you change the process&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A consultancy that finds problems which don’t exist is doing the same thing, with a bill attached.&lt;/p&gt;
&lt;h2 id=&quot;they-dont-land-and-expand&quot;&gt;They don’t land and expand&lt;/h2&gt;
&lt;p&gt;I’ve also seen consultancy done properly.&lt;/p&gt;
&lt;p&gt;Consultants who listen before telling, who understand why something exists before trying to replace it, and who share what they know so the existing team gets stronger.&lt;/p&gt;
&lt;p&gt;They don’t create dependency.&lt;/p&gt;
&lt;p&gt;That is what I like about Equal Experts.&lt;/p&gt;
&lt;p&gt;One of their values is to put customer success ahead of their own short-term interests. They also explain what that means in practice.&lt;/p&gt;
&lt;p&gt;They say they don’t “land and expand”.&lt;/p&gt;
&lt;p&gt;If they’re no longer the right solution, they should leave. When they run out of ways to add value, they aim to leave the customer in a better place than they found them.&lt;/p&gt;
&lt;p&gt;That is a different incentive.&lt;/p&gt;
&lt;p&gt;Their engineering principles struck a chord with me too: understand the context, choose the right tool for the job and avoid over-engineering.&lt;/p&gt;
&lt;p&gt;That is good consultancy.&lt;/p&gt;
&lt;p&gt;Come in. Understand. Help. Share what you know. Leave people stronger than you found them.&lt;/p&gt;
&lt;p&gt;And know when to leave.&lt;/p&gt;
&lt;h2 id=&quot;same-idea-different-subject&quot;&gt;Same idea, different subject&lt;/h2&gt;
&lt;p&gt;It’s also why I’m pleased to be doing this talk with Equal Experts.&lt;/p&gt;
&lt;p&gt;It’s called: Magic vs Science: Making AI Coding Agents Prove Their Work&lt;/p&gt;
&lt;p&gt;The talk is about moving past AI coding tricks and witchcraft, and using engineering practices to make generated code prove itself: testing, feedback, maintainability and observability.&lt;/p&gt;
&lt;p&gt;Equal Experts’ own engineering principles talk about fast feedback, well-tested code and proactive monitoring.&lt;/p&gt;
&lt;p&gt;Different subject, same idea.&lt;/p&gt;
&lt;p&gt;Good engineering shouldn’t rely on magic.&lt;/p&gt;
&lt;p&gt;It should demonstrate its value.&lt;/p&gt;
</content:encoded></item><item><title>Test WebMCP tools like an API (with Playwright)</title><link>https://arrangeactassert.com/posts/webmcp-tools-are-an-api-test-them-like-one/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/webmcp-tools-are-an-api-test-them-like-one/</guid><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The Chrome team’s &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/best-practices&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;best practices&lt;/a&gt; and &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/use-cases&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;use cases&lt;/a&gt; guides end on evaluation tests.&lt;/p&gt;
&lt;p&gt;Evals cover the agent’s judgement. Did it pick the right tool, did it fill the form the way the user meant, did it stop when it should have asked. You can’t hard-code those outcomes, which is why the guides send you to &lt;a href=&quot;https://web.dev/learn/ai/evaluation-driven-development&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;evaluation-driven development&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Underneath that sits a layer that is deterministic and dull. Once your page calls &lt;code&gt;registerTool&lt;/code&gt;, it advertises callable functions with typed schemas to whatever agent is driving. That’s an API. Get an &lt;code&gt;enum&lt;/code&gt; wrong and an agent walks a path your buttons never allow, and the eval that catches it will report that the model got confused. Your UI tests will never see it.&lt;/p&gt;
&lt;p&gt;I measured what Chrome 152 does when an agent calls these methods.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com/static/gifs/webmcp-tests.gif&quot; alt=&quot;The default lane on the command line: the six WebMCP tests, plus the two auth setup tests the chromium project depends on, passing in under three seconds&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-api-you-didnt-know-you-shipped&quot;&gt;The API you didn’t know you shipped&lt;/h2&gt;
&lt;p&gt;This is the imperative API: &lt;code&gt;registerTool&lt;/code&gt; in script. The same contract test applies when Chrome synthesises the schema from &lt;code&gt;toolname&lt;/code&gt; on a form.&lt;/p&gt;
&lt;p&gt;The cart page registers two, &lt;code&gt;add_to_cart&lt;/code&gt; and &lt;code&gt;get_cart&lt;/code&gt;. This is the one with a schema worth testing:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;add_to_cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Add a quantity of one catalogue item to the cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  inputSchema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;object&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    properties&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      sku&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;espresso&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cold-brew&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      qty&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    required&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;sku&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;qty &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read that as a developer and it’s a function. Read it as an agent and it’s a contract: these are the arguments, this one is mandatory, and the only two SKUs in the world are espresso and cold brew. The agent builds its call from the schema before it ever touches your handler.&lt;/p&gt;
&lt;p&gt;A typo in that &lt;code&gt;enum&lt;/code&gt; is a production bug your UI tests will never see. Your buttons don’t read the schema. The agent reads nothing else.&lt;/p&gt;
&lt;h2 id=&quot;two-problems-before-you-write-a-single-test&quot;&gt;Two problems before you write a single test&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Bundled Chromium has no WebMCP.&lt;/strong&gt; Playwright ships its own Chromium, and &lt;code&gt;document.modelContext&lt;/code&gt; isn’t in it. Your everyday suite can’t see the API at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chrome ships it behind flags, on a moving draft.&lt;/strong&gt; The surface has already moved once, from &lt;code&gt;navigator&lt;/code&gt; to &lt;code&gt;document&lt;/code&gt;. A suite pinned to today’s behaviour goes stale without telling you.&lt;/p&gt;
&lt;p&gt;Solve the first by faking the browser and you inherit the second: your fake drifts away from Chrome and your tests keep passing. So &lt;a href=&quot;https://github.com/jagreehal/playwright-cookbook/tree/main/src/42-webmcp-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;card 42&lt;/a&gt; runs two lanes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lane&lt;/th&gt;
&lt;th&gt;Browser&lt;/th&gt;
&lt;th&gt;Runs&lt;/th&gt;
&lt;th&gt;Proves&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;default&lt;/td&gt;
&lt;td&gt;bundled Chromium, &lt;code&gt;document.modelContext&lt;/code&gt; double&lt;/td&gt;
&lt;td&gt;every &lt;code&gt;pnpm test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;your page’s tools: schemas, handlers, and the state they share with the UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;native&lt;/td&gt;
&lt;td&gt;real Chrome with the flags on&lt;/td&gt;
&lt;td&gt;on demand&lt;/td&gt;
&lt;td&gt;the double still matches the browser&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You’ll spend your time in the default lane. It runs on any machine, needs no flagged browser, and tests the code you wrote. The native lane exists to stop the double turning into fiction.&lt;/p&gt;
&lt;h2 id=&quot;the-everyday-lane&quot;&gt;The everyday lane&lt;/h2&gt;
&lt;p&gt;The double goes in through &lt;code&gt;addInitScript&lt;/code&gt;, which runs before any page script, so the page finds &lt;code&gt;document.modelContext&lt;/code&gt; exactly where it expects it. Reverse that order and the page registers nothing.&lt;/p&gt;
&lt;p&gt;Then you test the tools the way an agent would use them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The schema is the contract, so assert on it.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a tool schema names the arguments an agent must send&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tool&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; schema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tool&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inputSchema&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;required&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;sku&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;properties&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;enum&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;espresso&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cold-brew&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;JSON.parse&lt;/code&gt;. The spec stringifies &lt;code&gt;inputSchema&lt;/code&gt; on the descriptor for the imperative API, so &lt;code&gt;tool.inputSchema.properties&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt; and a test that forgets this passes for the wrong reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One cart, two doors.&lt;/strong&gt; An agent calling a tool and a user clicking a button have to land in the same state. This is the assertion I’d fight to keep if I could only have one:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a tool call and a click reach the same cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByTestId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;add-cold-brew&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tools &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; add &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tool&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; tool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;add_to_cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;executeTool&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sku&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;espresso&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByTestId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cart-count&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByTestId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContainText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1 x cold-brew&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByTestId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContainText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1 x espresso&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A tool that reports success while the cart stays empty has lied to the agent, and only the UI assertion catches it. The best practices guide asks you to update the interface once a function completes, because agents read the interface to plan their next step. This is that bullet, written as a test.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com/static/gifs/webmcp-ui-mode.gif&quot; alt=&quot;The same six WebMCP tests in Playwright UI mode, scoped to the card so the setup tests are out of shot, with the cart test selected. The trace shows the click, the executeTool call, and a DOM snapshot holding one cold brew and one espresso&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The browser that never shipped the API.&lt;/strong&gt; Most of your users are on one. Drop the double and check the page still sells coffee:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addInitScript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;modelContext&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; configurable&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The best practices guide also asks you to register tools when a page state makes them useful and unregister them after. An &lt;code&gt;AbortSignal&lt;/code&gt; owns that lifetime, which is how a component drops its tools on unmount. Assert both halves, because a tool that outlives the screen it belongs to is an agent calling into a page state you’ve already torn down:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;an AbortSignal drops the registration it owns&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; names &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; controller &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AbortController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;temporary_probe&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Registered for the length of one controller&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ok&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; signal&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; controller&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;signal &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; before &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    controller&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; after &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; after&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; before &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;names&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;before&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;temporary_probe&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;names&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;after&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;temporary_probe&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one runs in the native lane. The everyday lane could run it against the double, but I am the one who taught the double to drop a tool on abort, so the test would only ever agree with itself. A claim about the browser has to be checked against the browser.&lt;/p&gt;
&lt;h2 id=&quot;what-chrome-actually-does&quot;&gt;What Chrome actually does&lt;/h2&gt;
&lt;p&gt;Measured against Chrome 152.0.7977.65, not read off the explainer:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;th&gt;What Chrome does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getTools()&lt;/code&gt; order&lt;/td&gt;
&lt;td&gt;sorted by name, ignoring registration order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inputSchema&lt;/code&gt; on a descriptor&lt;/td&gt;
&lt;td&gt;a JSON &lt;strong&gt;string&lt;/strong&gt;, so parse before asserting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;executeTool(tool, input)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the &lt;a href=&quot;https://webmachinelearning.github.io/webmcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;draft&lt;/a&gt; takes an object; Chrome 152 wants a JSON string, and an object rejects with &lt;code&gt;UnknownError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;handler returns an object&lt;/td&gt;
&lt;td&gt;serialised, so &lt;code&gt;{a:1}&lt;/code&gt; arrives as &lt;code&gt;&apos;{&quot;a&quot;:1}&apos;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;handler returns &lt;code&gt;undefined&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;arrives as the string &lt;code&gt;&quot;undefined&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;handler throws&lt;/td&gt;
&lt;td&gt;the call &lt;strong&gt;rejects&lt;/strong&gt; with &lt;code&gt;UnknownError&lt;/code&gt;, and your message is replaced with a generic one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;duplicate tool name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;InvalidStateError&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AbortSignal&lt;/code&gt; on registration&lt;/td&gt;
&lt;td&gt;aborting withdraws the tool&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The throwing case is the one that will cost you an afternoon. Your handler raises &lt;code&gt;Unknown SKU: tea&lt;/code&gt;, and the agent receives none of that. It gets a rejection and a sentence about a script function that failed.&lt;/p&gt;
&lt;p&gt;The guides tell you to validate strictly in code and loosely in schema, and to write errors the model can self-correct from. That advice only works if you return the error rather than throw it:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sku&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;qty &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Could not add that item: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-double-is-a-claim&quot;&gt;The double is a claim&lt;/h2&gt;
&lt;p&gt;A test double says “this is what the browser does”. Nothing keeps that claim true except reading the original again, which is the native lane’s only job. It drives real Chrome with the flags on, and the files end in &lt;code&gt;.contract.ts&lt;/code&gt; so the everyday run skips them.&lt;/p&gt;
&lt;p&gt;It earned its place while I was building the card. My double resolved a throwing handler with the error message as text, which is what the WebMCP libraries I’d read do: they catch, and hand the agent something readable. I credited the browser for library behaviour. The first native run rejected instead, and both lanes now assert what Chrome does.&lt;/p&gt;
&lt;p&gt;When one of these fails, suspect the double before the browser.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;the browser owns the context, not a page script&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shape &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    registerTool&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;registerTool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    onPrototype&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shape&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;registerTool&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[native code]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shape&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onPrototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;registerTool&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That test fails if the double leaks into the native lane, which is the failure mode that would quietly invalidate everything else.&lt;/p&gt;
&lt;h2 id=&quot;two-traps&quot;&gt;Two traps&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;data:&lt;/code&gt; URL has no WebMCP.&lt;/strong&gt; Its origin is opaque, and &lt;code&gt;document.modelContext&lt;/code&gt; is absent there in a browser that exposes it on every real page. Probe on &lt;code&gt;http://localhost&lt;/code&gt;. I lost an hour concluding the feature was missing from a Chrome that had it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version checks lie.&lt;/strong&gt; &lt;code&gt;&amp;gt;= 152&lt;/code&gt; passes on a build with the flags off and fails on a future build that renames nothing. Ask the browser, on the page you’re about to test:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; available &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelContext&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;registerTool &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;function&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;available&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;This Chrome exposes no document.modelContext&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then feature-detect &lt;code&gt;executeTool&lt;/code&gt; on its own. The draft puts it on &lt;code&gt;ModelContext&lt;/code&gt;, but Chrome’s testing surface is behind &lt;code&gt;WebMCPTesting&lt;/code&gt;. A browser can expose registration without the hook, or the hook can disagree with the IDL, which is why the native lane exists.&lt;/p&gt;
&lt;h2 id=&quot;where-the-evals-start&quot;&gt;Where the evals start&lt;/h2&gt;
&lt;p&gt;None of this tells you whether an agent picks &lt;code&gt;add_to_cart&lt;/code&gt; over &lt;code&gt;search_products&lt;/code&gt;, whether your description reads as an execution or an initiation, or whether an agent can complete the shopping list on the &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/use-cases&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;use-cases page&lt;/a&gt; without adding the same item to two carts. Those are the questions the Chrome guides point at, and they need an agent in the loop.&lt;/p&gt;
&lt;p&gt;They also assume the layer underneath holds. Every eval you run against a wrong &lt;code&gt;enum&lt;/code&gt; measures your model’s patience with your schema.&lt;/p&gt;
&lt;hr&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; test:webmcp            &lt;span class=&quot;token comment&quot;&gt;# default lane, no special browser&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; test:webmcp:native     &lt;span class=&quot;token comment&quot;&gt;# native lane, needs a Chrome with WebMCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The native lane wants a Chrome that ships WebMCP, launched with &lt;code&gt;--enable-experimental-web-platform-features&lt;/code&gt; and &lt;code&gt;--enable-features=WebMCPTesting,DevToolsWebMCPSupport&lt;/code&gt;. Point &lt;code&gt;CHROME_BIN&lt;/code&gt; at it if the default search misses yours.&lt;/p&gt;
&lt;p&gt;The pattern is also an agent skill, &lt;a href=&quot;https://github.com/jagreehal/playwright-cookbook/tree/main/skills/playwright-webmcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;playwright-webmcp&lt;/code&gt;&lt;/a&gt;. It wires the two lanes into a repo and carries the Chrome behaviours as a reference file the agent has to read before it writes the double. That’s the part I’d otherwise expect an agent to get wrong, because the libraries it has seen catch handler errors and return the message as text, and it will write that down as browser behaviour. Mine did.&lt;/p&gt;
&lt;p&gt;WebMCP is a draft under active discussion, so some of the table above will age. The native lane is how I’ll find out when it does.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The card: &lt;a href=&quot;https://github.com/jagreehal/playwright-cookbook/tree/main/src/42-webmcp-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;src/42-webmcp-tools&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Live card docs: &lt;a href=&quot;https://jagreehal.github.io/playwright-cookbook/cards/42&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Card 42&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Live harness: &lt;a href=&quot;https://jagreehal.github.io/playwright-cookbook/webmcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;/webmcp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The skill: &lt;a href=&quot;https://github.com/jagreehal/playwright-cookbook/tree/main/skills/playwright-webmcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;skills/playwright-webmcp&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The explainer: &lt;a href=&quot;https://github.com/webmachinelearning/webmcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;webmachinelearning/webmcp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Chrome’s guides: &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/best-practices&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;best practices&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/use-cases&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;use cases&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/build-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;build tools&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/ai/webmcp/secure-tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;secure tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Instrument Before You Know the Question</title><link>https://arrangeactassert.com/posts/instrument-before-you-know-the-question/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/instrument-before-you-know-the-question/</guid><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Dave Farley tells a story about an organisation that took months to ship a release. Staged, layered, careful. While someone walked him through the process, he asked what happens when production breaks and a fix has to go out now.&lt;/p&gt;
&lt;p&gt;“Oh, we can do a type seven release in under an hour.”&lt;/p&gt;
&lt;p&gt;So why not run every release as a type seven?&lt;/p&gt;
&lt;p&gt;“We couldn’t possibly do that. The risk is too high.”&lt;/p&gt;
&lt;p&gt;Type seven was their name for skipping every check the normal process existed to run, shipping the diff, and hoping. That organisation kept two paths to production: one so slow nobody could learn from it, and one so dangerous they saved it for emergencies.&lt;/p&gt;
&lt;p&gt;Your observability has a type seven too.&lt;/p&gt;
&lt;p&gt;You know the shape of it. Production is misbehaving, your dashboards answer none of the questions you have, so someone adds a log line and ships it. Waits for the deploy. Reads the output. Adds another log line. Or flips debug logging on across a service for twenty minutes and flips it off before the bill arrives. Or attaches a debugger to a live process and holds their breath.&lt;/p&gt;
&lt;p&gt;Nobody files that under “the normal process failed”. It goes under incident response, where uncomfortable things go to be forgiven.&lt;/p&gt;
&lt;p&gt;The talk this story comes from is worth watching in full:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/5YF7najQ7Eg?si=kjet1CRvek9Dmxgz&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Organisations that get this right never need a type seven. Releasing is already cheap and fast enough that even a real emergency uses the normal path, with the safety still in it. Fast and safe stop being a trade-off. Two paths exist when you plan your way through a system that only yields to learning.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-88-percent&quot;&gt;The 88 percent&lt;/h2&gt;
&lt;p&gt;Bain and Company put the number of business transformation efforts that fall short of their aims at 88 percent. Farley quotes it from Dave Clack’s book, and his reading of it is the one I find convincing: at that rate you are not looking at variance. You are looking at a method that does not work.&lt;/p&gt;
&lt;p&gt;His diagnosis comes from Cynefin. An organisation that builds software is a complex adaptive system. Two properties define that kind of system: you can see cause and effect only in hindsight, and the system shifts while you interact with it. A fixed multi-step plan is worse than useless in a system like that, because the first step changes the ground the other steps were standing on.&lt;/p&gt;
&lt;p&gt;Give the same feature to two developers and you get two different systems, and you cannot say in advance which will be easier to change next month. Someone hands in their notice and the project speeds up, slows down, or falls over, and nobody can tell you which beforehand.&lt;/p&gt;
&lt;p&gt;Guessing without feedback is how you leave complex and enter chaotic. A type seven debug session is that slide: you add a log line because the data is not there, you wait, you guess again. Always-on instrumentation is what keeps the work in probe, sense, and respond. Run a small change, watch what it does, keep it or step back. Farley lists four conditions that make this possible:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Safety to be wrong when you were trying to be right&lt;/li&gt;
&lt;li&gt;Changes small enough and reversible enough that being wrong is cheap&lt;/li&gt;
&lt;li&gt;A guess, a way to check the guess, and a short gap between them&lt;/li&gt;
&lt;li&gt;Language that lands with the people you need on board&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Condition one is a leadership behaviour. Condition four is a conversation. Condition two is version control, automated tests, and a deployment pipeline, which most teams have spent a decade getting good at.&lt;/p&gt;
&lt;p&gt;He named a practice, not a product. What that practice looks like in the code is a tooling gap, and it is the one that gets skipped.&lt;/p&gt;
&lt;h2 id=&quot;a-change-with-no-check-is-a-gamble&quot;&gt;A change with no check is a gamble&lt;/h2&gt;
&lt;p&gt;Farley is blunt about it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A change that has no expected outcome and no way to measure the result isn’t an experiment at all. It’s just a change, and that’s a gamble that you can’t learn from.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Count the changes your team merged last month. Now count the ones where somebody wrote down what they expected to see, and could go and look. If your answer is anything like the teams I work with, the second number is small and clusters around the changes that scared people.&lt;/p&gt;
&lt;p&gt;Everything else went out as a gamble the team called continuous improvement.&lt;/p&gt;
&lt;p&gt;The reason is timing, and it is boring. Instrumentation gets treated as something you add when you need it, which means you add it once you needed it, which is after the moment you could have learned anything from it. The type seven debug session is what that policy looks like at 2am.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jagreehal.github.io/autotel/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;autotel&lt;/a&gt; exists to move the check to the same moment as the change. Every example in this post is exercised in the repo, and the assertions exit non-zero when a claim stops holding.&lt;/p&gt;
&lt;p&gt;The loop is guess, instrument, change, observe, compare, learn.&lt;/p&gt;
&lt;p&gt;Most teams can already guess and change. They can usually observe something. The gaps are instrumenting before you know the question, and comparing what happened against what you expected.&lt;/p&gt;
&lt;h2 id=&quot;you-cannot-know-which-dimension-will-matter&quot;&gt;You cannot know which dimension will matter&lt;/h2&gt;
&lt;p&gt;If cause and effect are visible only in hindsight, then hindsight needs the data to have been there at the time. Picking three fields to log in advance is a bet that you know which three will explain a failure you have not seen yet. In a complex adaptive system, that is a bet you should expect to lose.&lt;/p&gt;
&lt;p&gt;So write one event per unit of work carrying the dimensions that describe the work, not the person: plan, region, flag values, payment provider, which cache the read came from, how many items were in the cart. Not because you will look at all of them. Because you cannot know which one you will need. That is the wide event argument I made in &lt;a href=&quot;https://arrangeactassert.com/posts/logging-sucks/&quot;&gt;Logging Sucks&lt;/a&gt;, arriving from the other side: there it was about the questions logs cannot answer, here it is about the questions an experiment cannot answer.&lt;/p&gt;
&lt;p&gt;You guess the outcome, which is the thing your change is about: p95, conversion, error rate. You instrument the context, which is the thing that will explain the outcome: plan, region, flag, provider, cart size. Knowing what you are aiming at has never told anyone which variable will turn out to matter.&lt;/p&gt;
&lt;p&gt;Redact anything that identifies a person at the boundary. Every field still costs storage and query time, which is what sampling is for, and what &lt;code&gt;bucket()&lt;/code&gt; below is for. Neither is a reason to pick three fields up front and hope.&lt;/p&gt;
&lt;h2 id=&quot;the-guess-ships-with-the-code&quot;&gt;The guess ships with the code&lt;/h2&gt;
&lt;p&gt;A span is the start. The dimensions and the guess have to go in the same file.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trace &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; checkout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; quote &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;priceCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;quote&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fulfil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payment&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That function is now a span: timing, failures, and a parent for everything it calls. Anything instrumented that runs inside it attaches itself without being handed anything.&lt;/p&gt;
&lt;p&gt;Timing and errors tell you a change did not break. They do not tell you whether your guess held, or why. For that you name the dimensions the request ran under, while you are writing the code:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withTracing&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; getRequestLogger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; postCheckout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withTracing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; log &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getRequestLogger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      plan&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;plan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      cart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;length &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      pricing&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processCheckout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; result&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emitNow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One event per request, carrying the state that request ran under. This costs about thirty seconds while you are already in the file. It costs an incident to add later.&lt;/p&gt;
&lt;p&gt;That records what happened. It does not record what you expected, which is the other half of Farley’s condition. So autotel has a primitive for the guess itself:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; experiment &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; checkout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;experiment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;checkout-pricing&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    variant&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    expect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;p95 drops, conversion holds&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; quote &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;priceCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fulfil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;quote&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every span in that request now carries &lt;code&gt;experiment.name&lt;/code&gt;, &lt;code&gt;experiment.variant&lt;/code&gt; and &lt;code&gt;experiment.expectation&lt;/code&gt;. The two cohorts you want to compare are selectable from the telemetry rather than reconstructed a week later from deploy timestamps, and the expectation travels with them, so whoever opens the trace in a month reads the claim alongside the result.&lt;/p&gt;
&lt;p&gt;That string is not itself a check, and it would be dishonest to call it one. It is the claim, written down at the moment you are least tempted to flatter it, and carried to the place the result will show up. That is the honest measurement he asked for. The checking happens later, in the comparison. Writing it here is what makes the comparison possible at all, because a claim nobody recorded cannot be checked, only remembered generously.&lt;/p&gt;
&lt;p&gt;Numeric fields need one more thing before they can explain anything:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; bucket &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel/analysis&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;cart.size&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A raw count takes a near-unique value per request, and a value that never repeats cannot describe a group. Bucketing at instrumentation time is what turns it into a field that can.&lt;/p&gt;
&lt;h2 id=&quot;mark-change-compare&quot;&gt;Mark, change, compare&lt;/h2&gt;
&lt;p&gt;Once every request carries its dimensions, probe-sense-respond stops being a metaphor and becomes something you run.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; compareCohorts &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel/analysis&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; differences &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compareCohorts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  outlier&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; slowCheckouts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  baseline&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; normalCheckouts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;compareCohorts&lt;/code&gt; ranks the field and value pairs that separate the group you are investigating from a normal population. It answers the question you have during an incident: what is different about the ones that broke.&lt;/p&gt;
&lt;p&gt;Two details in it matter more than the function does. It skips fields whose values never repeat, which is why &lt;code&gt;bucket()&lt;/code&gt; exists at the instrumentation end. And its output is labelled a hypothesis, to be confirmed against individual traces. That is incident exploration, not Farley’s check. His check is whether the outcome you named showed up. The person in Compare, reading the claim that travelled with the spans, is how you decide you have seen it.&lt;/p&gt;
&lt;p&gt;The devtools UI is closer to the loop he describes. Mark a moment. Change something. Compare after against before. The mark is the probe, the comparison is the sense, and what you do next is the respond.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;experiment()&lt;/code&gt; writes the name and the arm onto every span, Compare reads them back: pick &lt;code&gt;checkout-pricing&lt;/code&gt; and it offers you its arms, instead of asking you to type two queries and remember what you called the variants.&lt;/p&gt;
&lt;h2 id=&quot;the-speed-of-the-loop-is-the-speed-you-learn&quot;&gt;The speed of the loop is the speed you learn&lt;/h2&gt;
&lt;p&gt;That short gap is the rest of condition three. Farley puts it in one line: “the speed of that loop is the speed at which your organization can learn.”&lt;/p&gt;
&lt;p&gt;This is where most observability stacks lose. Your telemetry lives in a vendor’s backend, so to see the result of a change you deploy it, wait for the pipeline, wait for ingestion, open a dashboard, and by then it is tomorrow and you are on a different problem. The loop is a day long, so the team runs a handful of real experiments a year and calls the rest “delivery”.&lt;/p&gt;
&lt;p&gt;autotel-devtools puts an OTLP receiver on your machine. Spans arrive as you exercise the code, in a UI with a query language over them:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;service = api AND duration &amp;gt; 100
name CONTAINS checkout
http.status_code = 500&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The loop is seconds. Every field a service emits is queryable without being declared anywhere, so a question you did not anticipate does not need a schema change and a deploy before you can ask it.&lt;/p&gt;
&lt;p&gt;A team that can answer a question in seconds asks more questions. That is the whole mechanism.&lt;/p&gt;
&lt;p&gt;A production experiment still waits on a deploy and on whatever backend you ship to, and no receiver running on your laptop changes that. What it changes is what you ship. You find out on your machine that the field you needed is missing, while adding it costs thirty seconds, instead of finding out from a dashboard a week after the change went out and the window closed. Production is not where you rehearse the question. It is where the answer matters.&lt;/p&gt;
&lt;h2 id=&quot;you-cannot-experiment-on-a-part-of-the-system-you-cannot-see&quot;&gt;You cannot experiment on a part of the system you cannot see&lt;/h2&gt;
&lt;p&gt;Some of your code emits nothing. Not the parts you would guess, either. &lt;code&gt;npx autotel map&lt;/code&gt; records every entry point and scores what it emits. Coverage lists the handlers that have emitted nothing: the places where you can change them, ship them, and learn nothing. A missing map 404s rather than looking clean, because a false bill of health is worse than no report.&lt;/p&gt;
&lt;h2 id=&quot;the-trace-you-cannot-afford-to-lose&quot;&gt;The trace you cannot afford to lose&lt;/h2&gt;
&lt;p&gt;Sampling is what makes always-on instrumentation affordable, and it is how you lose the declined payment that looked like the other ten thousand. A request carrying &lt;code&gt;baggage: autotel.debug=1&lt;/code&gt; keeps its trace with no deploy and no debug logging across the service. That is a better type seven, not the end of them. Farley’s version is that the emergency path disappears because the normal one is already fast and safe enough: if the request that broke already emitted its plan, its provider and its cart size, you are reading, not reproducing.&lt;/p&gt;
&lt;h2 id=&quot;survival-is-not-mandatory&quot;&gt;Survival is not mandatory&lt;/h2&gt;
&lt;p&gt;Deming said it, and Farley quotes it: it is not necessary to change, because survival is not mandatory.&lt;/p&gt;
&lt;p&gt;The companies that come through a decade of this are not the ones that predicted it. Nobody predicts a complex adaptive system. They are the ones that got cheap at finding things out, and stayed cheap at it while everyone else was building a business case for a dashboard.&lt;/p&gt;
&lt;p&gt;I did not write autotel to produce traces. Traces are a means. I wrote it so that the gap between changing something and knowing what you changed collapses to something short enough that your team runs experiments without scheduling them, and so that the answer is waiting when the question arrives rather than being bolted on at 2am by someone who is guessing.&lt;/p&gt;
&lt;p&gt;Farley ends with a swap: stop asking how do we get this right, start asking how do we learn what to do next.&lt;/p&gt;
&lt;p&gt;That second question has a precondition nobody says out loud. It assumes your system can answer. Most cannot, which is why so many teams ask the first question instead. It is the only one their tooling can hear.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Every API in this post ships in autotel 7.2.0 and later.&lt;/p&gt;
&lt;p&gt;The loop runs in &lt;a href=&quot;https://github.com/jagreehal/autotel/tree/main/apps/example-experiment&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;apps/example-experiment&lt;/code&gt;&lt;/a&gt;: 800 checkouts across both arms of a pricing experiment, one planted cause for the slow ones, and an assertion that &lt;code&gt;compareCohorts&lt;/code&gt; finds it without being told. Sampling, coverage, &lt;code&gt;--baseline&lt;/code&gt; and &lt;code&gt;--min-score&lt;/code&gt; have their own checks, in that app and in &lt;a href=&quot;https://github.com/jagreehal/autotel/tree/main/apps/example-hono&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;apps/example-hono&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They exit non-zero when a claim stops being true, which is the bargain this post is making: a claim with no way to check it is a gamble.&lt;/p&gt;
&lt;p&gt;autotel is open source and works with any OTLP backend: &lt;a href=&quot;https://github.com/jagreehal/autotel&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/autotel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your team still equates “we adopted OTel” with the three-pillars stack, read &lt;a href=&quot;https://arrangeactassert.com/posts/otel-is-not-the-three-pillars/&quot;&gt;OpenTelemetry Is Not the Three Pillars&lt;/a&gt; (draft) and run &lt;a href=&quot;https://github.com/jagreehal/autotel/tree/main/apps/example-pillars-vs-unified&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;apps/example-pillars-vs-unified&lt;/code&gt;&lt;/a&gt;. Put an LLM in the call stack and the same rule holds: &lt;a href=&quot;https://arrangeactassert.com/posts/you-cant-ship-agents-like-software/&quot;&gt;You Can’t Ship Agents Like Software&lt;/a&gt; (draft).&lt;/p&gt;
&lt;p&gt;The type seven story, the four conditions, and the Cynefin framing are Dave Farley’s, from &lt;a href=&quot;https://www.youtube.com/watch?v=5YF7najQ7Eg&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How to Build a Team of Devs That Improves Itself&lt;/a&gt; on the Modern Software Engineering channel. The 88% figure is Bain and Company’s, quoted in Dave Clack’s &lt;em&gt;The Case for Connection&lt;/em&gt;.&lt;/p&gt;
</content:encoded></item><item><title>The $1 House Still Needs a Site Survey</title><link>https://arrangeactassert.com/posts/the-dollar-house-still-needs-a-site-survey/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-dollar-house-still-needs-a-site-survey/</guid><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Matt Pocock got Uncle Bob on a livestream, and the bit I keep coming back to is the house.&lt;/p&gt;
&lt;p&gt;Bob asks you to imagine that every change to a house costs a dollar. The foundation, the roof, moving the kitchen, moving the stairs. All of it, a dollar.&lt;/p&gt;
&lt;p&gt;Would you pay an architect thousands to get the plan perfect before the contractor starts? Or would you tell them to put the foundation there, walk through it, decide the traffic pattern is wrong, and move the stairs?&lt;/p&gt;
&lt;p&gt;He is right about the plan. He leaves out the other half of what an architect does.&lt;/p&gt;
&lt;iframe
  src=&quot;https://www.youtube.com/embed/zcLPGC-tvgk&quot;
  title=&quot;Matt Pocock and Uncle Bob on agents, tests and architecture&quot;
  style=&quot;width:100%; aspect-ratio:16/9;&quot;
  frameborder=&quot;0&quot;
  allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot;
  allowfullscreen
&gt;&lt;/iframe&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;what-bob-gave-up-and-what-he-kept&quot;&gt;What Bob gave up, and what he kept&lt;/h2&gt;
&lt;p&gt;Bob is blunt about heavy up front specification. He tried it, he was trying it again the week of the interview, and he calls the outcome the same every time: you write the plan, the agents run off half cocked on some nonsense the plan never anticipated, and you stop, rewrite, and start them over.&lt;/p&gt;
&lt;p&gt;The agents themselves make this worse, because they love writing plans. The plans come back gorgeous and full of things nobody can build. So he went back to the agile loop. Do a story or two, look at what came out, reorganise, do a bit more.&lt;/p&gt;
&lt;p&gt;What he did not give up is constraint.&lt;/p&gt;
&lt;p&gt;Later in the same conversation he describes a file that pins which module is allowed to depend on which, and how the dependencies should flow. A checker runs at the end of the loop.&lt;/p&gt;
&lt;p&gt;If the agents violated the rules they have to fix it, usually by inverting a dependency or splitting a module in half. He runs crap scores over the code and mutation testing over the tests, and the agents sit in that loop until the tools go green.&lt;/p&gt;
&lt;p&gt;Ask him about specifications and he says they are ephemeral and he throws them away. The dependency rules and the thresholds are the things he keeps.&lt;/p&gt;
&lt;p&gt;The distinction worth pulling out is prescription versus context.&lt;/p&gt;
&lt;p&gt;Matt raises this in the conversation and lets it go. He asks how much planning happens before the gauntlet starts, because putting the wrong work through it is wasteful, and he says out loud that building the wrong thing is still possible. Bob answers with the history of waterfall and the agile correction, which is a good answer to how much planning and not an answer to how you know it is the right work. The gauntlet is a delivery machine. Crap scores, mutation testing and a dependency checker will tell you the thing was built well. None of them can tell you whether it was worth building.&lt;/p&gt;
&lt;h2 id=&quot;the-architects-other-job&quot;&gt;The architect’s other job&lt;/h2&gt;
&lt;p&gt;An architect does not exist because moving a wall is expensive. Before anyone decides where the walls go, someone has to know whether the plot floods, which way the prevailing wind comes from, where the sun rises, what the planning authority will allow, where the utilities run, whether anyone living there uses a wheelchair, and whether the family will still fit in the house in twenty years.&lt;/p&gt;
&lt;p&gt;None of those answers get cheaper because the contractor works for a dollar a change. You can iterate at enormous speed and end up with a beautifully built house facing the wrong way on a floodplain. You are placing &lt;a href=&quot;https://arrangeactassert.com/posts/engineering-decisions-are-bets-not-proofs/&quot;&gt;a bet&lt;/a&gt; either way. The survey is what tells you the odds.&lt;/p&gt;
&lt;h2 id=&quot;the-interview-nobody-passes-by-typing&quot;&gt;The interview nobody passes by typing&lt;/h2&gt;
&lt;p&gt;There is a version of this you have probably sat through. You walk into a principal engineer system design interview and the panel says: design a system for X. If your first answer is “let’s start coding and discover the architecture as we go”, you have not shown them any system design yet.&lt;/p&gt;
&lt;p&gt;What you do instead is ask. How many users? What is the read to write ratio? What consistency guarantees do we need? What happens when a region fails? What data are we storing and where is it allowed to live? What is the growth curve? Which parts of this cannot go down?&lt;/p&gt;
&lt;p&gt;They are the forces acting on the architecture, and they decide which implementations are even in the running.&lt;/p&gt;
&lt;p&gt;They get to this themselves. Matt reaches for John Ousterhout’s split between tactical and strategic programming, and both of them stop to pull the book off the shelf. Bob takes it as given: agents are strong at the tactical work and weak at the strategic. That list of questions is the strategic work. The agents did not make any of it cheaper.&lt;/p&gt;
&lt;h2 id=&quot;context-that-compiles&quot;&gt;Context that compiles&lt;/h2&gt;
&lt;p&gt;Bob’s reason for preferring tools over prompts has a name: lost in the middle. Anything you write at the top of a long context loses its grip as the window fills. A checker that fails the build does not, which is why I keep putting standards in &lt;a href=&quot;https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals/&quot;&gt;linters instead of prompt files&lt;/a&gt;. Sort your context into two piles.&lt;/p&gt;
&lt;p&gt;The first pile compiles. Module dependency rules in a file with a checker behind them, the way Bob does it. Complexity and coverage thresholds, &lt;a href=&quot;https://github.com/jagreehal/100-percent-test-coverage-is-false-hope&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;picked so a green gate means something&lt;/a&gt;. A performance budget expressed as a test that fails at 200ms. Data residency as a lint rule that rejects an import of the wrong region’s client. A public contract pinned by contract tests. Agents obey these because they run into them, not because they read them.&lt;/p&gt;
&lt;p&gt;The second pile does not compile. What are we optimising for. Which constraints are fixed and which are negotiable. What this system has to become when the thing the company announced last quarter actually ships. Who this is for and what happens to them when it breaks. No checker exists for any of that, and you cannot leave it in a prompt and expect it to survive. It also decides whether &lt;a href=&quot;https://arrangeactassert.com/posts/why-great-products-need-strong-foundations/&quot;&gt;the foundations hold&lt;/a&gt;: what you know is coming changes how you build now.&lt;/p&gt;
&lt;p&gt;Bob’s answer about juniors sits in that second pile. Asked how someone starting out learns the strategic half, he suggested they spend a few months being treated like an agent, given agent sized tasks and put through the same deterministic gauntlet, “horribly unproductive but learning a hell of a lot”.&lt;/p&gt;
&lt;p&gt;His own judgement came from somewhere else. He can spot an agent thrashing because he has watched systems thrash for fifty years. A principal engineer asks about regional failure because they were on call the night a region went down, and about data residency because they have watched a regulatory constraint arrive long after the architecture was set. The tactical work was the apprenticeship that produced the context.&lt;/p&gt;
&lt;p&gt;There is a second question underneath the one about juniors learning to code. Where does the next generation get its context from, if the ten years of implementation that used to supply it are the part we are handing to the agents? I do not have a good answer yet.&lt;/p&gt;
&lt;h2 id=&quot;direction-is-not-a-plan&quot;&gt;Direction is not a plan&lt;/h2&gt;
&lt;p&gt;The vision does not need to be two hundred pages. It can be a paragraph.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This system will serve millions of users across several regions, hold regulated financial data, and keep taking payments while a region is down.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That paragraph says nothing about the implementation. It rules out a large class of the implementations an agent would otherwise produce. You can still throw code away six times an hour inside it, which is the part Bob and Matt are right about. I still would not put customers in that house, for the same reason I would not put them in a &lt;a href=&quot;https://arrangeactassert.com/posts/when-does-a-vibe-coded-app-become-a-real-product/&quot;&gt;vibe-coded prototype&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That paragraph is a fence. It says what the system must never do. It does not say what anyone is trying to achieve, and an agent held inside a fence will build something nobody wanted, and build it well, at speed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When a customer’s card fails, they keep their service and understand what happened, without having to call us.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Matt has shown us something important about working with agents: we need to watch their tendency to go heads down too quickly. Give an agent a prompt and it starts writing code. Put it in plan mode and it produces a plan that often reads like the code in prose. In both cases, it has gone straight to cutting.&lt;/p&gt;
&lt;p&gt;What’s missing is what Brooks called the design concept: the underlying picture of the solution that sharpens through conversation before implementation begins.&lt;/p&gt;
&lt;p&gt;Matt’s &lt;a href=&quot;https://www.aihero.dev/skills-grill-me&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;grill-me&lt;/a&gt; is that conversation. The agent interviews until every branch is visited and nothing is left silently assumed. You work collaboratively with the agent to understand why the thing should exist, what outcome it should produce and which decisions follow from that. It does not build until you confirm that you share the same understanding.&lt;/p&gt;
&lt;p&gt;Then it executes while that conversation is still in context. It’s measure twice, cut once, even when cutting costs almost nothing.&lt;/p&gt;
&lt;h2 id=&quot;back-to-the-house&quot;&gt;Back to the house&lt;/h2&gt;
&lt;p&gt;The contractor moves any wall for a dollar, so use that. Do not spend six months deciding whether the kitchen island sits 20cm to the left. Build it, walk around it, move it.&lt;/p&gt;
&lt;p&gt;Before the first dollar, though, somebody has to say: we are on a floodplain, the wind comes off the west, one of the people living here uses a wheelchair, and we would like the house standing in thirty years.&lt;/p&gt;
&lt;p&gt;This is the site survey. It covers the ground, and it covers who is going to live on it: a family who cook together every night and have never once eaten in the dining room.&lt;/p&gt;
&lt;p&gt;One half tells you what the plot will allow, the other what the house is for.&lt;/p&gt;
&lt;p&gt;Neither half is a floor plan. A contractor who moves any wall for a dollar can satisfy both while you are still arguing about the island.&lt;/p&gt;
&lt;p&gt;As the cost of producing code falls towards nothing, working out the forces and where the system is heading is a larger share of what engineers are paid for.&lt;/p&gt;
</content:encoded></item><item><title>You Can&apos;t Support What You Didn&apos;t Record</title><link>https://arrangeactassert.com/posts/you-cant-support-what-you-didnt-record/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/you-cant-support-what-you-didnt-record/</guid><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Support asks a year after the payment: “Why did the customer receive €117? And which card did we charge?”&lt;/p&gt;
&lt;p&gt;A supportable system answers that with one query. If answering means trawling archived logs, guessing what the exchange rate was that day, and hoping nobody edited the payment method since, you don’t have a supportable system.&lt;/p&gt;
&lt;p&gt;Record the decision at the point you make it, and never destroy the data it points to.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You Can’t Support What You Didn’t Record&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2752px) 2752px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2752&quot; height=&quot;1536&quot; src=&quot;https://arrangeactassert.com/_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_Z26Yp6k.webp&quot; srcset=&quot;/_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_2h4Ug.webp 640w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_1atRC9.webp 750w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_hG5sE.webp 828w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_1CKYPI.webp 1080w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_1wnwdi.webp 1280w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_1LBHwK.webp 1668w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_1sE3pE.webp 2048w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_ZlRlUK.webp 2560w, /_astro/you-cant-support-what-you-didnt-record.DMAEvIfd_Z26Yp6k.webp 2752w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;two-rules&quot;&gt;Two rules&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rule 1: never overwrite reference data.&lt;/strong&gt; A payer’s stored payment method is reference data. When the payer changes it, insert a new row. When they remove it, set &lt;code&gt;deletedAt&lt;/code&gt;. No &lt;code&gt;UPDATE&lt;/code&gt;, no &lt;code&gt;DELETE&lt;/code&gt;, ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 2: snapshot the decision inputs on every transaction.&lt;/strong&gt; At the moment a payment executes, write down everything the decision depended on: which payment method, what rate, what amounts. Write the values as they were at that moment, on the payment record itself.&lt;/p&gt;
&lt;p&gt;I covered how the payment flow gathers those inputs into a context object in &lt;a href=&quot;https://arrangeactassert.com/posts/tracking-every-decision-in-payments/&quot;&gt;Tracking Every Decision in Payments&lt;/a&gt;. This post is about writing that context onto the durable record so support can still read it a year later.&lt;/p&gt;
&lt;p&gt;A payment record is a claim about the past, and if the data underneath it can change, the claim stops being true.&lt;/p&gt;
&lt;p&gt;Both rules protect that claim.&lt;/p&gt;
&lt;h2 id=&quot;internal-data-pointer-plus-snapshot&quot;&gt;Internal data: pointer plus snapshot&lt;/h2&gt;
&lt;p&gt;For data you own, keep both. The transfer record stores a pointer into the reference table and a snapshot of what the pointer resolved to at execution time:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentMethod&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;card&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bank_account&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  last4&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  deletedAt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// soft delete only&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransferRecord&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transferId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  paymentMethodId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// pointer, resolvable forever&lt;/span&gt;
  paymentMethod&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; last4&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// what it was at execution time&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pointer works because of Rule 1. The snapshot means support skips the join: the record itself says “card ending 4242”, and keeps saying it. When a dispute or audit needs the full reference row, soft-deleted or not, the pointer still resolves.&lt;/p&gt;
&lt;h2 id=&quot;external-data-capture-the-value&quot;&gt;External data: capture the value&lt;/h2&gt;
&lt;p&gt;The exchange rate came from someone else’s API. You can’t foreign-key into a third party’s history, so the value you captured is the only record you will ever have:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransferRecord&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  rate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// the rate we converted at&lt;/span&gt;
  rateCapturedAt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// when we fetched it&lt;/span&gt;
  convertedAmount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// what it produced&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The workflow stamps the rate the moment it fetches it:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchRate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GBP&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EUR&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// External data: capture it now, we can&apos;t point at the provider&apos;s history later&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rateCapturedAt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A month or a year later, “why €117?” has an answer: rate 1.17, captured at 14:53:12 UTC, applied to £100. Call the rate API at support time instead and you get today’s rate, a different number answering a different question.&lt;/p&gt;
&lt;h2 id=&quot;model-output-the-worst-external-data-of-all&quot;&gt;Model output: the worst external data of all&lt;/h2&gt;
&lt;p&gt;An exchange rate at least has a provider you could argue with. A model call has nothing. Same prompt, same model, different answer, and no history to refetch. If you didn’t record it, it never happened.&lt;/p&gt;
&lt;p&gt;So record the whole step: the model and version, the prompt, the tool calls it asked for, the arguments it sent, what each tool returned, and the final text.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ModelStep&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  toolCalls&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    toolName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// exactly as the model sent it&lt;/span&gt;
    output&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// absent if the tool never ran&lt;/span&gt;
    error&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; outputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The interesting field is the one that isn’t there. Here is a real run against a local &lt;code&gt;llama3.2&lt;/code&gt; with a calculator tool, arguments typed as &lt;code&gt;z.number()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tool-call&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;toolName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;calculator&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;input&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;23&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;invalid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AI_InvalidToolInputError: expected number, received string at path a&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The model sent strings. Validation rejected them, so &lt;code&gt;execute&lt;/code&gt; never ran. Then the model answered:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using the calculator tool, I get: 23 + 7 = 30&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It did not use the calculator tool. It guessed, and it happened to guess right. &lt;code&gt;finishReason&lt;/code&gt; was &lt;code&gt;stop&lt;/code&gt;. Nothing threw. Every dashboard stayed green.&lt;/p&gt;
&lt;p&gt;That is the whole argument for recording the step. The final text is the model’s account of what it did, and the model is not a reliable narrator. The tool call record is evidence. It shows the arguments the model actually produced, and its missing &lt;code&gt;output&lt;/code&gt; shows the tool never executed. The next question is only answerable because you kept it: was 30 arithmetic or a coin flip?&lt;/p&gt;
&lt;p&gt;Record the absences too, then. A tool that was offered and never called, a step that ended early, a validation failure that resolved itself. &lt;code&gt;null&lt;/code&gt; is a finding.&lt;/p&gt;
&lt;h2 id=&quot;what-goes-wrong-without-this&quot;&gt;What goes wrong without this&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Someone updates or hard-deletes a payment method row. Historic payments claim the wrong card, or point at nothing. Nothing errors. A chargeback investigation dead-ends eighteen months later.&lt;/li&gt;
&lt;li&gt;Someone answers a rate query by calling the rate API at support time. They report today’s rate to the customer, and it’s wrong.&lt;/li&gt;
&lt;li&gt;Someone logs only the model’s final text. A month later a customer disputes the number in it, and there is no way to tell whether a tool computed it or the model invented it. Re-running the prompt produces a different answer, which settles nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wide-events-same-idea&quot;&gt;Wide events, same idea&lt;/h2&gt;
&lt;p&gt;I’ve written about how &lt;a href=&quot;https://arrangeactassert.com/posts/logging-sucks/&quot;&gt;wide events beat scattered logs&lt;/a&gt;: one canonical event per request, carrying all the context that request accumulated.&lt;/p&gt;
&lt;p&gt;You apply the same discipline to storage. The wide event snapshots a request; the transfer record snapshots a transaction. The workflow writes the same values to both:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;transfer.id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; transfer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transferId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;transfer.rate&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;transfer.rate.captured_at&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; rateCapturedAt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;payment_method.id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; paymentMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;payment_method.last4&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; paymentMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;last4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Model steps go on the same event: &lt;code&gt;gen_ai.request.model&lt;/code&gt;, &lt;code&gt;gen_ai.tool.name&lt;/code&gt;, &lt;code&gt;gen_ai.usage.input_tokens&lt;/code&gt;. The span shows you this week’s latency spike; the record answers next year’s “did the tool run?”&lt;/p&gt;
&lt;p&gt;Keep both. Telemetry retention runs out in days or weeks, so the wide event serves this week’s incident. The transfer record outlives it and serves next year’s dispute.&lt;/p&gt;
&lt;h2 id=&quot;the-payoff&quot;&gt;The payoff&lt;/h2&gt;
&lt;p&gt;Support needs one endpoint:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/api/transfer/:id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; record &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTransferRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; record &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NotFound&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;transferId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TXN-001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;requestedAmount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;fromCurrency&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GBP&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;toCurrency&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EUR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;rate&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.17&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;rateCapturedAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2026-07-22T14:53:12.000Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;convertedAmount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;117&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;paymentMethodId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pm_001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;paymentMethod&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;last4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;4242&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;completed&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In production, put the endpoint behind auth and scope the lookup to the record’s owner; the record answers questions for support, not for whoever guesses an ID.&lt;/p&gt;
&lt;p&gt;Every decision sits next to the inputs you wrote when you made it. A year later, “why €117, and which card?” is one authenticated &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Good products die when people become resources</title><link>https://arrangeactassert.com/posts/good-products-die-when-people-become-resources/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/good-products-die-when-people-become-resources/</guid><pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Throughout my career the one thing I’ve watched kill good products is a single word: resource.&lt;/p&gt;
&lt;p&gt;Once a company calls its people resources, it starts treating them like resources. It adds them, rotates them, splits them across teams.&lt;/p&gt;
&lt;p&gt;The product is the first thing to suffer.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Resource planning treats people as interchangeable slots; product teams need trust, context, and chemistry&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;768&quot; src=&quot;https://arrangeactassert.com/_astro/good-products-die-when-people-become-resources.CZbtcB0j_1UWB8H.webp&quot; srcset=&quot;/_astro/good-products-die-when-people-become-resources.CZbtcB0j_1j2KBI.webp 640w, /_astro/good-products-die-when-people-become-resources.CZbtcB0j_Z2uaQq.webp 750w, /_astro/good-products-die-when-people-become-resources.CZbtcB0j_Z1N4OLx.webp 828w, /_astro/good-products-die-when-people-become-resources.CZbtcB0j_1B1jOQ.webp 1080w, /_astro/good-products-die-when-people-become-resources.CZbtcB0j_Z1nQp9h.webp 1280w, /_astro/good-products-die-when-people-become-resources.CZbtcB0j_1UWB8H.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Yes, you want a team. The dynamic of that team decides far more than the org chart admits.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;chemistry-you-cannot-buy&quot;&gt;Chemistry you cannot buy&lt;/h2&gt;
&lt;p&gt;People talk about forming, storming, norming and performing, and then forget what it means. A team is not a list of job titles. It is a living system, and when the team changes the system changes with it. One common reading of &lt;a href=&quot;https://en.wikipedia.org/wiki/Tuckman%27s_stages_of_group_development&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tuckman’s model&lt;/a&gt; is that a new member can push a team back into storming.&lt;/p&gt;
&lt;p&gt;The chemistry between people either works or it does not, and you cannot buy it after the fact. It reminds me of arranged marriages. Back in the eighties, when I was growing up, they were commonplace, and I assumed one was the path for me too. People would grow to love each other, we were told. But I saw enough unhappiness to know chemistry mattered. In my own family and the world around me, that has changed a lot. People are far more likely to choose their own partners now, and families have had to change their culture and thinking to accept it.&lt;/p&gt;
&lt;p&gt;Good product teams work the same way. There is a line from Simon Sinek I like: “A team is not a group of people who work together. A team is a group of people who trust each other.” You can assemble one backend engineer, one frontend engineer, one tester and one product person on a spreadsheet and call it a team. You have capacity on paper.&lt;/p&gt;
&lt;p&gt;Trust is a separate thing, and it takes time.&lt;/p&gt;
&lt;h2 id=&quot;the-person-i-would-choose-again&quot;&gt;The person I would choose again&lt;/h2&gt;
&lt;p&gt;I have worked with someone I would choose again tomorrow. At one company they were seen as too quiet. At another they did not work out. For me they were one of the best people I have worked with.&lt;/p&gt;
&lt;p&gt;Not for agreeing with me. For how they challenged me. The way they set out an argument worked. The way they shared what they knew worked. The way they pushed back made the product better, without ego getting in the way. We put the business first, and we put the product first, and the work clicked. You need conflict, but it has to be the right conflict.&lt;/p&gt;
&lt;p&gt;Marty Cagan makes the case for durable, empowered product teams, and SVPG has long argued against outsourcing core competencies when they are central to the business. His phrase for the teams that work is &lt;a href=&quot;https://www.svpg.com/missionaries-vs-mercenaries/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;missionaries, not mercenaries&lt;/a&gt;. His measure is outcomes over output. You lose both when you move people around like pieces on a board.&lt;/p&gt;
&lt;h2 id=&quot;the-cost-lands-on-a-person&quot;&gt;The cost lands on a person&lt;/h2&gt;
&lt;p&gt;I have been on teams where the people making the staffing calls sat nowhere near the day-to-day work, and their bad choices did not stop at the team. They landed on a person.&lt;/p&gt;
&lt;p&gt;A brilliant backend engineer was told to become full-stack. He did not want to be. It was not what he enjoyed, not the books he was reading, not what he spent his own time on. He could not bring himself to care about the front end. But he loved the product, so he accepted it.&lt;/p&gt;
&lt;p&gt;It drove him into a downward spiral. He lost motivation, and we all do our best work on the things we love, so the work showed it. He felt trapped. Every task was uphill, work he had never chosen and had no pull towards. He had written React before, and he still got no dopamine from solving a problem in that part of the stack.&lt;/p&gt;
&lt;p&gt;He had been added as a resource to fill a full-stack gap, and no one asked what he actually wanted to do. The team suffered. People started to read the mismatch as a performance problem, when it was a role-design problem. He had been placed into a slot, not chosen for the work he was best at. So how was he ever going to do good work on something he did not want to do?&lt;/p&gt;
&lt;p&gt;There is a place for disagree and commit. This was not it. Adding him that way, and bending the team around a role no one needed to fill like that, was bad for the product and worse for him. It was bad for the company too. He walked away not long after.&lt;/p&gt;
&lt;h2 id=&quot;product-thinking-or-resource-thinking&quot;&gt;Product thinking or resource thinking&lt;/h2&gt;
&lt;p&gt;That story is the difference between product thinking and resource thinking. The two ask different questions. Product thinking asks whether a change improves the outcome, protects context, and helps the team understand the customer. Resource thinking asks whether you can add a body, rotate a body, or fill a gap. Those are not the same question, and I now sort companies by which one they reach for first. The best product culture I have been part of came from people, not process, which I wrote about in &lt;a href=&quot;https://arrangeactassert.com/posts/creating-a-product-culture-at-cambridge-university-press/&quot;&gt;creating a product culture at Cambridge University Press&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A lot of the confusion comes from ideas companies have read but never lived. The Spotify model is the obvious one, a way of working that even Spotify does not use, which I wrote about in &lt;a href=&quot;https://arrangeactassert.com/posts/before-you-change-the-process-understand-the-problem/&quot;&gt;before you change the process, understand the problem&lt;/a&gt;. These hyped ways of organising teams can look right on paper. Before you adopt one, ask who actually benefits from it.&lt;/p&gt;
&lt;p&gt;AI raises the stakes. It is already part of everyday development, and the more raw production work it absorbs, the more the human work shifts towards judgement, taste, context and attention to detail. Dotting the i’s and crossing the t’s stops being the small part of the job and becomes the job. So the question sharpens: what is the resource for, and what outcome do you expect from it?&lt;/p&gt;
&lt;h2 id=&quot;how-the-decline-starts&quot;&gt;How the decline starts&lt;/h2&gt;
&lt;p&gt;I have worked at companies I would call fantastic product companies, and I have watched some of them decline. The decline starts quietly.&lt;/p&gt;
&lt;p&gt;Leadership decides to bring in offshore teams, or rotate people, or split the work across locations, without thinking about the dynamic. The problem is not geography. The problem is breaking context and chemistry while pretending nothing has changed. In a planning deck it reads as efficient. In the room, the product suffers. I once &lt;a href=&quot;https://arrangeactassert.com/posts/velocity-theatre-and-the-people-who-measure-the-wrong-thing/&quot;&gt;saw the dynamic of a team die inside a day&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before that, testers, engineers, product people and stakeholders solved problems together. Testers had a real voice, treated as first-class members of the team rather than a service on the side. I had spent a long time breaking down the silos the Jira lanes enforced, which is the work I wrote about in &lt;a href=&quot;https://arrangeactassert.com/posts/the-team-i-built-before-i-fixed-anything/&quot;&gt;the team I built before I fixed anything&lt;/a&gt;. Then the resource thinking arrived. People got added without care. The work fell back into silos. Context leaked away. The people who cared started to care less. The harmony broke. People who had respected each other found it hard to work together.&lt;/p&gt;
&lt;p&gt;That is the part leaders miss. When you treat the team casually, the team sees it, and that carelessness spreads into the decisions and into the product. Fred Brooks named the mechanism decades ago in &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Mythical_Man-Month&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;em&gt;The Mythical Man-Month&lt;/em&gt;&lt;/a&gt;: “Adding manpower to a late software project makes it later.” Nine women cannot produce a baby in one month.&lt;/p&gt;
&lt;p&gt;Some work does not get faster because more people have been assigned to it. Coordination, onboarding and communication all take time, and they can make a late project later. We still believe people are interchangeable units of delivery, and they are not.&lt;/p&gt;
&lt;h2 id=&quot;consulting-runs-on-the-same-incentive&quot;&gt;Consulting runs on the same incentive&lt;/h2&gt;
&lt;p&gt;This is not only a product-company problem. Consulting has its own version of the same trap.&lt;/p&gt;
&lt;p&gt;I have spent years as a consultant across many consultancies, and the model there is plain. The more consultants on a project, the more the consultancy earns. That does not automatically make it right for the company paying the bill. They care about the product, not the staffing model.&lt;/p&gt;
&lt;p&gt;I have since written about what that incentive looks like from inside a consultancy in &lt;a href=&quot;https://arrangeactassert.com/posts/the-best-consultancies-make-themselves-less-necessary/&quot;&gt;the best consultancies make themselves less necessary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The line often attributed to Charlie Munger applies here: “Show me the incentive and I will show you the outcome.” The consultancy’s incentive and the client’s incentive are not the same, and everyone involved should be honest about that.&lt;/p&gt;
&lt;h2 id=&quot;knowledge-without-churn&quot;&gt;Knowledge without churn&lt;/h2&gt;
&lt;p&gt;The same holds for the bus factor. You do not want all the knowledge trapped in one head, so pairing and documentation matter. Knowledge sharing works when it comes from a stable team, not from constant churn. Spreading knowledge and disturbing the team are two different acts.&lt;/p&gt;
&lt;p&gt;AI can help with the bus factor, but only if the team uses it deliberately. It can keep documentation fresh, capture decisions, explain workflows, and remove some of the mundane work. Done well, it helps knowledge stay in the system. But it does not replace the judgement, taste and context of the people building the product.&lt;/p&gt;
&lt;p&gt;If the value sits in judgement, shared context and knowing why past decisions were made, you cannot rotate it in every three months. I hold six months as the minimum contract for serious product work. You need that time to understand the product, its history, the decisions taken, and the decisions the team chose against. Some companies understand this instinctively. Your opinion in week one is worth a dollar. Three weeks in it is worth three. Two months in, five. The context that makes it worth anything never shows up on a resourcing plan.&lt;/p&gt;
&lt;h2 id=&quot;autonomy-and-fit&quot;&gt;Autonomy and fit&lt;/h2&gt;
&lt;p&gt;Not everyone fits everywhere, and that is fine. Two people click, another two are chalk and cheese. Neither is a bad person. The chemistry is wrong for that context, and the product carries the cost when every conversation turns into work and every decision turns into conflict. I have watched that curdle into office politics and a bitterness that spreads.&lt;/p&gt;
&lt;p&gt;The product shows it. Instead of something clear and coherent, you get a run of compromises made by people who are tired, frustrated, and ready to give up so they can move on. People stop pushing. The product turns into a mishmash of clashing patterns and styles and half-finished initiatives, a platform that hardens into its own kind of minefield over time.&lt;/p&gt;
&lt;p&gt;The alternative is worth the discomfort. Resource thinking optimises for the average, and average is where products go to die. I would take a team with real chemistry, even if it does not last forever, over a safe, interchangeable one that never risks anything. Better to have built something you were proud of and watched it end than to have never built it at all.&lt;/p&gt;
&lt;p&gt;Amy Edmondson defined team psychological safety as “a shared belief that the team is safe for interpersonal risk taking.” That is not about being nice. It is about people speaking honestly, challenging well, and disagreeing without it turning personal, so the &lt;a href=&quot;https://arrangeactassert.com/posts/the-loudest-voice-is-not-the-smartest-group/&quot;&gt;loudest voice does not run the room&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The product has to come first, and for it to come first the team has to work. Communication has to flow, the way I described in &lt;a href=&quot;https://arrangeactassert.com/posts/teams-should-communicate-like-a-team-fielding-in-cricket/&quot;&gt;teams should communicate like a team fielding in cricket&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Get the chemistry right and the safety sits there, invisible, so everyone keeps their eyes on the product instead of on the friction.&lt;/p&gt;
&lt;p&gt;If you hold any power over how teams are formed, be careful with the word resource, and with the arbitrary rotation that tends to follow it. You would not choose a partner from a spec sheet. Do not choose a team from one either.&lt;/p&gt;
&lt;p&gt;Chemistry is not the soft part of the job. It is often what decides whether a good product survives.&lt;/p&gt;
</content:encoded></item><item><title>Good questions protect the room</title><link>https://arrangeactassert.com/posts/good-questions-protect-the-room/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/good-questions-protect-the-room/</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Our software craftsmanship group encourages new speakers to come and practise their talks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.meetup.com/cambridge-software-crafters/events/315410040/?eventOrigin=group_upcoming_events&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;One is coming up in August&lt;/a&gt;. At the start of every meetup we read aloud the code of conduct.&lt;/p&gt;
&lt;p&gt;It can feel formal, but the repetition is the point. It sets the culture and reminds us who we want to be.&lt;/p&gt;
&lt;p&gt;A question can be good and still land badly. The timing and the room decide.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;&lt;img alt=&quot;Audience at a small tech meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;666&quot; src=&quot;https://arrangeactassert.com/_astro/good-questions-protect-the-room.DoxO4f2q_Vifeh.webp&quot; srcset=&quot;/_astro/good-questions-protect-the-room.DoxO4f2q_sYDW7.webp 640w, /_astro/good-questions-protect-the-room.DoxO4f2q_1o9IHw.webp 750w, /_astro/good-questions-protect-the-room.DoxO4f2q_13n6LF.webp 828w, /_astro/good-questions-protect-the-room.DoxO4f2q_Vifeh.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Something happens when someone gives a talk for the first time, or steps out of their shell because public speaking can be terrifying. A lot of it comes down to the questions people ask.&lt;/p&gt;
&lt;p&gt;The question that helps gives something back to the speaker and never leaves them feeling small or put off speaking again. A question that does the opposite is the anti-pattern, because it teaches the whole community to stay quiet, and the discussions and the respect we have for each other are the reason the group works at all.&lt;/p&gt;
&lt;h2 id=&quot;when-good-questions-land-badly&quot;&gt;When good questions land badly&lt;/h2&gt;
&lt;p&gt;A couple of months ago I spoke at an AI meetup. The speaker before me had built an app with AI, and the app had security flaws. Someone in the audience spotted them and kept asking, question after question, until the speaker looked uncomfortable.&lt;/p&gt;
&lt;p&gt;The questions were good. I’m sure the speaker would have welcomed the feedback in a code review, or over coffee. Asked in that room, at that moment, nobody else put their hand up. The room went quiet. The speaker felt awful.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.recurse.com/social-rules&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Recurse Center&lt;/a&gt;, a programming retreat, has a useful rule for one smaller version of this: no “well-actuallys”, which they define as a correction with “no bearing on the crux of the conversation”. Correctness matters. The harm is that some corrections move a room from learning towards status.&lt;/p&gt;
&lt;p&gt;The security questions at the AI meetup were more serious than a minor correction, but the same lesson holds. A valid point can land in a way that shuts the rest of the room down.&lt;/p&gt;
&lt;p&gt;From where I was sitting, it seemed unlikely the speaker could answer those questions well in that setting, so I won’t judge what the audience member should or shouldn’t have said. I care about the effect it had, on the speaker, and on every other person in the room who might have been weighing up their own first talk and decided against it.&lt;/p&gt;
&lt;h2 id=&quot;questions-that-are-assumptions&quot;&gt;Questions that are assumptions&lt;/h2&gt;
&lt;p&gt;Some questions are assumptions in disguise. The person has reached a conclusion and wraps it in a question mark to make it land.&lt;/p&gt;
&lt;p&gt;Edgar Schein called the opposite of this &lt;a href=&quot;https://books.google.com/books/about/Humble_Inquiry.html?id=g9aw5lKYu58C&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;humble inquiry&lt;/a&gt;, “the fine art of drawing someone out, of asking questions to which you do not know the answer.” He subtitled the book &lt;em&gt;The Gentle Art of Asking Instead of Telling&lt;/em&gt;, and that’s the line.&lt;/p&gt;
&lt;p&gt;A question you know the answer to is an instruction. Even a genuine question carries a risk the asker doesn’t see. It can derail the talk. The question can be valid on its own terms and pull the room away from the point the speaker came to make. Ten minutes later you’re deep in an edge case that mattered to one person, and the thread the speaker spent weeks preparing has gone.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-a-question-good&quot;&gt;What makes a question good&lt;/h2&gt;
&lt;p&gt;A good question helps everyone in the room. It’s the one where someone leans over afterwards and says, “I’m glad you asked, I was wondering the same thing.” It doesn’t put the speaker on the spot, it furthers their learning, and yours.&lt;/p&gt;
&lt;p&gt;Sometimes it’s the single clarification the talk needs to land, because one undefined term changes the whole meaning.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hbr.org/2016/07/what-great-listeners-actually-do&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Zenger and Folkman&lt;/a&gt; spent years studying what great listeners do. They found that “people perceive the best listeners to be those who periodically ask questions that promote discovery and insight,” and that “these questions gently challenge old assumptions, but do so in a constructive way.”&lt;/p&gt;
&lt;p&gt;A good question leaves the speaker ready to move forward.&lt;/p&gt;
&lt;p&gt;Amy Edmondson gave this a name in 1999: psychological safety, “a shared belief held by members of a team that the team is safe for interpersonal risk taking,” a confidence that the team “will not embarrass, reject, or punish someone for speaking up.”&lt;/p&gt;
&lt;p&gt;Edmondson’s talk on the same idea, The Fearless Organization, is worth watching:&lt;/p&gt;
&lt;iframe style=&quot;width:100%; aspect-ratio:16/9;&quot; src=&quot;https://www.youtube.com/embed/b395WrEQbeU?si=4FXGuJJnEeHgLZOx&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Standing up to talk is an interpersonal risk. So is asking a question, admitting you don’t know something, or floating a half-formed idea. Protect that risk and people take it again. Punish it once in public and they stop.&lt;/p&gt;
&lt;h2 id=&quot;candor-has-to-be-built-in&quot;&gt;Candor has to be built in&lt;/h2&gt;
&lt;p&gt;As Ed Catmull wrote in his book &lt;a href=&quot;https://www.amazon.co.uk/Creativity-Inc-Overcoming-Unseen-Inspiration/dp/0812993012&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“Creativity, Inc.”&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A hallmark of a healthy, creative culture is that its people feel free to share ideas, opinions and criticisms… without the critical ingredient that is candor, there can be no trust. And without trust, creative collaboration is not possible.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pixar built a structure for that candor, the Brain Trust. It is a regular meeting where a director gets honest feedback on a film in progress. The comments are suggestions, not orders, and they are aimed at the work, not the person. It is the same thing a good question does at a meetup, made into a habit.&lt;/p&gt;
&lt;h2 id=&quot;draw-quieter-voices-in&quot;&gt;Draw quieter voices in&lt;/h2&gt;
&lt;p&gt;After a meetup once, a good friend pulled me aside. He said it was good that I had the confidence to contribute and ask questions, but my real aim should be to bring the people who weren’t talking into the conversation. That would be the real win. It stuck with me.&lt;/p&gt;
&lt;p&gt;Asking a good question is one skill. Drawing in someone who hasn’t spoken is the harder one, and it does more for the room than any point I could make myself. It’s the same move as a fielding team calling each other in, which I &lt;a href=&quot;https://arrangeactassert.com/posts/teams-should-communicate-like-a-team-fielding-in-cricket/&quot;&gt;compared to a cricket side&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;before-you-ask&quot;&gt;Before you ask&lt;/h2&gt;
&lt;p&gt;At the next meetup, I run through these in my head:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Can the speaker answer this in the room, right now?&lt;/li&gt;
&lt;li&gt;Does this help the room, or only prove you noticed something?&lt;/li&gt;
&lt;li&gt;Are you asking because you don’t know, or because you’ve decided?&lt;/li&gt;
&lt;li&gt;Who in the room hasn’t spoken yet, and could your question invite them in?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Those keep me from asking the wrong thing. For asking the right thing, I borrow Edmondson’s own set, in two kinds. Some broaden the discussion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What do others think?&lt;/li&gt;
&lt;li&gt;What are we missing?&lt;/li&gt;
&lt;li&gt;What other options could we consider?&lt;/li&gt;
&lt;li&gt;Who has a different perspective?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some deepen it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What leads you to think so?&lt;/li&gt;
&lt;li&gt;What is the concern you have about that?&lt;/li&gt;
&lt;li&gt;Can you give us an example?&lt;/li&gt;
&lt;li&gt;Can you explain that further?&lt;/li&gt;
&lt;li&gt;What do you think might happen if we did X?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice “who has a different perspective?” rather than “does anyone have a different perspective?”. The first assumes another view is out there and worth hearing. The second sets a hurdle almost no one in a full room wants to clear.&lt;/p&gt;
&lt;p&gt;The same forces play out inside companies, where one confident voice can take over the room and everyone pays for it. I wrote about that in &lt;a href=&quot;https://arrangeactassert.com/posts/the-loudest-voice-is-not-the-smartest-group/&quot;&gt;The loudest voice is not the smartest group&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>The loudest voice is not the smartest group</title><link>https://arrangeactassert.com/posts/the-loudest-voice-is-not-the-smartest-group/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-loudest-voice-is-not-the-smartest-group/</guid><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;A confident voice can ask a sharp question at the wrong moment and close a room down. In a meetup, the cost is one nervous speaker and a room that goes quiet. In a company, the same habit compounds, meeting after meeting, until the same few people decide what the team is allowed to say out loud.&lt;/p&gt;
&lt;p&gt;You see the pattern at conferences first. The people who are confident keep speaking. The people finding their voice hold back. Over time the room narrows. The same voices return, the same ideas circulate, and the different takes never get a hearing.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;&lt;img alt=&quot;A team meeting where everyone has room to speak&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;666&quot; src=&quot;https://arrangeactassert.com/_astro/the-loudest-voice-is-not-the-smartest-group.Dq1Ie1ee_Z1eIJLX.webp&quot; srcset=&quot;/_astro/the-loudest-voice-is-not-the-smartest-group.Dq1Ie1ee_DzjL7.webp 640w, /_astro/the-loudest-voice-is-not-the-smartest-group.Dq1Ie1ee_Z2794tJ.webp 750w, /_astro/the-loudest-voice-is-not-the-smartest-group.Dq1Ie1ee_Z1Y84Pk.webp 828w, /_astro/the-loudest-voice-is-not-the-smartest-group.Dq1Ie1ee_Z1eIJLX.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;when-one-voice-dominates&quot;&gt;When one voice dominates&lt;/h2&gt;
&lt;p&gt;Anita Woolley and her colleagues measured what this does to a group. In their &lt;a href=&quot;https://www.science.org/doi/10.1126/science.1193147&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;2010 study in Science&lt;/a&gt;, a group’s collective intelligence had little to do with the smartest person in it. It tracked social sensitivity and whether people took turns or one voice dominated.&lt;/p&gt;
&lt;p&gt;Groups where a few people dominated the conversation showed less collective intelligence than groups where more people took turns. Let the loudest voices dominate and the group gets duller.&lt;/p&gt;
&lt;p&gt;The room with the cleverest individual is not the room that thinks best. You want the room where more people get to speak.&lt;/p&gt;
&lt;h2 id=&quot;meetings-that-go-quiet&quot;&gt;Meetings that go quiet&lt;/h2&gt;
&lt;p&gt;I’ve sat in too many meetings where the same few people talk, the leader says “any questions?”, and the silence pushes everyone to the anonymous form.&lt;/p&gt;
&lt;p&gt;Sometimes anonymity is right. If someone’s job is on the line, or the company is about to change under people’s feet, of course. For the day to day, you have to give people room to speak and build the culture that makes them want to.&lt;/p&gt;
&lt;h2 id=&quot;a-quick-yes-is-a-warning&quot;&gt;A quick yes is a warning&lt;/h2&gt;
&lt;p&gt;A room can go quiet in another way. Everyone nods, the plan passes, and it looks like agreement. Amy Edmondson uses a cartoon of a management team waving a decision through, every one of them saying aye, while their thought bubbles say the opposite. In a real meeting you cannot see the thought bubbles, but they are there.&lt;/p&gt;
&lt;p&gt;Alfred Sloan ran General Motors on the opposite instinct. When his senior team agreed a big decision on the spot, he told them he took it they were all in agreement, then proposed they postpone it to the next meeting to give themselves time to disagree. The quick yes was the part that worried him.&lt;/p&gt;
&lt;h2 id=&quot;drive-out-fear&quot;&gt;Drive out fear&lt;/h2&gt;
&lt;p&gt;W. Edwards Deming put driving out fear at the centre of how he thought about management, not only in high-stakes moments but in the everyday. He made it his &lt;a href=&quot;https://deming.org/explore/fourteen-points/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eighth point&lt;/a&gt;: “Drive out fear, so that everyone may work effectively for the company.”&lt;/p&gt;
&lt;p&gt;I sit on the Deming side of this. You hire smart people for their ideas. No single person, however senior, has thought of every angle of a problem, and in a busy week the viewpoints are the reason you hired them. The sharing shouldn’t depend on the leader organising it either.&lt;/p&gt;
&lt;p&gt;A team should be able to give each other the space and the time to speak. That’s the same habit I &lt;a href=&quot;https://arrangeactassert.com/posts/teams-should-communicate-like-a-team-fielding-in-cricket/&quot;&gt;compared to a cricket side fielding together&lt;/a&gt;, sharing information out loud and backing each other up.&lt;/p&gt;
&lt;h2 id=&quot;ive-been-on-both-sides&quot;&gt;I’ve been on both sides&lt;/h2&gt;
&lt;p&gt;Just before Covid I gave a talk on how I build apps at a local UX meetup. The room was mostly designers. They asked how I worked with their mockups and handoffs, I answered, and we both came away with something.&lt;/p&gt;
&lt;p&gt;A month later I ran the same deck at a company I’d just joined. Six colleagues watched the practice session and liked it. At the company-wide session the organiser told the room this was meant to be a discussion, not a presentation, then interrupted me within the first few minutes. She talked over my answers for the rest of it. At the end she told the room I’d wasted everyone’s time.&lt;/p&gt;
&lt;p&gt;Afterwards several attendees messaged me to apologise for her. What I didn’t understand at the time was that nobody there had done these sessions before. I was the first.&lt;/p&gt;
&lt;h2 id=&quot;show-and-tell-beats-abstract-talks&quot;&gt;Show and tell beats abstract talks&lt;/h2&gt;
&lt;p&gt;That was alien to me, because I’d come from a place where we ran a regular show and tell and everyone was encouraged to present. I did one on &lt;a href=&quot;https://arrangeactassert.com/posts/introducing-typescript-at-cambridge-university-press/&quot;&gt;TypeScript&lt;/a&gt; and &lt;a href=&quot;https://arrangeactassert.com/posts/introducing-tailwind-at-cambridge-university-press/&quot;&gt;Tailwind&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I learned more from watching colleagues talk through their own approaches than any conference could teach me, because it was about our domain and the code we shipped.&lt;/p&gt;
&lt;p&gt;People quote &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_law&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Conway’s Law&lt;/a&gt; about systems mirroring the organisations that build them. This is the other half of it. Sharing ideas and arguing about how things work, out loud, breaks down the walls between teams.&lt;/p&gt;
&lt;p&gt;Talks tied to what someone shipped on Tuesday land. Abstract ones don’t.&lt;/p&gt;
&lt;h2 id=&quot;count-the-voices&quot;&gt;Count the voices&lt;/h2&gt;
&lt;p&gt;At your next meeting, count how many people speak and how many ask a question. Note the number. Your job is to make it bigger next time.&lt;/p&gt;
&lt;p&gt;One way in is an icebreaker, if you’re leading, or you can suggest one to whoever is. Skip the cheesy and personal ones. Most people dread sharing a childhood fun fact before a sprint review, and it ignores their privacy. Keep it trivial. Ask the room whether it’s jam or cream on a scone first.&lt;/p&gt;
&lt;p&gt;There’s no right answer and nothing at stake, so anyone can answer, and in half a minute the whole room has spoken once.&lt;/p&gt;
&lt;p&gt;What matters is that each person has used their voice early, before anything is on the line. When someone speaks, the rest of the room notices they are there. On a video call that counts for more than it should. The software puts the current speaker front and centre and buries the rest, so in a big meeting you can go the whole hour without seeing half the people in it. One round of small answers pulls the quiet ones back onto the screen, and into the room.&lt;/p&gt;
&lt;p&gt;The loudest voice can make a room feel decisive. It also makes the room duller. Build rooms where more people speak.&lt;/p&gt;
&lt;p&gt;I wrote about the meetup side in &lt;a href=&quot;https://arrangeactassert.com/posts/good-questions-protect-the-room/&quot;&gt;Good questions protect the room&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Claude Code sandbox: close the gaps before you auto-allow</title><link>https://arrangeactassert.com/posts/claude-code-sandbox-close-the-gaps-before-you-auto-allow/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/claude-code-sandbox-close-the-gaps-before-you-auto-allow/</guid><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Most Claude Code sandbox guides sell convenience. Fewer prompts, smoother flow, less time approving commands.&lt;/p&gt;
&lt;p&gt;But what about the blast radius?&lt;/p&gt;
&lt;p&gt;When an AI agent runs a command, it does not only run the command you had in mind. It runs every child process, package script, setup hook and recovery step that command sets off.&lt;/p&gt;
&lt;p&gt;A helpful agent reads a README, installs a dependency, retries a failed setup step, and turns “get this project running” into “execute whatever this project tells me to execute.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Claude Code sandbox: close the gaps before you auto-allow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1672px) 1672px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1672&quot; height=&quot;941&quot; src=&quot;https://arrangeactassert.com/_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_1Ft0Pu.webp&quot; srcset=&quot;/_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_Z2llj4Y.webp 640w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_Z1Sr3qj.webp 750w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_Z2rmnd3.webp 828w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_aJiom.webp 1080w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_Z1B2JXY.webp 1280w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_j4Kha.webp 1668w, /_astro/claude-code-sandbox-close-the-gaps-before-you-auto-allow.ChC_3lok_1Ft0Pu.webp 1672w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The sandbox is a boundary, not a trust button. And the boundary only protects you to the extent you configure it.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;stop-thinking-of-it-as-a-productivity-feature&quot;&gt;Stop thinking of it as a productivity feature&lt;/h2&gt;
&lt;p&gt;Describing the sandbox as a productivity feature is tempting. Without it, Claude asks before running most commands. With it, sandboxed Bash commands run on their own. You get fewer interruptions and a smoother session.&lt;/p&gt;
&lt;p&gt;True, and the least interesting part.&lt;/p&gt;
&lt;p&gt;The question I want answered is the one a permission prompt never asks: if this command goes bad, what can it still read, where can it write, and who can it talk to?&lt;/p&gt;
&lt;p&gt;That is the model I care about. Not “do I trust Claude,” not “did I approve this one command,” not even “does the repo look clean.” A coding agent does not run isolated commands. It explores, retries, follows instructions, reads error messages, installs packages, and tries to recover when a stranger’s script fails. That is the point of using an agent, and it is also where the danger lives.&lt;/p&gt;
&lt;p&gt;Give an agent full access to your machine and every package script and setup step inherits that access. The agent may act in good faith. The process tree it starts will not.&lt;/p&gt;
&lt;p&gt;The sandbox moves the unit of trust. Instead of trusting each command the moment it appears, you decide the boundary up front. Inside it, development moves fast. Outside it, the operating system says no.&lt;/p&gt;
&lt;h2 id=&quot;a-clean-repo-is-not-the-same-as-safe-execution&quot;&gt;A clean repo is not the same as safe execution&lt;/h2&gt;
&lt;p&gt;This is not hypothetical. In late June 2026 Mozilla’s 0DIN team published a &lt;a href=&quot;https://0din.ai/blog/clone-this-repo-and-i-own-your-machine&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;proof of concept&lt;/a&gt; where a normal-looking GitHub repository walks an AI coding agent into opening a reverse shell, with nothing malicious sitting in the repo for a reviewer to catch.&lt;/p&gt;
&lt;p&gt;The chain is what makes it work. A Python package is built to fail on first use and tells the agent to run an init command. That command resolves an attacker-controlled DNS TXT record, decodes the value it gets back, and pipes it to bash.&lt;/p&gt;
&lt;p&gt;The payload, a reverse shell, never lived in the repository. The agent fetched and ran it at runtime, and the shell ran with the developer’s own access to environment variables, API keys and local config. &lt;a href=&quot;https://www.tomshardware.com/tech-industry/cyber-security/ai-coding-agents-can-be-tricked-into-installing-malware-via-clean-github-repositories-mozillas-0din-team-shows-how-claude-code-can-be-exploited-by-its-own-helpfulness&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tom’s Hardware&lt;/a&gt; and &lt;a href=&quot;https://www.bleepingcomputer.com/news/security/clean-github-repo-tricks-ai-coding-agents-into-running-malware/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;BleepingComputer&lt;/a&gt; both covered it, and 0DIN found Cursor, Copilot and Gemini CLI vulnerable to versions of the same trick.&lt;/p&gt;
&lt;p&gt;No single evil file appears anywhere. The damage comes from a chain: a boring-looking repo, normal setup instructions, a failed command, a helpful recovery step, a payload pulled in at runtime, and a shell with your privileges. Agents are good at completing exactly that chain.&lt;/p&gt;
&lt;p&gt;A human reviewing a command judges it locally. You see &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;composer install&lt;/code&gt;, or a tool-specific setup step, and you approve what is in front of you. The agent acts on the next step. The sandbox is where you cap what that whole execution tree can reach.&lt;/p&gt;
&lt;h2 id=&quot;what-the-sandbox-covers&quot;&gt;What the sandbox covers&lt;/h2&gt;
&lt;p&gt;The Claude Code sandbox applies to Bash commands and their child processes. That scope matters. When a sandboxed command runs, you can restrict what it writes, what it reads if you configure that, which network destinations it reaches, and whether a failed sandboxed command may retry outside the sandbox.&lt;/p&gt;
&lt;p&gt;On macOS it uses Apple’s Seatbelt framework. On Linux and WSL2 it uses &lt;a href=&quot;https://github.com/containers/bubblewrap&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;bubblewrap&lt;/a&gt; for filesystem isolation and a proxy for network control. Native Windows is not supported, so on Windows you run Claude Code inside a WSL2 distribution to get the Linux sandbox.&lt;/p&gt;
&lt;p&gt;That is a useful boundary, not a magic one. It does not turn arbitrary code into trusted code, does not put every Claude Code tool in a container, does not inspect encrypted traffic, and does not know on its own which of your files are secrets. You configure the boundary you want.&lt;/p&gt;
&lt;h2 id=&quot;the-write-boundary-is-a-sensible-default&quot;&gt;The write boundary is a sensible default&lt;/h2&gt;
&lt;p&gt;By default, sandboxed commands write to the current working directory and the session temp directory. That covers most of what an agent needs: a build tool writing generated files, a test runner writing temporary output, a package manager updating project files, a framework scaffolding routes or migrations.&lt;/p&gt;
&lt;p&gt;What it stops is a command casually rewriting your shell config, replacing a system binary, or dropping files somewhere unrelated to the project. Most of the agent’s real work lives in the repository. Let it work there, and do not hand it the rest of your machine by accident.&lt;/p&gt;
&lt;h2 id=&quot;the-read-gap-is-the-part-people-miss&quot;&gt;The read gap is the part people miss&lt;/h2&gt;
&lt;p&gt;Here is where I want you to slow down. The sandbox limits writes well by default. It does not limit reads the same way.&lt;/p&gt;
&lt;p&gt;Do not assume a sandboxed command cannot read a sensitive file just because it cannot write outside the project. Without extra configuration, the default read policy still reaches files you would never want a package script or a hijacked setup step to see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.ssh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.aws/credentials&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;cloud provider config&lt;/li&gt;
&lt;li&gt;npm tokens&lt;/li&gt;
&lt;li&gt;GitHub tokens in the environment&lt;/li&gt;
&lt;li&gt;other credentials under your home directory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the gap between “the sandbox is enabled” and “the sandbox is useful for my threat model.” A process that can read your credentials and reach the network does not need write access to ruin your day. It reads what it finds and sends it out. So the first serious change is to close reads.&lt;/p&gt;
&lt;h2 id=&quot;start-with-credentials&quot;&gt;Start with credentials&lt;/h2&gt;
&lt;p&gt;Claude Code gives you a dedicated &lt;code&gt;sandbox.credentials&lt;/code&gt; block (v2.1.187 and later). It denies reads of named credential files and unsets sensitive environment variables before each sandboxed command runs. This is the minimum I would start with:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;autoAllowBashIfSandboxed&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.aws/credentials&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.config/gcloud&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.npmrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;envVars&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_ACCESS_KEY_ID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SESSION_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NPM_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Treat this as the baseline, not as caution. If an agent starts a process you did not expect, that process has no business inheriting your most useful secrets.&lt;/p&gt;
&lt;h2 id=&quot;then-close-the-home-directory-read-path&quot;&gt;Then close the home-directory read path&lt;/h2&gt;
&lt;p&gt;For a stronger project setup, deny reads from the home directory and re-allow the project. Put this in the project’s &lt;code&gt;.claude/settings.json&lt;/code&gt;, not your user-level &lt;code&gt;~/.claude/settings.json&lt;/code&gt;, because &lt;code&gt;.&lt;/code&gt; only resolves to the project root when the config lives in project settings.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;filesystem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;denyRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./secrets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a trap in &lt;code&gt;allowRead: [&quot;.&quot;]&lt;/code&gt;. Re-allowing the project pulls every project file back into reach, including &lt;code&gt;.env&lt;/code&gt; and anything under &lt;code&gt;secrets/&lt;/code&gt;, so deny those paths in the same block. This is where the layer distinction bites. A &lt;code&gt;permissions&lt;/code&gt; rule like &lt;code&gt;Read(./.env)&lt;/code&gt; blocks Claude’s own Read tool, and it does nothing to a sandboxed &lt;code&gt;cat .env&lt;/code&gt; in a postinstall script. Only a &lt;code&gt;filesystem.denyRead&lt;/code&gt; entry stops Bash, because the OS enforces it whatever the command does. Keep both: the permission rule for Claude’s tools, the sandbox rule for everything Bash spawns. That gives you the boundary most people assume the word “sandbox” already includes.&lt;/p&gt;
&lt;h2 id=&quot;a-config-for-daily-development&quot;&gt;A config for daily development&lt;/h2&gt;
&lt;p&gt;For normal web work I want the agent to move quickly inside the repo: run tests, install packages, start a dev server, inspect project files. I do not want it reading secrets or publishing anything without me. Here is what I run for a typical Next.js, Vite or React project:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;autoAllowBashIfSandboxed&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;allowUnsandboxedCommands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;network&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowLocalBinding&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowedDomains&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;registry.npmjs.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api.github.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;filesystem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;denyRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./secrets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.aws/credentials&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.npmrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;envVars&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NPM_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_ACCESS_KEY_ID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SESSION_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deny&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env.*)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./secrets/**)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bash(git push *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(npm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(pnpm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few choices are deliberate. &lt;code&gt;autoAllowBashIfSandboxed&lt;/code&gt; is on, because the point is to let safe work continue without constant prompts. &lt;code&gt;allowLocalBinding&lt;/code&gt; is on, because frontend dev servers bind local ports. Reads of the home directory and the project’s own secrets are denied, the project is otherwise readable, credential files and token variables are blocked, and publishing and pushing still ask. Fast inside the boundary, deliberate at the edges.&lt;/p&gt;
&lt;p&gt;The two-domain allowlist is a starting point, not a finished list. A real project usually needs more: &lt;code&gt;registry.yarnpkg.com&lt;/code&gt; or a private registry, &lt;code&gt;pypi.org&lt;/code&gt; and &lt;code&gt;crates.io&lt;/code&gt; for polyglot repos, plus CDN, font and storage hosts your app pulls at build time. Do not try to predict them all. Run with the short list, and when an install or a dev server fails with a host-not-allowed error, add that exact host. The prompt tells you what to add, so you widen the boundary by evidence rather than by guessing a wildcard.&lt;/p&gt;
&lt;h2 id=&quot;broad-network-domains-undo-the-point&quot;&gt;Broad network domains undo the point&lt;/h2&gt;
&lt;p&gt;Network control is one of the sandbox’s most useful features, and one of the easiest to weaken. The built-in proxy decides access by hostname, which stops a sandboxed command from calling random domains. What it does not do is open TLS and inspect the encrypted contents.&lt;/p&gt;
&lt;p&gt;So a broad domain is a broad escape route. &lt;code&gt;github.com&lt;/code&gt; is not one destination in practice. It is a platform of user-controlled content, redirects, raw files, releases, issues and gists. Allowing it wholesale gives a payload somewhere to phone home. That is not a reason to ban GitHub, it is a reason to be specific. Prefer this:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;network&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowedDomains&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;registry.npmjs.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api.github.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;over a wildcard list like &lt;code&gt;[&quot;*.github.com&quot;, &quot;*&quot;]&lt;/code&gt;, which only looks like a boundary.&lt;/p&gt;
&lt;p&gt;Specific cuts both ways, though. &lt;code&gt;api.github.com&lt;/code&gt; does not cover &lt;code&gt;raw.githubusercontent.com&lt;/code&gt;, &lt;code&gt;codeload.github.com&lt;/code&gt;, or a &lt;code&gt;git clone&lt;/code&gt; over HTTPS, which talks to &lt;code&gt;github.com&lt;/code&gt; itself. A repo that installs git-based or private dependencies will hit the escape hatch on every one of those until you add the exact host. That is the trade you want: each host is a decision you made, not a door you left open. For higher-risk environments, route sandbox traffic through a corporate proxy that terminates TLS and applies real egress rules. For local development the rule is simpler: allow the few domains your tools need, and make everything else earn a prompt.&lt;/p&gt;
&lt;h2 id=&quot;know-what-the-escape-hatch-does&quot;&gt;Know what the escape hatch does&lt;/h2&gt;
&lt;p&gt;Claude Code has a useful fallback. When a command fails because of sandbox restrictions, it can retry the command outside the sandbox through the normal permission flow. For a tool that cannot run sandboxed at all, that saves you turning the whole thing off.&lt;/p&gt;
&lt;p&gt;For untrusted code, that fallback is the wrong default. When you are reviewing a random repository, auditing a suspicious dependency, or testing a branch from someone you do not know, switch the hatch off:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;autoAllowBashIfSandboxed&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;allowUnsandboxedCommands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;network&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowedDomains&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;filesystem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;denyRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./secrets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.aws/credentials&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.config/gcloud&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.npmrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;envVars&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NPM_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_ACCESS_KEY_ID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SESSION_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deny&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WebFetch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WebSearch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env.*)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./secrets/**)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The credentials block matters more here than in daily development, not less. The 0DIN payload went straight for environment variables and local config, and untrusted code is exactly when you want those stripped before any command runs. This is slower by design. With untrusted code you do not want the agent deciding that a failed sandboxed command deserves a retry with more access. You want the failure in front of you so you can choose the next step.&lt;/p&gt;
&lt;h2 id=&quot;docker-is-host-access&quot;&gt;Docker is host access&lt;/h2&gt;
&lt;p&gt;Docker does not sit neatly inside the sandbox. The Docker CLI talks to the Docker daemon over a Unix socket, and access to that socket is access to the host. Allow a sandboxed process to use the Docker socket and you may have handed back the power you were trying to remove.&lt;/p&gt;
&lt;p&gt;So do not solve Docker by punching a hole through the sandbox. Exclude the Docker commands instead, so they run outside it and stay visible through the normal permission flow:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;autoAllowBashIfSandboxed&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;excludedCommands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;docker *&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;docker-compose *&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;network&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowedDomains&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;registry.npmjs.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ghcr.io&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;filesystem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;denyRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./secrets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.aws/credentials&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;envVars&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NPM_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bash(docker *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(docker-compose *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(git push *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deny&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env.*)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./secrets/**)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker stays a conscious action, and everything else stays boxed in.&lt;/p&gt;
&lt;p&gt;When the agent genuinely needs Docker — building images, running &lt;code&gt;docker compose&lt;/code&gt;, spinning up a multi-service stack — excluding those commands trades safety for incomplete work. The follow-on in this series, &lt;a href=&quot;https://arrangeactassert.com/posts/docker-sandboxes-when-claude-code-needs-docker/&quot;&gt;Docker Sandboxes: when Claude Code needs Docker&lt;/a&gt;, covers moving the boundary outward: run Claude Code inside a microVM with its own Docker daemon, instead of punching the host socket through the inner sandbox.&lt;/p&gt;
&lt;h2 id=&quot;sandboxing-and-permissions-are-different-layers&quot;&gt;Sandboxing and permissions are different layers&lt;/h2&gt;
&lt;p&gt;This trips people up. The sandbox controls what a Bash command can access once it runs. Permissions control whether a Claude Code tool runs at all. They are not the same control.&lt;/p&gt;
&lt;p&gt;The built-in file tools, Read, Edit and Write, go through the permission system. They do not become OS-sandboxed Bash processes when the sandbox is on. So you still need permission rules alongside the sandbox:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deny&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env.*)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;Read(./secrets/**)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;Read(./private/**)&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bash(git push *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(npm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(pnpm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four layers do four jobs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it controls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Permissions&lt;/td&gt;
&lt;td&gt;What Claude may attempt with any tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandbox filesystem&lt;/td&gt;
&lt;td&gt;What Bash can read and write once it starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credentials&lt;/td&gt;
&lt;td&gt;The secret files and env vars Bash never inherits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;Where Bash and its child processes can connect&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You want all four. Drop one and the others have a gap to cover for it.&lt;/p&gt;
&lt;h2 id=&quot;what-i-would-check-into-a-team-repo&quot;&gt;What I would check into a team repo&lt;/h2&gt;
&lt;p&gt;For a team I would commit a conservative policy at &lt;code&gt;.claude/settings.json&lt;/code&gt; so the security posture shows up in code review:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sandbox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;autoAllowBashIfSandboxed&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;allowUnsandboxedCommands&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;network&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowLocalBinding&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowedDomains&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;registry.npmjs.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api.github.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;filesystem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;denyRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;~/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./.env.*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./secrets&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allowRead&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;credentials&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.ssh&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.aws/credentials&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~/.npmrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;envVars&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NPM_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_ACCESS_KEY_ID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS_SESSION_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deny&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deny&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./.env.*)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Read(./secrets/**)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ask&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bash(git push *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(npm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bash(pnpm publish *)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I would add a short note to the README so a new joiner knows the rules: the policy allows normal project work inside the repo, blocks reads from your home directory and the project’s own &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;secrets/&lt;/code&gt;, removes common token variables from sandboxed commands, and keeps publishing and pushing behind manual approval. Run &lt;code&gt;/sandbox&lt;/code&gt; and select auto-allow for everyday development. For an untrusted branch or a dependency audit, drop to strict mode by setting &lt;code&gt;autoAllowBashIfSandboxed&lt;/code&gt; and &lt;code&gt;allowUnsandboxedCommands&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; and emptying &lt;code&gt;allowedDomains&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-the-sandbox-does-not-solve&quot;&gt;What the sandbox does not solve&lt;/h2&gt;
&lt;p&gt;The sandbox reduces risk without removing responsibility. It will not stop Claude making a bad edit inside your project, so use git. It will not make a broad network allowlist safe, so keep the list narrow. It will not make Docker harmless, so treat the socket as host access. It will not protect a secret you forgot to block, so add the credential rules that fit your environment. It will not sandbox every Claude Code tool, so the built-in file tools still rely on permission rules. And it will not make untrusted code safe to run. It makes the damage smaller when something goes wrong, which is still worth a lot.&lt;/p&gt;
&lt;h2 id=&quot;what-should-the-standard-be&quot;&gt;What should the standard be?&lt;/h2&gt;
&lt;p&gt;It shouldn’t be “Claude asked, and I approved it.”&lt;/p&gt;
&lt;p&gt;It is this: if this command misbehaves, it cannot read my home directory, cannot inherit my tokens, cannot write outside the project, cannot reach random hosts, and cannot silently retry outside the sandbox.&lt;/p&gt;
&lt;p&gt;That is a better place to work from, and a more honest way to use agents. We are going to let these tools install packages, run tests, generate files, read errors and keep going, because that is where the speed comes from. Autonomy without a boundary is just delegation to whatever the agent meets next. The sandbox lets you draw that boundary and have the operating system enforce it.&lt;/p&gt;
&lt;p&gt;So do not turn on auto-allow because you are tired of prompts. Turn it on once the boundary is real: reads closed, credentials removed, network narrowed, escape hatch understood, dangerous actions still behind a prompt. Then let the agent work.&lt;/p&gt;
</content:encoded></item><item><title>When does a vibe-coded app become a real product?</title><link>https://arrangeactassert.com/posts/when-does-a-vibe-coded-app-become-a-real-product/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/when-does-a-vibe-coded-app-become-a-real-product/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I’ve seen non-developers build apps that would have taken engineers days, if not weeks.&lt;/p&gt;
&lt;p&gt;Not just functional apps, but polished apps with rich functionality that bring joy to users. They meet real needs, and the attention to detail is unmatched.&lt;/p&gt;
&lt;p&gt;Product people and domain experts can build good apps, and they build them fast.&lt;/p&gt;
&lt;p&gt;So the question is: when does a vibe-coded app become a real product?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A vibe coding journey from app to production&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2752px) 2752px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2752&quot; height=&quot;1536&quot; src=&quot;https://arrangeactassert.com/_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_154ODQ.webp&quot; srcset=&quot;/_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_ZUGOqB.webp 640w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_ZpOli0.webp 750w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_2qnEQX.webp 828w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_Z1Ycdz1.webp 1080w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_1Kxkbu.webp 1280w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_1etxeN.webp 1668w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_Z1iYHx6.webp 2048w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_1GVWpy.webp 2560w, /_astro/when-does-a-vibe-coded-app-become-a-real-product.CGtEL6XL_154ODQ.webp 2752w&quot;&gt;&lt;/p&gt;
&lt;p&gt;That is the question a lot of companies are about to face.&lt;/p&gt;
&lt;p&gt;In many businesses, engineers are no longer the only people building the next prototype. Client managers, sales teams, product people and domain experts build it too, using tools like Lovable, Base44, Claude and other AI app builders.&lt;/p&gt;
&lt;p&gt;And that is a good thing.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;A client explains a problem. A domain expert knows the workflow. They sit together and, instead of writing a long requirements document, they build something. In days, sometimes hours, not the six months a normal roadmap would take.&lt;/p&gt;
&lt;p&gt;That moves the conversation from “tell me what you need” to “is this what you mean?”&lt;/p&gt;
&lt;p&gt;Every layer in between is a chance to lose the point. A requirements document, a spec, a planning meeting, a handoff to someone who has never spoken to the customer: each one is where the original need turns into something slightly different. The person with the domain knowledge skips those layers. They are close to the customer, in direct contact, and they build what the two of them want.&lt;/p&gt;
&lt;p&gt;Andrej Karpathy named the feeling when he &lt;a href=&quot;https://x.com/karpathy/status/1886192184808149383&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;coined the term&lt;/a&gt; in February 2025: “it’s not really coding — I just see stuff, say stuff, run stuff, and copy paste stuff, and it mostly works.” That speed is intoxicating, and it closes deals that would have died in a six-month backlog.&lt;/p&gt;
&lt;p&gt;Part of it is the hit of seeing the idea live. A working app you can click within minutes beats a slide or a spec, and that feeling separates the people who make things from the people who only talk about them. Give someone that hit once and they chase it again.&lt;/p&gt;
&lt;p&gt;The instinct is not new. Tim Brown of IDEO has &lt;a href=&quot;https://hbr.org/2008/06/design-thinking&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;argued for years&lt;/a&gt; that you build a rough prototype to think with, and that it beats a thick stack of spec documents. Vibe coding makes that prototype cheaper to build than ever.&lt;/p&gt;
&lt;h2 id=&quot;make-it-work-make-it-right-make-it-fast&quot;&gt;Make it work, make it right, make it fast&lt;/h2&gt;
&lt;p&gt;For years, engineers have said things like:&lt;/p&gt;
&lt;p&gt;Make it work. Make it right. Make it fast. (I dug into how that maxim holds up once AI writes the first draft in &lt;a href=&quot;https://arrangeactassert.com/posts/revisiting-make-it-work-make-it-right-make-it-fast-in-the-age-of-ai/&quot;&gt;Make It Work, Make It Right, Make It Fast in the Age of AI&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Vibe-coded apps are brilliant at the first part. They turn a vague idea into something real that people can click, challenge, reject, improve and sell.&lt;/p&gt;
&lt;p&gt;As an engineer, I value testing, linting, accessibility, observability, dependency management, secure deployments and maintainable code.&lt;/p&gt;
&lt;p&gt;But I understand why a sales team does not want all of that on day one.&lt;/p&gt;
&lt;p&gt;A prototype exists to move fast and to learn. It does not exist to look like a fully governed production system.&lt;/p&gt;
&lt;p&gt;As Charity Majors &lt;a href=&quot;https://charitydotwtf.substack.com/p/ai-demands-more-engineering-discipline&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;puts it&lt;/a&gt;, “the true product of every (good) software engineering team is production.” An app that works in the demo says nothing about month six, when the dependencies are stale, the API key has rotated, and someone files a support ticket.&lt;/p&gt;
&lt;h2 id=&quot;when-the-prototype-crosses-a-trust-boundary&quot;&gt;When the prototype crosses a trust boundary&lt;/h2&gt;
&lt;p&gt;A prototype is scaffolding. It helps people see the shape of the thing quickly, test the idea, move around it, and decide whether it is worth building properly.&lt;/p&gt;
&lt;p&gt;But you do not ask customers to live in the scaffolding.&lt;/p&gt;
&lt;p&gt;Agents will rebuild the walls for a dollar, and you will still have a house on a floodplain if nobody did the &lt;a href=&quot;https://arrangeactassert.com/posts/the-dollar-house-still-needs-a-site-survey/&quot;&gt;site survey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the app carries the company logo, connects to real systems, stores customer data or has people depending on it, the business has moved from scaffolding to building, often without anyone deciding that shift has happened.&lt;/p&gt;
&lt;p&gt;Someone has to own the foundations, the wiring, the fire exits and the maintenance. The same shift happens when the app starts costing money to run, when someone expects support, when the company’s reputation rides on how good it is.&lt;/p&gt;
&lt;p&gt;The specifics bite fast. A prototype humming along on someone’s personal API key turns into a security and billing problem the moment it is business-critical. &lt;a href=&quot;https://www.theregister.com/2015/01/06/dev_blunder_shows_github_crawling_with_keyslurping_bots/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Exposed keys do real damage&lt;/a&gt;: one developer pushed AWS keys to GitHub, bots spun up servers to mine cryptocurrency within hours, and the bill climbed into four figures before he noticed. An app parked on a free Vercel Hobby plan breaks the rules as soon as it earns money: Vercel restricts that tier to &lt;a href=&quot;https://vercel.com/docs/limits/fair-use-guidelines&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“non-commercial personal use only”&lt;/a&gt; and pushes commercial projects onto a paid plan. The bill and the liability land on the company, not on the person who built it in an afternoon.&lt;/p&gt;
&lt;p&gt;That is the moment the conversation has to change, because the app has crossed a trust boundary. Engineers are not trying to slow things down, and product people have not done anything wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before that point, it is experimentation. After it, it is software the business is responsible for.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is where many companies will struggle.&lt;/p&gt;
&lt;p&gt;Involve engineering too early and the process becomes the bottleneck vibe coding was meant to avoid. Involve engineering too late and the company inherits risk: security, accessibility, cost, operations, dependencies and support.&lt;/p&gt;
&lt;h2 id=&quot;a-graduation-path&quot;&gt;A graduation path&lt;/h2&gt;
&lt;p&gt;Banning vibe coding would be the wrong lesson. So would forcing every vibe-coded app through the same governance as a core banking system or a main customer platform, which kills the value that made it worth building.&lt;/p&gt;
&lt;p&gt;What works is a graduation path: lightweight, visible, and clear to the people using it.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 0: Personal build&lt;/strong&gt; — A live site, but no company data, no client access, no company brand and no production expectations. The API keys belong to the builder, not the business. It is hosted on Lovable or similar, not on company infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 1: Company prototype&lt;/strong&gt; — The company sees the value and wants real users to try it. Company branding may appear. Before it ships, someone reviews API key terms, hosting, data use and commercial restrictions. The app is still experimental, but it is no longer purely personal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 2: Paid pilot&lt;/strong&gt; — The app now needs paid usage above the free tiers, so it costs the company money. The business reviews and approves that spend. Costs are tracked, ownership is clear, and basic security, accessibility and dependency checks apply. Still no company APIs and no company login.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 3: Product&lt;/strong&gt; — Uses real customer data, internal systems, company authentication or paid APIs. Now it enters the software development lifecycle.&lt;/p&gt;
&lt;p&gt;A Level 3 app does not automatically need months of process. It means the business has accepted that this is no longer a demo but something the company owns.&lt;/p&gt;
&lt;p&gt;The important part is not the exact labels. It is that someone can look at an app and quickly decide what level it is at, who owns it, and what has to happen before it moves up.&lt;/p&gt;
&lt;h2 id=&quot;the-handover-problem&quot;&gt;The handover problem&lt;/h2&gt;
&lt;p&gt;Moving an app up that path runs into a practical engineering problem.&lt;/p&gt;
&lt;p&gt;If a team builds the app in Lovable and engineers then fix it directly in GitHub, where is the source of truth?&lt;/p&gt;
&lt;p&gt;Is it the version in Lovable, or the version in the repository? Can the business team still iterate, or has the app moved into an engineering-owned lifecycle? The handover point decides who owns the next change.&lt;/p&gt;
&lt;p&gt;Martin Fowler would call a fast prototype &lt;a href=&quot;https://martinfowler.com/bliki/TechnicalDebtQuadrant.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;deliberate, prudent technical debt&lt;/a&gt;: you ship now and accept you will pay it back later. The trouble starts when that debt turns reckless and invisible, when the app drifts into production and nobody records that the handover happened.&lt;/p&gt;
&lt;p&gt;Vibe coding does not remove the need for engineering judgement. &lt;a href=&quot;https://arxiv.org/abs/2506.23253&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Research by Advait Sarkar and Ian Drosos&lt;/a&gt; argues it redistributes that judgement toward managing context, evaluating output fast, and knowing when to drop the AI and edit by hand. The handover is where that judgement has to show up.&lt;/p&gt;
&lt;h2 id=&quot;do-not-kill-the-energy-that-built-it&quot;&gt;Do not kill the energy that built it&lt;/h2&gt;
&lt;p&gt;When the app graduates, remember why it exists. One person saw a problem, felt it, and built something. That vision and that drive are the reason you are here, not the engineering team and not the roadmap.&lt;/p&gt;
&lt;p&gt;Most engineers, given the choice, want to build, not run product. Product thinking is its own craft. It takes discipline, customer context and a different set of instincts from engineering. The person who built the prototype may have those instincts because they were closest to the problem.&lt;/p&gt;
&lt;p&gt;So the real risk at handover is human, not technical. Take the app away from the person who built it, tidy it up “properly”, and you can drain the energy that made it good. Kill that energy and you kill the product.&lt;/p&gt;
&lt;p&gt;Security and operations teams are part of that handover, but they cannot be the whole of it. Their job is to protect the business, keep systems stable and reduce surprises. That matters. But it is not the same as owning the customer problem or carrying the product vision. If the app becomes only a thing to secure, host, monitor and control, the company may make it safer while draining the reason it was worth saving.&lt;/p&gt;
&lt;p&gt;The business needs to see this coming. The aim is to keep the initiator driving while engineering makes the thing safe to own, not to hand the whole thing over.&lt;/p&gt;
&lt;h2 id=&quot;the-tools-are-not-the-enemy&quot;&gt;The tools are not the enemy&lt;/h2&gt;
&lt;p&gt;It would be easy to write these tools off as toys. They are not.&lt;/p&gt;
&lt;p&gt;Take Lovable. It &lt;a href=&quot;https://docs.lovable.dev/integrations/github&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;syncs two ways with GitHub&lt;/a&gt;, so the code can be cloned, edited in your own IDE, or self-hosted. It runs &lt;a href=&quot;https://docs.lovable.dev/features/security&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;security checks&lt;/a&gt; too, from dependency audits to keeping API keys server-side. These builders are moving toward the enterprise problem, not away from it.&lt;/p&gt;
&lt;p&gt;So the answer cannot be “stop using them”. Platform guardrails are not the same as company ownership, and that is the line that matters.&lt;/p&gt;
&lt;p&gt;A platform can generate the code, deploy it, scan it for obvious holes, and sync it to GitHub. It cannot decide whether the app now represents the company, whether a client treats it as an official product, who pays for the API usage, who gets paged when it breaks, or whether the business accepts the data and reputational risk. Those are company decisions.&lt;/p&gt;
&lt;h2 id=&quot;this-is-not-a-new-problem&quot;&gt;This is not a new problem&lt;/h2&gt;
&lt;p&gt;Vibe coding is the AI-native version of something companies have wrestled with for years: citizen development. Low-code and no-code platforms made the same promise and hit the same wall. Microsoft &lt;a href=&quot;https://learn.microsoft.com/en-us/power-platform/guidance/adoption/assess-security-posture&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;warns&lt;/a&gt; that when security gets cumbersome, people bypass it and drift into “shadow IT”. Gartner &lt;a href=&quot;https://www.gartner.com/en/documents/6370411&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;makes the point&lt;/a&gt; that low-code and no-code speed development but need support and governance so citizen developers can build safely at scale.&lt;/p&gt;
&lt;p&gt;The useful framing comes from OWASP, whose &lt;a href=&quot;https://owasp.org/www-project-citizen-development-top10-security-risks/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Citizen Development Top 10&lt;/a&gt; treats the goal as safe adoption rather than a ban: guardrails that let innovation thrive while keeping security intact. A graduation path is how you bring that spirit to vibe coding.&lt;/p&gt;
&lt;h2 id=&quot;engineering-as-enabler&quot;&gt;Engineering as enabler&lt;/h2&gt;
&lt;p&gt;Engineering’s job here is to enable the people building these apps, not to guard a gate. I made the fuller case for that shift in &lt;a href=&quot;https://arrangeactassert.com/posts/engineering-gatekeeper-to-enabler-citizen-developer/&quot;&gt;From Gatekeeper to Enabler&lt;/a&gt;, where I argued that engineering adds more value handing citizen developers safe defaults than standing in their way.&lt;/p&gt;
&lt;p&gt;There is a practical reason for this too. Every engineering team I have worked on is already at capacity. The roadmap is full, and no spare team is waiting to adopt a stack of vibe-coded apps. Much of what people are building is work that sat in the backlog for months, deferred behind something more urgent. Vibe coding gives those ideas another route to daylight. Funnelling every app through engineering is not feasible, so enablement is the only model that scales.&lt;/p&gt;
&lt;p&gt;Give non-technical teams room to create: safe defaults, approved places to host, guidance on API keys, company accounts, data, branding and security, and a fast route to ask for help before the app becomes a liability. And give engineers the context to see why these apps matter.&lt;/p&gt;
&lt;p&gt;There is a competitive point here too. If your company makes this too hard, the ideas will not wait. The people closest to the customer will find another way to build, or a competitor will get there first. One missed prototype does not matter much. Repeat the pattern, though, and you lose more than experiments. You lose innovation velocity.&lt;/p&gt;
&lt;p&gt;In the AI era, the ability to turn customer insight into working software is becoming a first-class business utility. Security, operations and engineering should make that utility safe to use, not so hard to reach that people route around it. Make it hard and you do not stop the work. You push it into personal accounts, unmanaged tools, or the hands of a competitor who moves faster.&lt;/p&gt;
&lt;p&gt;Vibe coding is already happening, so the question is not whether to allow it. The choice companies face is whether to treat it as shadow IT or to build a path where creativity, speed and engineering discipline work together.&lt;/p&gt;
&lt;p&gt;Vibe-coded apps should not be blocked. They should be given a clear path, from a quick prototype to a product the company owns. The danger is not that people outside engineering are building software. The danger is that nobody knows when the business has become responsible for it.&lt;/p&gt;
&lt;p&gt;Businesses still need to move fast. The trick is knowing when the thing built to learn has become something the company must own.&lt;/p&gt;
</content:encoded></item><item><title>How sandbox runs risky installs in a throwaway container</title><link>https://arrangeactassert.com/posts/how-sandbox-runs-risky-installs-in-a-throwaway-container/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-sandbox-runs-risky-installs-in-a-throwaway-container/</guid><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/sandbox-node&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;@jagreehal/sandbox-node&lt;/code&gt;&lt;/a&gt; runs your &lt;code&gt;npm install&lt;/code&gt; in a throwaway container that can see your project and the registry, and nothing else.&lt;/p&gt;
&lt;p&gt;Install scripts still run. &lt;code&gt;node-gyp&lt;/code&gt; still builds. Your SSH keys, npm token, cloud credentials, and &lt;code&gt;.env&lt;/code&gt; are not in the box, so a malicious dependency has nothing to steal and nowhere to send it.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-one-picture-version&quot;&gt;The one-picture version&lt;/h2&gt;
&lt;p&gt;Put &lt;code&gt;sandbox&lt;/code&gt; in front of the command you already run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; zod
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood the risky code runs in a container that can reach your project files and the npm registry. It cannot reach your home directory, your credentials, or anywhere else on the internet. When the command finishes, the box is deleted and your installed dependencies stay behind.&lt;/p&gt;
&lt;p&gt;This is install-time containment, not a general sandbox. It targets the one moment that the &lt;a href=&quot;https://arrangeactassert.com/posts/npm-install-runs-code-you-never-read/&quot;&gt;previous post&lt;/a&gt; is about: when untrusted dependency code executes with your access.&lt;/p&gt;
&lt;h2 id=&quot;why-this-is-worth-it&quot;&gt;Why this is worth it&lt;/h2&gt;
&lt;p&gt;You do not have to stop using normal package managers. You do not have to disable install scripts and break native modules. You do not have to read every transitive dependency before you clone a repo.&lt;/p&gt;
&lt;p&gt;You keep the workflow you already use. The difference is that install-time code runs somewhere with no secrets to steal, nowhere to phone home, and fewer places to persist. Same workflow, smaller blast radius.&lt;/p&gt;
&lt;p&gt;That gives you a handful of practical benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Safer installs without changing package managers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install scripts still work&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better defaults for agents and CI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less reliance on perfect dependency review&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One tool and one config, not a toolchain to wire up&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;one-attack-path-end-to-end&quot;&gt;One attack path, end to end&lt;/h2&gt;
&lt;p&gt;You add a package. One dependency under it ships a &lt;code&gt;postinstall&lt;/code&gt; script. During install, that script reads &lt;code&gt;~/.npmrc&lt;/code&gt;, checks &lt;code&gt;~/.aws/credentials&lt;/code&gt;, writes a hook into &lt;code&gt;.git/hooks&lt;/code&gt;, and makes an HTTPS request to a host you have never heard of.&lt;/p&gt;
&lt;p&gt;On your host, that works because the script runs as you. In &lt;code&gt;sandbox&lt;/code&gt;, each step hits a different wall. The credentials are not mounted. The common persistence paths are read-only. The network request has no route unless you allowed that host.&lt;/p&gt;
&lt;h2 id=&quot;three-layers-check-it-contain-it-catch-it&quot;&gt;Three layers: check it, contain it, catch it&lt;/h2&gt;
&lt;p&gt;A supply-chain worm needs three things to work: a version fresh enough to still be live, something worth stealing, and a way out. &lt;code&gt;sandbox&lt;/code&gt; works in three layers that line up against those, so no single bypass defeats it: it checks a package before the box runs, contains the code while it runs, and catches anything that tries to get out.&lt;/p&gt;
&lt;h3 id=&quot;check-it-before-the-box-runs&quot;&gt;Check it before the box runs&lt;/h3&gt;
&lt;p&gt;Before any dependency code executes, &lt;code&gt;sandbox&lt;/code&gt; vets what you are about to pull. This is the part that reaches out to external sources to confirm there are no known issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Risk hints&lt;/strong&gt; inspect each direct package before it installs. By default they use the metadata npm already returns, with no extra network calls: install scripts, versions published in the last hours or days, brand-new packages, newly added binaries, deprecations, a name within one or two edits of a popular package (a typosquat, checked against a corpus of around 2,500 names), a release that dropped the npm provenance attestations its earlier versions shipped, and a first-time or long-dormant publisher (a maintainer-takeover signal). The &lt;code&gt;thorough&lt;/code&gt; level, which the &lt;code&gt;strict&lt;/code&gt; preset turns on, reaches further out to the npm downloads API and DNS to flag missing repository or license metadata, suspiciously low download counts, and a maintainer email domain that no longer resolves (a known route to seizing an npm account). They warn by default; &lt;code&gt;--fail-on-risk&lt;/code&gt; makes them block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A release-age cooldown&lt;/strong&gt; refuses any version published more recently than your threshold: three days on the &lt;code&gt;balanced&lt;/code&gt; and &lt;code&gt;agent&lt;/code&gt; presets, seven on &lt;code&gt;strict&lt;/code&gt;. Worms detonate within hours, so the install never even resolves a version that fresh, falling back to the last one that has aged past the threshold. It is one of the strongest controls against publish-and-detonate worms, but a cooldown alone leaves gaps, which is why the layers below exist alongside it. &lt;a href=&quot;https://arrangeactassert.com/posts/minimum-release-age-is-necessary-but-not-enough/&quot;&gt;Minimum release age is necessary, but not enough&lt;/a&gt; walks through where it falls short.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A known-malware check&lt;/strong&gt; queries the &lt;a href=&quot;https://osv.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;OSV database&lt;/a&gt; for the exact version you would pull and refuses anything flagged as malware (&lt;code&gt;MAL-...&lt;/code&gt;), even a version old enough to clear the cooldown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your own blocklist&lt;/strong&gt; blocks immediately when you already know a package is bad, without waiting for OSV to catch up: a committed &lt;code&gt;sandbox.advisories.json&lt;/code&gt; for your team, plus malware feeds you trust, such as Aikido’s public npm malware list.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sandbox preflight&lt;/code&gt;&lt;/strong&gt; runs all of the above without installing anything, so you can review a package, or a whole pull request’s dependency changes, before it touches your machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;contain-it-while-it-runs&quot;&gt;Contain it while it runs&lt;/h3&gt;
&lt;p&gt;A check is a signal, not a guarantee, so the vetted install still runs inside the throwaway box. Inside, there is nothing to take and no way out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No credentials.&lt;/strong&gt; The container starts almost empty: &lt;code&gt;SANDBOX=1&lt;/code&gt;, &lt;code&gt;HOME=/root&lt;/code&gt;, and little else. No &lt;code&gt;~/.ssh&lt;/code&gt;, &lt;code&gt;~/.npmrc&lt;/code&gt;, &lt;code&gt;~/.aws&lt;/code&gt;, or home directory is mounted, so a script that greps &lt;code&gt;process.env&lt;/code&gt; for an AWS key finds nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistence is read-only.&lt;/strong&gt; &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;.husky&lt;/code&gt;, &lt;code&gt;.claude&lt;/code&gt;, &lt;code&gt;.vscode&lt;/code&gt;, and &lt;code&gt;package.json&lt;/code&gt; are mounted read-only, so an install cannot plant an auto-running hook.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No route off-box.&lt;/strong&gt; The container sits on an internal network with no gateway. Its only exit is a proxy that forwards to allowlisted hosts and nothing else, so even malware that ignores &lt;code&gt;HTTP_PROXY&lt;/code&gt; is stuck. UDP and ICMP have no route either, which closes DNS tunnelling and ICMP exfiltration, not just HTTP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No cloud-metadata pivot.&lt;/strong&gt; The metadata endpoints (IMDS) are blackholed, so a dependency cannot reach the magic address that would hand it your cloud role’s credentials.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stripped capabilities.&lt;/strong&gt; &lt;code&gt;--cap-drop ALL&lt;/code&gt;, &lt;code&gt;--security-opt no-new-privileges&lt;/code&gt;, and container-root is not host-root.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;catch-it-and-prove-the-box-held&quot;&gt;Catch it and prove the box held&lt;/h3&gt;
&lt;p&gt;The last layer is evidence: knowing something tried, and being able to show it did not get out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An egress tripwire&lt;/strong&gt; logs every blocked outbound attempt, the highest-signal event the tool produces, and &lt;code&gt;--fail-on-egress&lt;/code&gt; turns one into a failed build.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Canary honeytokens&lt;/strong&gt; plant fake-but-realistic AWS, Stripe, and Slack credentials in the install environment, exactly what a thief greps for. If one ever shows up leaving the box, that is unambiguous proof of theft and the run fails hard. On by default in the &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;agent&lt;/code&gt; presets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A retroactive sweep&lt;/strong&gt; (&lt;code&gt;sandbox scan&lt;/code&gt;) re-checks your committed lockfile against OSV later, catching dependencies that turned malicious after you installed them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A committed-secrets scan&lt;/strong&gt; (&lt;code&gt;sandbox secrets&lt;/code&gt;) checks the repo itself for credentials you may have committed, reporting where, with the values redacted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signed receipts and a tamper-evident audit log&lt;/strong&gt; turn “the boundary held” into something a later CI stage or a third party can verify without re-running it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sandbox demo&lt;/code&gt;&lt;/strong&gt; runs four real supply-chain attacks (credential theft, a persistence hook, a cloud-metadata pivot, network exfiltration) against the live sandbox and shows each one contained. It exits non-zero if any attack gets through, so it doubles as a test that the boundary still holds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It works across &lt;strong&gt;npm, pnpm, yarn, and bun&lt;/strong&gt;, plus runners like &lt;code&gt;npx&lt;/code&gt;, &lt;code&gt;bunx&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;tsx&lt;/code&gt;, and &lt;code&gt;vite&lt;/code&gt;. Anything that pulls new versions goes through the same checks, so &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;upgrade&lt;/code&gt;, and &lt;code&gt;audit fix&lt;/code&gt; are covered too, not just first install.&lt;/p&gt;
&lt;h2 id=&quot;one-tool-instead-of-a-toolchain&quot;&gt;One tool instead of a toolchain&lt;/h2&gt;
&lt;p&gt;None of these checks is a new idea on its own. You could assemble most of them from separate tools: one to review packages before install, one to block known malware, one to enforce a minimum release age, and a devcontainer for isolation. Then you wire them together, keep four configurations in sync, and hope every developer set them up the same way.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sandbox&lt;/code&gt; puts review, age-gating, malware-blocking, and containment behind one prefix and one config file. You get the safety and the developer experience in one place, instead of orchestrating a toolchain and hoping it holds.&lt;/p&gt;
&lt;p&gt;That single file is also what turns this from a personal habit into a team decision. Commit &lt;code&gt;sandbox.config.json&lt;/code&gt; and the boundary is reviewed in a pull request, like any other code. &lt;code&gt;sandbox verify&lt;/code&gt; enforces it in CI so nothing merges around it, a personal override that loosens it is flagged on every run, and a badge can advertise that installs go through it. Everyone installs against the same policy, whether or not they remember to.&lt;/p&gt;
&lt;h2 id=&quot;limits&quot;&gt;Limits&lt;/h2&gt;
&lt;p&gt;You should know the edges before you adopt it.&lt;/p&gt;
&lt;p&gt;Your &lt;strong&gt;source tree stays writable&lt;/strong&gt; during a normal install, because package managers need a writable root and pnpm writes temp files there. A malicious dependency can still overwrite a file in &lt;code&gt;src/&lt;/code&gt; during install. You will see it in &lt;code&gt;git diff&lt;/code&gt;, and &lt;code&gt;--frozen&lt;/code&gt; makes the whole tree read-only on every package manager except pnpm. What &lt;code&gt;sandbox&lt;/code&gt; blocks is credential theft, persistence, and exfiltration. It does not promise source immutability unless you ask for it.&lt;/p&gt;
&lt;p&gt;Anything you &lt;strong&gt;grant&lt;/strong&gt; is in scope on purpose. Forwarding a private-registry token with &lt;code&gt;--env NPM_TOKEN&lt;/code&gt;, mounting a path, or turning network on are explicit opt-ins. Grant the minimum.&lt;/p&gt;
&lt;p&gt;It needs &lt;strong&gt;Docker&lt;/strong&gt; (or a Docker-compatible engine like OrbStack or Podman) and runs on macOS or Linux, or Windows under WSL2.&lt;/p&gt;
&lt;h2 id=&quot;how-it-sits-next-to-other-tools&quot;&gt;How it sits next to other tools&lt;/h2&gt;
&lt;p&gt;Devcontainers give you a full containerised workspace, but a devcontainer does not make &lt;code&gt;npm install&lt;/code&gt; safe: inside it, the install still runs with whatever the container can reach. &lt;code&gt;sandbox&lt;/code&gt; fills the install-time gap a devcontainer leaves open, and it can &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-put-sandbox-in-front-of-npm-pnpm-yarn-and-bun/&quot;&gt;generate the devcontainer for you&lt;/a&gt; when you want a persistent environment. That is composition, not competition.&lt;/p&gt;
&lt;p&gt;The same is true of Claude Code’s built-in OS sandbox: run that for the agent’s whole blast radius, and &lt;code&gt;sandbox&lt;/code&gt; for the supply-chain surface on top.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sandbox&lt;/code&gt; does not try to read the dependency code in time, recognise the package, or out-guess the release timing. It runs the install in a box that has nothing worth stealing and no way to send it. Same workflow, smaller blast radius.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-put-sandbox-in-front-of-npm-pnpm-yarn-and-bun/&quot;&gt;next post&lt;/a&gt; covers setup: getting the &lt;code&gt;sandbox&lt;/code&gt; command, the one-button onboarding, making it automatic so you never type the prefix, and wiring it into agents and CI.&lt;/p&gt;
</content:encoded></item><item><title>How to put sandbox in front of npm, pnpm, yarn, and bun</title><link>https://arrangeactassert.com/posts/how-to-put-sandbox-in-front-of-npm-pnpm-yarn-and-bun/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-put-sandbox-in-front-of-npm-pnpm-yarn-and-bun/</guid><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Get the &lt;code&gt;sandbox&lt;/code&gt; command, run one setup step, and put &lt;code&gt;sandbox&lt;/code&gt; in front of the commands you already run.&lt;/p&gt;
&lt;p&gt;New to Node, or not sure why &lt;code&gt;npm install&lt;/code&gt; is risky in the first place? Start with &lt;a href=&quot;https://arrangeactassert.com/posts/npm-install-runs-code-you-never-read/&quot;&gt;why install-time code is a trust decision&lt;/a&gt;, then &lt;a href=&quot;https://arrangeactassert.com/posts/how-sandbox-runs-risky-installs-in-a-throwaway-container/&quot;&gt;what running it in a throwaway container buys you&lt;/a&gt;. Otherwise, read on.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;p&gt;One dependency: &lt;strong&gt;Docker.&lt;/strong&gt; Docker Desktop, OrbStack, or any Docker-compatible engine works, and the CLI builds its own images on first run. You also need &lt;strong&gt;Node 20 or newer&lt;/strong&gt;, on &lt;strong&gt;macOS or Linux&lt;/strong&gt; (on Windows, run it inside WSL2). Make sure the engine is running before you start.&lt;/p&gt;
&lt;p&gt;The fast path is short:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx @jagreehal/sandbox-node@latest setup &lt;span class=&quot;token parameter variable&quot;&gt;--vibe&lt;/span&gt;
npx @jagreehal/sandbox-node@latest &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is enough to try it on a fresh clone without changing your shell or project setup first.&lt;/p&gt;
&lt;h2 id=&quot;what-you-get&quot;&gt;What you get&lt;/h2&gt;
&lt;p&gt;This is not a new workflow. It is the same install and run commands with the risky part moved behind a boundary.&lt;/p&gt;
&lt;p&gt;Same workflow, smaller blast radius.&lt;/p&gt;
&lt;p&gt;That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You keep install scripts working&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You keep npm, pnpm, yarn, and bun&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You can apply the same boundary in local dev, AI-agent sessions, and CI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You stop depending on memory and caution every time you clone a repo&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;get-the-command&quot;&gt;Get the command&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;@latest&lt;/code&gt; so &lt;code&gt;npx&lt;/code&gt; does not reuse a stale cached version. For day-to-day work, add it to the project:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; @jagreehal/sandbox-node&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CLI installs as both &lt;code&gt;sandbox&lt;/code&gt; and &lt;code&gt;sandbox-node&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;one-button-setup&quot;&gt;One-button setup&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sandbox setup&lt;/code&gt; writes a config if you do not have one, checks Docker, builds the images if needed, and prints the next commands:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox setup &lt;span class=&quot;token parameter variable&quot;&gt;--vibe&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;# safe defaults for exploring and cloning repos&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;# install deps, lifecycle scripts contained&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; zod         &lt;span class=&quot;token comment&quot;&gt;# add a dependency&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev          &lt;span class=&quot;token comment&quot;&gt;# run a dev server, tests, a build&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--vibe&lt;/code&gt; is the relaxed preset for exploring: containment is on, but the release-age gate is warn-only so a fresh clone is not blocked. When you want the gate enforcing, pick a stricter preset:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox init &lt;span class=&quot;token parameter variable&quot;&gt;--preset&lt;/span&gt; balanced   &lt;span class=&quot;token comment&quot;&gt;# blocks versions younger than 3 days (the default)&lt;/span&gt;
sandbox init &lt;span class=&quot;token parameter variable&quot;&gt;--preset&lt;/span&gt; strict     &lt;span class=&quot;token comment&quot;&gt;# blocks 7 days, plus the OSV malware check and canary tokens&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Preview any command in plain English before it runs, without executing it:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox --dry-run &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It prints what would be mounted, which hosts the install can reach, and that your host credentials stay out.&lt;/p&gt;
&lt;h2 id=&quot;make-it-automatic&quot;&gt;Make it automatic&lt;/h2&gt;
&lt;p&gt;Remembering to type &lt;code&gt;sandbox&lt;/code&gt; on every install is a rule you will break under pressure. Set the boundary once instead.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sandbox path&lt;/code&gt; installs shell functions so a bare &lt;code&gt;npm install&lt;/code&gt; routes through the sandbox out of habit:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox path &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;# auto-detects zsh, bash, or fish&lt;/span&gt;
sandbox path status
sandbox path uninstall&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After you open a new terminal, the install vector (&lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;pnpm add&lt;/code&gt;, &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;npx&lt;/code&gt;, and friends) runs sandboxed, while &lt;code&gt;npm run dev&lt;/code&gt;, &lt;code&gt;npm test&lt;/code&gt;, and &lt;code&gt;node app.js&lt;/code&gt; hit the real tool on the host untouched. Two escape hatches are always there:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;# bypass the wrapper for one call&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;SANDBOX_OFF&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;       &lt;span class=&quot;token comment&quot;&gt;# disable the wrappers for the whole shell&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a convenience guardrail, not the boundary itself. The real protection is still &lt;code&gt;sandbox&lt;/code&gt; running the command in a container.&lt;/p&gt;
&lt;h2 id=&quot;cloning-a-repo-or-letting-an-agent-install&quot;&gt;Cloning a repo or letting an agent install&lt;/h2&gt;
&lt;p&gt;This is where containment earns its keep:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/some/app &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; app
sandbox setup &lt;span class=&quot;token parameter variable&quot;&gt;--vibe&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev          &lt;span class=&quot;token comment&quot;&gt;# common dev ports are auto-forwarded&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For coding agents like Claude Code, the &lt;code&gt;--agent&lt;/code&gt; preset stops relying on the model to remember the rule:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox init &lt;span class=&quot;token parameter variable&quot;&gt;--agent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It writes &lt;code&gt;.sandbox/AGENT.md&lt;/code&gt; (guidance the agent reads), a &lt;code&gt;PreToolUse&lt;/code&gt; hook that blocks a bare &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;npx&lt;/code&gt; on the host and tells the agent to re-run it through &lt;code&gt;sandbox&lt;/code&gt;, and &lt;code&gt;permissions.deny&lt;/code&gt; rules so the agent cannot read &lt;code&gt;.env&lt;/code&gt; or &lt;code&gt;secrets/**&lt;/code&gt; into its own context. A model that ignores the markdown still hits the hook.&lt;/p&gt;
&lt;p&gt;To contain the agent’s whole session rather than each operation, generate a hardened devcontainer from the same config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox devcontainer init
&lt;span class=&quot;token comment&quot;&gt;# then: open in VS Code, &quot;Reopen in Container&quot;, run the agent inside&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The per-operation form (default) and the per-session form (devcontainer) apply the same hardening at two lifecycles, both driven by one &lt;code&gt;sandbox.config.json&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;give-the-agent-the-install-skill&quot;&gt;Give the agent the install skill&lt;/h3&gt;
&lt;p&gt;The repo also ships a Claude Code skill, &lt;code&gt;sandbox-install&lt;/code&gt;, that turns the agent into the human-in-the-loop reviewer. Instead of installing blind, the agent runs &lt;code&gt;sandbox preflight&lt;/code&gt; first (the gates, without installing anything), shows you each finding with a recommended action, and runs the real install only once you have cleared the risk, with the flags that match your choices. It will not proceed past a known-malware advisory on its own.&lt;/p&gt;
&lt;p&gt;Install it with the &lt;a href=&quot;https://github.com/vercel-labs/skills&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;skills&lt;/code&gt; CLI&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx skills &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; jagreehal/sandbox-node&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That drops the skill into your agent’s skills directory, and the agent picks it up when you ask it to install or vet a package. If you would rather not use the CLI, copy &lt;code&gt;skills/sandbox-install&lt;/code&gt; from the &lt;a href=&quot;https://github.com/jagreehal/sandbox-node&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;repo&lt;/a&gt; into your project’s &lt;code&gt;.claude/skills&lt;/code&gt; (or &lt;code&gt;~/.claude/skills&lt;/code&gt; for every project) by hand.&lt;/p&gt;
&lt;h2 id=&quot;wire-it-into-ci&quot;&gt;Wire it into CI&lt;/h2&gt;
&lt;p&gt;CI is where untrusted dependency code runs unattended, so it is where containment pays off most. The pattern is &lt;code&gt;--frozen&lt;/code&gt; (reproducible, read-only install) plus &lt;code&gt;--fail-on-egress&lt;/code&gt; (fail the build if install-time code tries to phone home):&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .github/workflows/install.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest   &lt;span class=&quot;token comment&quot;&gt;# the runner already has Docker&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm i &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;g @jagreehal/sandbox&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; sandbox &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;frozen &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;fail&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;on&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;egress npm install
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; sandbox npm test&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The guarantee this gives you has two honest halves. &lt;strong&gt;Host secrets stay out:&lt;/strong&gt; anything you do not explicitly grant, your home credentials and any environment variable you did not forward, is never in the container for dependency code to read. &lt;strong&gt;Nothing leaves without a route:&lt;/strong&gt; if a host is not in &lt;code&gt;egress.allow&lt;/code&gt;, install-time code cannot send data there, and &lt;code&gt;--fail-on-egress&lt;/code&gt; turns the attempt into a failed build instead of a silent leak.&lt;/p&gt;
&lt;p&gt;What the install &lt;em&gt;can&lt;/em&gt; read is the project tree it runs against. A secret committed into the repo, or the checkout token below, sits in that tree and is readable inside the box. Default-deny egress is what contains it: readable, but with nowhere to send it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--frozen&lt;/code&gt; needs a committed, in-sync lockfile. If an install legitimately needs a host (a private registry, &lt;code&gt;nodejs.org&lt;/code&gt; for native modules), allow it once so it is committed in your config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox allow npm.pkg.github.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One CI-specific gotcha worth knowing: &lt;code&gt;actions/checkout&lt;/code&gt; writes the job’s GitHub token into &lt;code&gt;.git/config&lt;/code&gt; by default. &lt;code&gt;sandbox&lt;/code&gt; mounts &lt;code&gt;.git&lt;/code&gt; read-only, so install code can read that token but not change it, and default-deny egress stops it leaving. To keep it out of the tree entirely, set &lt;code&gt;persist-credentials: false&lt;/code&gt; on the install job:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;persist-credentials&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To gate only what a pull request changes, &lt;code&gt;sandbox delta&lt;/code&gt; diffs the lockfile against the merge target and runs the age, malware, and deprecation gates over just the added or bumped versions. Run &lt;code&gt;sandbox scan&lt;/code&gt; on a nightly schedule to catch dependencies that turn malicious after merge, and gate merges with &lt;code&gt;sandbox verify&lt;/code&gt; so the committed boundary cannot be quietly loosened.&lt;/p&gt;
&lt;h2 id=&quot;grant-a-secret-when-an-install-needs-one&quot;&gt;Grant a secret when an install needs one&lt;/h2&gt;
&lt;p&gt;The container starts with an almost-empty environment, so nothing from your shell or CI runner is in the box by default. When an install genuinely needs one host secret, like a private-registry token, grant exactly that and nothing more:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox &lt;span class=&quot;token parameter variable&quot;&gt;--env&lt;/span&gt; NPM_TOKEN &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;# forward one host var by name (its value only)&lt;/span&gt;
sandbox allow npm.pkg.github.com           &lt;span class=&quot;token comment&quot;&gt;# plus allow the private-registry host&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To pull values from an env file, use &lt;code&gt;--env-from&lt;/code&gt;, and narrow it to specific keys with a &lt;code&gt;:KEY,KEY&lt;/code&gt; suffix so the rest of the file stays out:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox --env-from .env &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;              &lt;span class=&quot;token comment&quot;&gt;# inject every key in .env&lt;/span&gt;
sandbox --env-from .env:NPM_TOKEN &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# inject only NPM_TOKEN; everything else stays out&lt;/span&gt;
sandbox --env-from .env tsx script.ts            &lt;span class=&quot;token comment&quot;&gt;# one-off script with its env injected&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file is never mounted; only the values you ask for become container env vars. To make a grant permanent for the project, put it in &lt;code&gt;sandbox.config.json&lt;/code&gt; under &lt;code&gt;grants.env&lt;/code&gt; (named vars) or &lt;code&gt;grants.envFiles&lt;/code&gt; (files, with the same &lt;code&gt;:KEY,KEY&lt;/code&gt; filtering), so it is reviewed in one place instead of retyped each run.&lt;/p&gt;
&lt;p&gt;One thing to know: a &lt;code&gt;.env&lt;/code&gt; that lives &lt;strong&gt;inside the project&lt;/strong&gt; is not a grant. It is part of the tree &lt;code&gt;sandbox&lt;/code&gt; mounts so the install can run, so dependency code can read it like any other project file. Default-deny egress is what keeps that contained: the code can read a project &lt;code&gt;.env&lt;/code&gt;, but under the registry-only allowlist it has nowhere to send the contents. Keep &lt;code&gt;egress.allow&lt;/code&gt; tight if your tree holds real secrets, and prefer ssh-agent over mounting key files.&lt;/p&gt;
&lt;h2 id=&quot;going-further&quot;&gt;Going further&lt;/h2&gt;
&lt;p&gt;The defaults cover everyday installs. A few more commands are worth knowing once it is running.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Review before you install.&lt;/strong&gt; &lt;code&gt;sandbox preflight&lt;/code&gt; runs the same gates as a real install (release-age, malware, deprecation, risk hints) without installing anything. It prints each finding and exits non-zero exactly when the install would be blocked, so it drops into a pre-merge check. Tighten it per run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox --min-release-age &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; --fail-on-advisory preflight &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Check your setup.&lt;/strong&gt; &lt;code&gt;sandbox doctor&lt;/code&gt; validates the config, package manager, and container backend, and flags a container-escape CVE in the runtime or an end-of-life Node line in the image.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Block packages you already know are bad.&lt;/strong&gt; When you do not want to wait for OSV, drop a committed &lt;code&gt;sandbox.advisories.json&lt;/code&gt; in the repo, or list malware feeds you trust and cache them locally:&lt;/p&gt;
&lt;pre class=&quot;language-jsonc&quot; data-language=&quot;jsonc&quot;&gt;&lt;code class=&quot;language-jsonc&quot;&gt;// sandbox.config.json — Aikido&apos;s public npm malware list
{ &quot;install&quot;: { &quot;malwareFeeds&quot;: [&quot;https://malware-list.aikido.dev/malware_predictions.json&quot;] } }&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox feeds update          &lt;span class=&quot;token comment&quot;&gt;# fetch and cache the feeds; the install check then reads them offline&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A match in either source always blocks, independent of the OSV lookup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Catch theft in the act.&lt;/strong&gt; &lt;code&gt;--canaries&lt;/code&gt; plants fake AWS, Stripe, and Slack credentials in the install environment. If one ever leaves the box, the run fails with proof of exfiltration. It is on by default in the &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;agent&lt;/code&gt; presets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Re-check later, and scan the repo.&lt;/strong&gt; Dependencies can turn malicious after you install them, and secrets can slip into the repo:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox scan                  &lt;span class=&quot;token comment&quot;&gt;# re-query OSV for every version in the committed lockfile&lt;/span&gt;
sandbox secrets               &lt;span class=&quot;token comment&quot;&gt;# offline scan for committed credentials (values redacted)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neither needs a container, and both exit non-zero on a finding, so they fit a nightly cron or a CI step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prove the boundary held.&lt;/strong&gt; For a chain of custody, &lt;code&gt;sandbox verify --sign&lt;/code&gt; emits an Ed25519-signed receipt that the boundary is intact, which a later stage checks with &lt;code&gt;sandbox verify-receipt&lt;/code&gt;. Set &lt;code&gt;SANDBOX_AUDIT_LOG=&amp;lt;path&amp;gt;&lt;/code&gt; to append a tamper-evident, hash-chained log of every run.&lt;/p&gt;
&lt;h2 id=&quot;watch-it-work&quot;&gt;Watch it work&lt;/h2&gt;
&lt;p&gt;You do not have to take the claims on faith:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox demo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It runs real supply-chain attacks (credential theft, a persistence hook, an IMDS pivot, egress exfiltration) against the live sandbox in a throwaway project and shows each one contained. It exits non-zero if any attack is not contained.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;Get Docker running, &lt;code&gt;npm install -D @jagreehal/sandbox-node&lt;/code&gt;, run &lt;code&gt;sandbox setup&lt;/code&gt;, and put &lt;code&gt;sandbox&lt;/code&gt; in front of the commands you already type. Wire &lt;code&gt;sandbox path&lt;/code&gt; into your shell so you stop having to remember, and add the &lt;code&gt;--frozen --fail-on-egress&lt;/code&gt; step in CI.&lt;/p&gt;
&lt;p&gt;Your installs run the same as before. Same workflow, smaller blast radius. The code they execute has nothing of yours to steal and nowhere to send it.&lt;/p&gt;
</content:encoded></item><item><title>Minimum release age is necessary, but not enough</title><link>https://arrangeactassert.com/posts/minimum-release-age-is-necessary-but-not-enough/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/minimum-release-age-is-necessary-but-not-enough/</guid><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The most-recommended npm defence right now is a cooldown: refuse to install any version published more recently than a few days ago. pnpm shipped it as &lt;code&gt;minimumReleaseAge&lt;/code&gt;, Aikido Safe Chain turns it on by default, and after the recent Shai-Hulud-style npm worms, it became the advice everyone repeats.&lt;/p&gt;
&lt;p&gt;It is good advice. It closes the window these worms detonate in. But “set a cooldown” is being sold as if it were the whole answer, and it is not. A cooldown knows one thing about a package: how old it is. There are at least three reasons it is not enough on its own, and for those, age is the wrong question to ask.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;what-a-cooldown-does&quot;&gt;What a cooldown does&lt;/h2&gt;
&lt;p&gt;A minimum release age refuses to resolve any version published more recently than your threshold. Set it to three days and a version published two hours ago does not get installed; the resolver falls back to the last version that has aged past the line.&lt;/p&gt;
&lt;p&gt;It is one of the strongest controls against publish-and-detonate worms. Those worms compromise a maintainer account, publish a malicious version, and spread within hours. Some of the versions developers pulled were five minutes and around an hour old. A cooldown refuses to even resolve anything that fresh, so the bad version is never the one you install.&lt;/p&gt;
&lt;p&gt;Keep the cooldown. Everything below is about what it leaves open, not a case against it.&lt;/p&gt;
&lt;h2 id=&quot;gap-1-the-malicious-version-that-aged-in&quot;&gt;Gap 1: the malicious version that aged in&lt;/h2&gt;
&lt;p&gt;A cooldown asks one question: is this version old enough? It does not ask: is this version &lt;em&gt;bad&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Most of the time those line up, because worms detonate fast and get caught fast. Not all of the time. A version can sit past your threshold and still be malicious. The attacker who plants something and waits a week beats a three-day cooldown by definition. Once a version crosses your age line, the cooldown no longer filters it at all.&lt;/p&gt;
&lt;p&gt;So you need a second axis: not “too new to trust” but “known to be bad.” That is a malware check. In sandbox-node’s case, the second gate is an OSV malware check: &lt;a href=&quot;https://github.com/jagreehal/sandbox-node&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;@jagreehal/sandbox-node&lt;/code&gt;&lt;/a&gt; queries the &lt;a href=&quot;https://osv.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;OSV database&lt;/a&gt; for the exact version an install would pull and refuses anything flagged as malware, even a version old enough to clear the cooldown:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox --fail-on-advisory &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# block a known-malicious version&lt;/span&gt;
sandbox init &lt;span class=&quot;token parameter variable&quot;&gt;--preset&lt;/span&gt; strict              &lt;span class=&quot;token comment&quot;&gt;# strict turns this on for you&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two gates are complementary. The cooldown catches too-new-to-trust; the malware check catches known-bad. A zero-day worm is too fresh for any advisory, so the cooldown stops it. A republished known-bad version has aged in, so the malware check stops it. Neither covers the other.&lt;/p&gt;
&lt;h2 id=&quot;gap-2-the-version-that-turned-bad-after-you-installed-it&quot;&gt;Gap 2: the version that turned bad after you installed it&lt;/h2&gt;
&lt;p&gt;This second gap defeats both gates at once. An advisory database only knows what has been &lt;em&gt;reported so far&lt;/em&gt;. Most supply-chain compromises surface later: a version is published, looks clean, passes your cooldown, passes the malware check because nothing is filed yet, you install it, and &lt;em&gt;days afterwards&lt;/em&gt; OSV files a &lt;code&gt;MAL-...&lt;/code&gt; advisory for it.&lt;/p&gt;
&lt;p&gt;At install time, every check you can run returns green. The package was old enough and not yet known-bad. The cooldown is irrelevant here because the version had already aged in. The install-time malware check is irrelevant because the advisory did not exist yet.&lt;/p&gt;
&lt;p&gt;This is why sandbox-node also re-checks &lt;em&gt;after&lt;/em&gt; the fact:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox scan          &lt;span class=&quot;token comment&quot;&gt;# re-query OSV for every version in your committed lockfile&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sandbox scan&lt;/code&gt; re-queries OSV for the versions in your committed lockfile and exits non-zero if any installed package is &lt;em&gt;now&lt;/em&gt; flagged as malware. Run it nightly, or fold it into a CI gate, and a dependency that turned out bad after you installed it gets caught on the next sweep instead of never. A point-in-time gate cannot do this; only re-checking can.&lt;/p&gt;
&lt;h2 id=&quot;gap-3-the-one-that-catches-you&quot;&gt;Gap 3: the one that catches &lt;em&gt;you&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;The cooldown is blunt in the other direction too. It does not only block other people’s fresh malware; it blocks your own fresh publishes and any legitimate newly released dependency you want. So teams tune it down, exempt their own scope, or turn it off on the repos where the friction bites, which are often the repos that pull the most.&lt;/p&gt;
&lt;p&gt;That is not a bug in the cooldown, it is the nature of a time-based gate: the only knob is a number of days, and that one number trades safety against friction for every package at once. You end up either too loose to stop a patient attacker or too tight to ship. sandbox-node lets you exempt your own scope so the gate stays strict for everything else:&lt;/p&gt;
&lt;pre class=&quot;language-jsonc&quot; data-language=&quot;jsonc&quot;&gt;&lt;code class=&quot;language-jsonc&quot;&gt;{ &quot;install&quot;: { &quot;minReleaseAgeDays&quot;: 7, &quot;minReleaseAgeExclude&quot;: [&quot;@myscope/*&quot;] } }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But exempting a scope is still trusting it by name, which is the assumption a maintainer-account takeover breaks.&lt;/p&gt;
&lt;h2 id=&quot;the-layer-that-does-not-depend-on-timing-or-recognition&quot;&gt;The layer that does not depend on timing or recognition&lt;/h2&gt;
&lt;p&gt;Each gate above depends on knowing something in advance. The cooldown depends on the bad version being fresh. The malware check depends on someone having filed an advisory. Your own blocklist depends on you already knowing. Every one of them comes down to recognising the package, reading the code, or timing the release, and a brand-new, unrecognised, plausibly-aged package slips past all three.&lt;/p&gt;
&lt;p&gt;The control that does not depend on any of that is containment. If the install runs in a throwaway box that cannot see your SSH keys, cannot reach your npm token, and has no outbound route beyond the registry it needs to fetch packages, it does not matter whether the version was fresh, flagged, or recognised. The credentials are not in the box. Even if a script tries to exfiltrate, the default-deny egress allowlist gives it no general-purpose route out. The box is deleted afterwards and your installed dependencies stay.&lt;/p&gt;
&lt;p&gt;That is the difference worth being precise about. A cooldown, a malware check, and a blocklist all try to answer “should this code run?” and they answer it from incomplete information, every time. Containment changes the question to “if it runs, what can it reach?” and answers that one in full, regardless of what the gates knew.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# the install runs with no credentials, default-deny egress, IMDS blackholed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be precise about the claim. sandbox-node does not have a magically better blocklist: its malware check has publish lag like any other, and it blocks known malware, not every vulnerability. What sets it apart is that it does not &lt;em&gt;rely&lt;/em&gt; on the blocklist being complete. The cooldown and the OSV check are the cheap front line; containment is the backstop for everything they miss.&lt;/p&gt;
&lt;h2 id=&quot;use-them-together-not-instead&quot;&gt;Use them together, not instead&lt;/h2&gt;
&lt;p&gt;This is not cooldown versus sandbox. sandbox-node runs the cooldown &lt;em&gt;and&lt;/em&gt; the malware check &lt;em&gt;and&lt;/em&gt; the retroactive sweep &lt;em&gt;and&lt;/em&gt; the containment, behind one prefix and one config:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;sandbox init &lt;span class=&quot;token parameter variable&quot;&gt;--preset&lt;/span&gt; strict   &lt;span class=&quot;token comment&quot;&gt;# 7-day cooldown + OSV malware check + canaries + containment&lt;/span&gt;
sandbox &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
sandbox scan                    &lt;span class=&quot;token comment&quot;&gt;# later, catch what turned bad after install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A worm too fresh to be flagged hits the cooldown. A known-bad version old enough to clear the cooldown hits the malware check. A version that turns bad after you install it gets caught by the next &lt;code&gt;sandbox scan&lt;/code&gt;. And the one that beats all three, fresh enough or obscure enough that nothing flagged it, runs in a box with nothing of yours to steal and nowhere to send it.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;A minimum release age is necessary. It closes the worm window better than anything else, and you should turn it on. It is not sufficient, because it asks only how old a package is, and a patient attacker, a late advisory, and your own release schedule all make age the wrong question.&lt;/p&gt;
&lt;p&gt;The fix is not a longer cooldown or a better blocklist. It is to stop betting everything on the gate being right and run the install where a wrong answer cannot reach your credentials or your host environment. If you want the full picture, the &lt;a href=&quot;https://arrangeactassert.com/posts/npm-install-runs-code-you-never-read/&quot;&gt;safe-installs series&lt;/a&gt; walks through why install-time code is a trust decision, &lt;a href=&quot;https://arrangeactassert.com/posts/how-sandbox-runs-risky-installs-in-a-throwaway-container/&quot;&gt;what running it in a throwaway container buys you&lt;/a&gt;, and &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-put-sandbox-in-front-of-npm-pnpm-yarn-and-bun/&quot;&gt;how to put &lt;code&gt;sandbox&lt;/code&gt; in front of the commands you already run&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>npm install runs code you never read</title><link>https://arrangeactassert.com/posts/npm-install-runs-code-you-never-read/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/npm-install-runs-code-you-never-read/</guid><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;You run &lt;code&gt;npm install&lt;/code&gt; without thinking. It looks like a download step. It is a trust decision.&lt;/p&gt;
&lt;p&gt;Every package that resolves into your tree can run code the moment it installs, with the same access you have: your SSH keys, the npm token in &lt;code&gt;~/.npmrc&lt;/code&gt;, your cloud credentials, your &lt;code&gt;.env&lt;/code&gt;. Not the package you typed. Any of the hundreds underneath it. You approved none of them by name, and the package manager never asked.&lt;/p&gt;
&lt;p&gt;The fix is not to read more or trust less. It is to run that install somewhere your secrets are not.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;first-what-npm-install-actually-does&quot;&gt;First, what &lt;code&gt;npm install&lt;/code&gt; actually does&lt;/h2&gt;
&lt;p&gt;If you are new to Node, here is the part that makes the rest matter.&lt;/p&gt;
&lt;p&gt;When you run &lt;code&gt;npm install&lt;/code&gt;, npm reads the packages your project asked for, downloads them from the public npm registry (a shared store anyone can publish to), and drops them into a &lt;code&gt;node_modules&lt;/code&gt; folder. Each of those packages depends on others, and those depend on more. You ask for a handful and you get hundreds. These are called transitive dependencies: the ones you never named, pulled in on behalf of the ones you did. Most are written by people you will never meet.&lt;/p&gt;
&lt;p&gt;Downloading is not the whole story. A package can include scripts that npm runs automatically as part of installing it, called lifecycle scripts (&lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;postinstall&lt;/code&gt;). They exist for good reasons, like compiling native code or fetching a binary. But it means “install” is not a passive copy. It executes code from those hundreds of packages, on your machine, as you.&lt;/p&gt;
&lt;p&gt;That last fact is the one most people miss, and it is the whole reason this series exists.&lt;/p&gt;
&lt;h2 id=&quot;the-install-is-where-the-code-runs&quot;&gt;The install is where the code runs&lt;/h2&gt;
&lt;p&gt;That install-time code runs with everything your shell can reach. It can read files, open network connections, and write to disk before a single line of your own code executes. &lt;code&gt;node-gyp&lt;/code&gt;, which builds native modules, runs during install without even needing a lifecycle script, so “just turn scripts off” does not close the gap.&lt;/p&gt;
&lt;p&gt;The package manager answers operational questions. Can I resolve this version? Can I fetch the artifact? It does not ask the trust questions: should this code run on this machine, with this access, right now?&lt;/p&gt;
&lt;h2 id=&quot;the-agent-makes-it-routine&quot;&gt;The agent makes it routine&lt;/h2&gt;
&lt;p&gt;You told the agent to clone the repo and get it running. It ran &lt;code&gt;npm install&lt;/code&gt;. You were not watching the output, because not watching is the point of an agent.&lt;/p&gt;
&lt;p&gt;Somewhere three levels down the dependency tree, a &lt;code&gt;postinstall&lt;/code&gt; script read your &lt;code&gt;~/.npmrc&lt;/code&gt; and your AWS credentials and sent them out. The install finished green. You found out later, or you never did.&lt;/p&gt;
&lt;p&gt;Coding agents industrialise the thing that was already risky. They clone unfamiliar repos, they add dependencies on your behalf, and they run installs faster than you can review them. The trust decision you used to make a few times a day now happens unattended, on code neither of you has read.&lt;/p&gt;
&lt;h2 id=&quot;ci-runs-it-unattended-against-bigger-keys&quot;&gt;CI runs it unattended, against bigger keys&lt;/h2&gt;
&lt;p&gt;The same install runs on every build, in CI, with no one watching. And the secrets there are worth more than any laptop’s: your registry tokens, your cloud deploy credentials, the token your pipeline uses to push releases.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;postinstall&lt;/code&gt; script on a build runner has the same access the build does. One compromised dependency does not steal a single developer’s keys. It steals the organisation’s, on a machine nobody is looking at.&lt;/p&gt;
&lt;h2 id=&quot;the-usual-advice-is-partial&quot;&gt;The usual advice is partial&lt;/h2&gt;
&lt;p&gt;The standard supply-chain advice does not hold up on its own.&lt;/p&gt;
&lt;p&gt;“Audit your dependencies” assumes you can read every transitive package, and you cannot. A mid-sized project pulls in hundreds of them, most written by people you will never meet.&lt;/p&gt;
&lt;p&gt;“Use &lt;code&gt;--ignore-scripts&lt;/code&gt;” misses &lt;code&gt;node-gyp&lt;/code&gt;, which runs during native builds without a lifecycle script. It also breaks packages that genuinely need their install step.&lt;/p&gt;
&lt;p&gt;“Pin your versions” does nothing the day a pinned version turns out to be the compromised one.&lt;/p&gt;
&lt;p&gt;Each piece of advice closes one door. Install-time code still runs, and it still runs with everything you have.&lt;/p&gt;
&lt;h2 id=&quot;we-would-notice-fails-as-a-control&quot;&gt;“We would notice” fails as a control&lt;/h2&gt;
&lt;p&gt;Recent incidents follow one pattern. An attacker compromises a maintainer account, publishes a malicious release, and waits for developers to pull it before anyone reacts.&lt;/p&gt;
&lt;p&gt;The June 4, 2026 Shai-Hulud worm showed the compressed version. It pushed malicious releases and spread within hours. Some of the versions developers pulled were five minutes and around an hour old. By the time a dashboard flags the release, it is already on laptops and CI runners.&lt;/p&gt;
&lt;p&gt;“We would notice” is not a control, because you notice too late. The damage happens during the short window between publish and takedown, and an automatic install inside that window is all it takes.&lt;/p&gt;
&lt;h2 id=&quot;run-install-where-there-is-nothing-to-steal&quot;&gt;Run install where there is nothing to steal&lt;/h2&gt;
&lt;p&gt;Review tools warn you before install. Blocking tools refuse packages already confirmed as malware. Age gates refuse versions too fresh to trust. Each one helps, and each one depends on either reading the code, recognising the package, or timing the release. A brand-new, unrecognised, plausibly-aged package slips past all three.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;postinstall&lt;/code&gt; script runs in a throwaway box that cannot see your SSH keys, cannot reach your npm token, and cannot send anything out, it does not matter whether you recognised the package or read its code. The credentials are not in the box. There is no way out. The box is deleted afterwards, and your installed dependencies stay.&lt;/p&gt;
&lt;p&gt;In plain terms, here is what that buys you. You can install anything, clone any repo, and let an agent add packages, without betting your SSH keys, your tokens, and your cloud credentials on every one of those packages being honest. You work the way you already do. A malicious package just finds an empty room.&lt;/p&gt;
&lt;p&gt;That is the approach the rest of this series is about. I built &lt;a href=&quot;https://github.com/jagreehal/sandbox-node&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;@jagreehal/sandbox-node&lt;/code&gt;&lt;/a&gt; to do exactly this: put &lt;code&gt;sandbox&lt;/code&gt; in front of the &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pnpm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt;, or &lt;code&gt;bun&lt;/code&gt; command you already run, and the risky part happens in a container with your secrets left out.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt; is the most common command in your day and one of the least examined. It runs code you never read, with access you never granted by name, at a moment an attacker can predict.&lt;/p&gt;
&lt;p&gt;The fix is not to read more or trust less. It is to run install somewhere your secrets simply are not, so a bad package has nothing to take and no way to send it. You keep your normal workflow and stop betting it on every dependency. The &lt;a href=&quot;https://arrangeactassert.com/posts/how-sandbox-runs-risky-installs-in-a-throwaway-container/&quot;&gt;next post&lt;/a&gt; covers what that looks like.&lt;/p&gt;
</content:encoded></item><item><title>The GitHub and npm settings open source maintainers should turn on before they need them</title><link>https://arrangeactassert.com/posts/the-github-and-npm-settings-open-source-maintainers-should-turn-on-before-they-need-them/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-github-and-npm-settings-open-source-maintainers-should-turn-on-before-they-need-them/</guid><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In the middle of a supply-chain incident, the maintainer is not just fixing packages. They are locked out of their account, answering reports, trying to contact registries, trying to warn users, and trying to prove what happened.&lt;/p&gt;
&lt;p&gt;That is the part we do not talk about enough.&lt;/p&gt;
&lt;p&gt;Most open source maintainers are not companies. They do not have incident response teams. They do not have a security department. They have a GitHub account, an npm account, a laptop, and a lot of people depending on them.&lt;/p&gt;
&lt;p&gt;Security advice often assumes the maintainer is the weak link. That is backwards. The maintainer is the last line of defence, usually unpaid, usually alone, and often locked out of the systems they need during the incident.&lt;/p&gt;
&lt;p&gt;This is the checklist I wish every maintainer had before something goes wrong. No single setting saves you, so it works in layers: the account, the branch, the release path, the workflow, the tokens, the files, the tripwires, and the recovery plan.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;1-protect-your-github-account&quot;&gt;1. Protect your GitHub account&lt;/h2&gt;
&lt;p&gt;Everything below assumes the attacker does not control your GitHub account. Start here, because once someone has push access, a lot of “secure CI” assumptions collapse.&lt;/p&gt;
&lt;p&gt;Use phishing-resistant login where you can. GitHub supports passkeys and hardware security keys, and a passkey signs you in and satisfies 2FA in one step. An OTP app is better than SMS; a passkey or security key is better than both, because there is no code to phish.&lt;/p&gt;
&lt;p&gt;The ten-minute audit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable 2FA, then add a passkey or hardware security key&lt;/li&gt;
&lt;li&gt;Remove SSH keys you no longer recognise or use (&lt;a href=&quot;https://github.com/settings/keys&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;settings/keys&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Remove old personal access tokens; replace classic PATs with fine-grained ones scoped to specific repos&lt;/li&gt;
&lt;li&gt;Review authorised OAuth apps and GitHub Apps, and revoke anything you stopped using&lt;/li&gt;
&lt;li&gt;Check active sessions for devices you do not recognise&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Calendar this twice a year. Credentials accumulate; nobody deletes them without an appointment.&lt;/p&gt;
&lt;p&gt;If you maintain important packages, separate authority across accounts. Keep a rarely used admin identity for rulesets, environments, access changes, and recovery, and do day-to-day development from a non-admin maintainer account. If you can, keep approvals on a third account or teammate identity that does not share the same browser session or device posture. The goal is not ceremony. It is to stop one stolen day-to-day session from also being allowed to remove the protections that were meant to catch it.&lt;/p&gt;
&lt;p&gt;Solo maintainer? At minimum, separate a rarely used admin account from your daily development account.&lt;/p&gt;
&lt;h2 id=&quot;2-protect-your-release-branch&quot;&gt;2. Protect your release branch&lt;/h2&gt;
&lt;p&gt;Every package repo should protect &lt;code&gt;main&lt;/code&gt;. In &lt;strong&gt;Settings → Branches&lt;/strong&gt; (or the newer rulesets):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Require pull requests before merging&lt;/li&gt;
&lt;li&gt;Require at least one approval&lt;/li&gt;
&lt;li&gt;Require status checks to pass&lt;/li&gt;
&lt;li&gt;Block force pushes&lt;/li&gt;
&lt;li&gt;Block branch deletion&lt;/li&gt;
&lt;li&gt;Require conversation resolution&lt;/li&gt;
&lt;li&gt;Restrict who can push directly, if your plan allows it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For solo maintainers there is an obvious objection: who reviews my PR? Be honest about what this layer does. Branch protection will not save you from yourself, and it will not save you from a fully compromised account that can change the rules. But it stops accidental pushes, basic automation abuse, and compromise of a lower-privilege collaborator. It also creates friction, and sometimes friction is the control. In the June 2026 campaign, some attackers had enough GitHub privilege to remove branch protection before pushing to &lt;code&gt;main&lt;/code&gt;, which is exactly why you cannot treat branch rules as sufficient on their own. Section 3 closes the OIDC snapshot-branch path, which does not depend on &lt;code&gt;main&lt;/code&gt; branch protection noticing the push.&lt;/p&gt;
&lt;p&gt;The same June 2026 campaign also landed direct commits on &lt;code&gt;main&lt;/code&gt; with stolen credentials, disguised as ordinary feature work. Required review and signed commits still raise the bar, but they help only while the attacker does not have enough privilege to disable or rewrite those protections first. &lt;a href=&quot;https://arrangeactassert.com/posts/the-trusted-publishing-setting-that-would-have-blocked-the-npm-snapshot-branch-attacks/&quot;&gt;The trusted publishing post&lt;/a&gt; covers the OIDC half.&lt;/p&gt;
&lt;h2 id=&quot;3-protect-your-release-environment&quot;&gt;3. Protect your release environment&lt;/h2&gt;
&lt;p&gt;This is the layer that stopped mattering being theoretical in June 2026, when a worm published malicious versions through projects’ own trusted publishing pipelines by pushing throwaway &lt;code&gt;snapshot-*&lt;/code&gt; branches containing a copy of the release workflow. The publishes carried valid provenance. See &lt;a href=&quot;https://arrangeactassert.com/posts/the-trusted-publishing-setting-that-would-have-blocked-the-npm-snapshot-branch-attacks/&quot;&gt;the mechanics and the fix&lt;/a&gt; for details; the short version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a GitHub environment called &lt;code&gt;release&lt;/code&gt; (&lt;strong&gt;Settings → Environments&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Restrict it to &lt;code&gt;main&lt;/code&gt;, or to the tags you actually release from&lt;/li&gt;
&lt;li&gt;Add required reviewers if you can&lt;/li&gt;
&lt;li&gt;In npm’s trusted publisher settings, set &lt;strong&gt;Environment name&lt;/strong&gt; to &lt;code&gt;release&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jobs that reference an environment must satisfy its protection rules before they run. A workflow on a throwaway branch does not get the environment, does not get the OIDC claim, and the publish is rejected.&lt;/p&gt;
&lt;p&gt;The principle:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A workflow should not be allowed to publish just because it exists. It should have to come from the release path.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4-lock-down-github-actions-permissions&quot;&gt;4. Lock down GitHub Actions permissions&lt;/h2&gt;
&lt;p&gt;Default workflow permissions should be boring. Release permissions should exist only on the release job.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# workflow level: read-only&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; read

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; release
    &lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; read
      &lt;span class=&quot;token key atrule&quot;&gt;id-token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; write &lt;span class=&quot;token comment&quot;&gt;# only here, never workflow-wide&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest of the Actions checklist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;Settings → Actions → General&lt;/strong&gt;, set default workflow permissions to read-only&lt;/li&gt;
&lt;li&gt;Pin third-party actions to &lt;strong&gt;full commit SHAs&lt;/strong&gt;, not tags. GitHub’s own guidance says a full-length SHA is the only way to use an action as an immutable release; tags can be moved to malicious commits.&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;pull_request_target&lt;/code&gt; unless you fully understand what it grants. It runs with secrets in the context of your repo against code from a fork.&lt;/li&gt;
&lt;li&gt;Never run untrusted PR code in a job that has secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-remove-publish-tokens-from-ci&quot;&gt;5. Remove publish tokens from CI&lt;/h2&gt;
&lt;p&gt;The best npm token is the one that does not exist.&lt;/p&gt;
&lt;p&gt;If trusted publishing is available for your setup, use it and delete the automation tokens it replaces. A long-lived publish token in CI secrets is the single most valuable thing an attacker can exfiltrate from your repo, and stealers now harvest CI secrets as standard practice.&lt;/p&gt;
&lt;p&gt;The npm side of the audit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use trusted publishing for CI releases; remove old automation publish tokens&lt;/li&gt;
&lt;li&gt;Where you still need tokens (e.g. installing private packages), use read-only granular tokens with short expiry&lt;/li&gt;
&lt;li&gt;In each package’s settings, require 2FA for publishing and settings changes, and disallow token-based publishing where you can&lt;/li&gt;
&lt;li&gt;Audit the maintainers list on every package; remove people who no longer need access&lt;/li&gt;
&lt;li&gt;Check the trusted publisher settings themselves, and limit them to publish only, not every action&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-treat-release-files-as-sensitive&quot;&gt;6. Treat release files as sensitive&lt;/h2&gt;
&lt;p&gt;Some files in your repo are not ordinary code. If a file can change what gets published, treat it as release infrastructure.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;CODEOWNERS&lt;/code&gt; file makes that surface visible, and combined with branch protection’s “require review from code owners”, changes to it demand sign-off:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;# .github/CODEOWNERS
/.github/workflows/   @your-username
package.json          @your-username
package-lock.json     @your-username
pnpm-lock.yaml        @your-username
yarn.lock             @your-username
npm-shrinkwrap.json   @your-username
rollup.config.*       @your-username
vite.config.*         @your-username
webpack.config.*      @your-username
tsup.config.*         @your-username
/scripts/             @your-username&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even in a small project where you are the only owner, the file documents which paths are dangerous. It says: these files are not ordinary code. Future you, future co-maintainers, and future security reviewers all benefit from that being written down.&lt;/p&gt;
&lt;h2 id=&quot;7-watch-for-snapshot-branches&quot;&gt;7. Watch for snapshot branches&lt;/h2&gt;
&lt;p&gt;The June 2026 worm used throwaway branches with random names. Most maintainers do not have a SOC, and they do not need one. They need cheap tripwires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New branches with random or generated names&lt;/li&gt;
&lt;li&gt;Workflow files added or changed outside your normal branches&lt;/li&gt;
&lt;li&gt;Changes to &lt;code&gt;release.yml&lt;/code&gt; or whatever your publish workflow is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt; scripts changing, especially &lt;code&gt;postinstall&lt;/code&gt; or &lt;code&gt;preinstall&lt;/code&gt; appearing&lt;/li&gt;
&lt;li&gt;npm versions of your package you did not publish&lt;/li&gt;
&lt;li&gt;Actions runs with names you do not recognise (“Dependabot Updates” that you never configured)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two free tools cover most of this. Watch your own repo (Watch → Custom → Releases and Discussions plus rule-based notifications), and subscribe to your own package on npm so new-version emails reach you. The cheapest alert that something is wrong is an email about a release you did not make, arriving while you still have account access.&lt;/p&gt;
&lt;h2 id=&quot;8-prepare-for-account-lockout&quot;&gt;8. Prepare for account lockout&lt;/h2&gt;
&lt;p&gt;This is the section maintainers need most, and the one nobody writes.&lt;/p&gt;
&lt;p&gt;When an account is compromised, platforms suspend it. That is the right call for stopping the spread, and it has a brutal side effect: the maintainer loses access to the security log, the audit trail, the commit history, and the settings pages — the very evidence needed to prove which actions were not theirs, at exactly the moment everyone is asking.&lt;/p&gt;
&lt;p&gt;So keep a recovery file outside GitHub: a password-manager secure note, an encrypted local file, even a printed sheet. For each package:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;- npm package name
- GitHub repo URL
- npm owner account
- Trusted publisher settings (repo, workflow file, environment name)
- Normal release workflow path
- npm support: https://www.npmjs.com/support
- GitHub support: https://support.github.com
- Emergency contacts (co-maintainers, employer security team if relevant)
- Last known safe version
- The deprecate command:
    npm deprecate &amp;lt;pkg&amp;gt;@&amp;lt;bad-version&amp;gt; &quot;compromised - do not install&quot;
- The supersede command (publish a clean version ABOVE the bad one,
  because deprecation does not stop semver ranges resolving to it)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add to it the moment anything changes. The file costs you twenty minutes on a quiet afternoon. Its absence costs you days in the middle of the worst week of your maintainer life.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;Open source maintainers should not need to become incident response teams overnight.&lt;/p&gt;
&lt;p&gt;Until the platforms build better defaults, a small set of controls protects you before the panic starts: phishing-resistant login, a protected release branch, a locked release environment, minimal Actions permissions, no long-lived publish tokens, release files treated as infrastructure, cheap tripwires, and a recovery plan that still works if your GitHub or npm access disappears.&lt;/p&gt;
&lt;p&gt;None of this makes a maintainer invincible.&lt;/p&gt;
&lt;p&gt;It just means one stolen credential does not immediately become dozens of compromised packages, hundreds of malicious versions, and a maintainer locked out of the audit logs mid-incident.&lt;/p&gt;
&lt;p&gt;If you want the deeper dives: &lt;a href=&quot;https://arrangeactassert.com/posts/the-trusted-publishing-setting-that-would-have-blocked-the-npm-snapshot-branch-attacks/&quot;&gt;the trusted publishing setting that would have blocked the snapshot-branch attacks&lt;/a&gt; covers layer three in detail, and &lt;a href=&quot;https://arrangeactassert.com/posts/the-package-manager-settings-that-would-have-blocked-the-axios-attack/&quot;&gt;the package manager settings that would have blocked the Axios attack&lt;/a&gt; covers the consumer side. Publisher, consumer, and now the person in between.&lt;/p&gt;
</content:encoded></item><item><title>The trusted publishing setting that would have blocked the npm snapshot-branch attacks</title><link>https://arrangeactassert.com/posts/the-trusted-publishing-setting-that-would-have-blocked-the-npm-snapshot-branch-attacks/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-trusted-publishing-setting-that-would-have-blocked-the-npm-snapshot-branch-attacks/</guid><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In June 2026, a self-propagating npm worm compromised maintainer accounts and republished their packages with malware inside. Maintainers woke to hundreds of malicious versions across dozens of packages, often published in a few minutes overnight.&lt;/p&gt;
&lt;p&gt;Many of those versions went out through npm’s &lt;strong&gt;trusted publishing&lt;/strong&gt;, the tokenless way to publish from CI, and they carried &lt;strong&gt;valid provenance&lt;/strong&gt;. The green badge, the Sigstore attestation, the “built from this repo by this workflow” proof: all real.&lt;/p&gt;
&lt;p&gt;The worm never needed an npm password for those publishes. It used the release pipeline itself.&lt;/p&gt;
&lt;p&gt;Trusted publishing remains the right approach. Many configurations leave one field blank, and that blank field is the gap. Closing it takes about five minutes per package. This post shows the attack and the settings that would have stopped the snapshot-branch half of it.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;how-trusted-publishing-works-and-what-it-actually-checks&quot;&gt;How trusted publishing works (and what it actually checks)&lt;/h2&gt;
&lt;p&gt;Trusted publishing replaces long-lived npm tokens with a handshake between npm and your CI provider. You tell npm: “versions of this package may be published by &lt;em&gt;this&lt;/em&gt; GitHub repository, running &lt;em&gt;this&lt;/em&gt; workflow file.” When the workflow runs, GitHub mints a short-lived OIDC token (a signed statement describing the run), npm verifies the claims, and the publish goes through. No token sits in CI secrets waiting to be stolen.&lt;/p&gt;
&lt;p&gt;The default binding checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;repository&lt;/strong&gt; ✅&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;workflow filename&lt;/strong&gt; ✅ (e.g. &lt;code&gt;.github/workflows/release.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;branch&lt;/strong&gt; ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The binding says &lt;em&gt;which file&lt;/em&gt; may publish, but not &lt;em&gt;which ref&lt;/em&gt; it may run from.&lt;/p&gt;
&lt;h2 id=&quot;the-attack-bring-your-own-branch&quot;&gt;The attack: bring your own branch&lt;/h2&gt;
&lt;p&gt;The worm operated with stolen GitHub credentials that had push access. It avoided &lt;code&gt;main&lt;/code&gt;, where branch protection might have noticed. Instead, for each repository it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pushed a throwaway branch with a random name (&lt;code&gt;snapshot-a1b2c3d4&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Added its own &lt;code&gt;.github/workflows/release.yml&lt;/code&gt; on that branch, &lt;strong&gt;the same filename&lt;/strong&gt; as the project’s real release workflow, disguised with an innocent display name (“Dependabot Updates”)&lt;/li&gt;
&lt;li&gt;Gave the job &lt;code&gt;id-token: write&lt;/code&gt; and published&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;GitHub minted the OIDC token: correct repository ✅, correct workflow filename ✅. npm checked the claims: all match ✅. Publish accepted, provenance attached, badge green.&lt;/p&gt;
&lt;p&gt;The filename check fails when the attacker controls the file. Workflow files live in the repository, so anyone who can push a branch can create a workflow with any filename they like. The OIDC token includes which ref the workflow ran on. Default npm trusted publisher config does not require it. The worm used side branches because that path was easier, not because branch data was missing from the token.&lt;/p&gt;
&lt;p&gt;Every one of those malicious versions displayed valid provenance on npmjs.com. Provenance tells you a package was &lt;em&gt;built where it says it was built&lt;/em&gt;. It says nothing about whether anyone authorised that build. If you treat the badge as a trust signal, this attack breaks that assumption.&lt;/p&gt;
&lt;p&gt;The worm published with stolen credentials. GitHub and npm treated the runs as legitimate maintainer activity. The OIDC tokens and provenance were real. Authorisation was not. Platforms cannot distinguish your session from a stolen one without release rules you define.&lt;/p&gt;
&lt;h2 id=&quot;the-fix-make-the-branch-part-of-the-contract&quot;&gt;The fix: make the branch part of the contract&lt;/h2&gt;
&lt;p&gt;npm’s trusted publisher config has an optional field many people leave blank: &lt;strong&gt;Environment name&lt;/strong&gt;. It adds the missing branch dimension, provided you configure both halves.&lt;/p&gt;
&lt;h3 id=&quot;half-one-the-npm-side&quot;&gt;Half one: the npm side&lt;/h3&gt;
&lt;p&gt;In your package’s trusted publisher settings, set &lt;strong&gt;Environment name&lt;/strong&gt; to &lt;code&gt;release&lt;/code&gt;. npm now requires the OIDC token to carry an &lt;code&gt;environment: release&lt;/code&gt; claim. A workflow only gets that claim if its job declares:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; release&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;half-two-the-github-side-this-is-the-half-that-does-the-work&quot;&gt;Half two: the GitHub side (this is the half that does the work)&lt;/h3&gt;
&lt;p&gt;The attacker controls the workflow file. If the &lt;code&gt;release&lt;/code&gt; environment has no rules attached, they add &lt;code&gt;environment: release&lt;/code&gt; to their rogue workflow, GitHub grants it, and the publish goes through anyway. Configure the npm field and the GitHub environment together, or you gain nothing.&lt;/p&gt;
&lt;p&gt;The protection lives in the environment’s rules. In your repo: &lt;strong&gt;Settings → Environments → New environment → &lt;code&gt;release&lt;/code&gt;&lt;/strong&gt;, then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deployment branches and tags&lt;/strong&gt; → &lt;em&gt;Selected branches and tags&lt;/em&gt; → add &lt;code&gt;main&lt;/code&gt; (and &lt;code&gt;v*&lt;/code&gt; tags if you publish from tags)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Required reviewers&lt;/strong&gt; → add someone other than the account that pushes code, if you can (a co-maintainer or org teammate; solo maintainers need a second approver account or this layer does little, and it only helps while the attacker cannot disable the rule)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The chain now holds:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;npm demands an &lt;code&gt;environment: release&lt;/code&gt; claim&lt;/li&gt;
&lt;li&gt;GitHub only grants that environment to jobs running from &lt;code&gt;main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A workflow running from &lt;code&gt;snapshot-a1b2c3d4&lt;/code&gt; gets the environment refused, so no claim, so &lt;strong&gt;the publish is rejected&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A throwaway branch does not satisfy a main-only environment.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;Required reviewers&lt;/strong&gt; on top, a malicious commit on &lt;code&gt;main&lt;/code&gt; should pause the publish job until another human approves it. That only works when the approver is a different account from the one the attacker stole and the attacker cannot first remove or weaken the protection.&lt;/p&gt;
&lt;h2 id=&quot;the-hardened-release-workflow&quot;&gt;The hardened release workflow&lt;/h2&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .github/workflows/release.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Release

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; read &lt;span class=&quot;token comment&quot;&gt;# default-deny everywhere else&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; release &lt;span class=&quot;token comment&quot;&gt;# grants the claim npm now demands&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# refuse to run in forks/unexpected contexts&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; github.repository_owner == &apos;your&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;username&apos;
    &lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; read
      &lt;span class=&quot;token key atrule&quot;&gt;id-token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; write &lt;span class=&quot;token comment&quot;&gt;# ONLY on this job, never workflow-wide&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 &lt;span class=&quot;token comment&quot;&gt;# v5, pin to SHA&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@49933ea5288caeca8642d1e84afbd3f7d6820020 &lt;span class=&quot;token comment&quot;&gt;# v4, pin to SHA&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;registry-url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//registry.npmjs.org
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm ci &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;ignore&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;scripts
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run build &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm test
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm publish &lt;span class=&quot;token comment&quot;&gt;# OIDC, no token, no NODE_AUTH_TOKEN&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The details that matter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;environment: release&lt;/code&gt; on the publish job pairs with the npm field&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id-token: write&lt;/code&gt; goes &lt;strong&gt;only&lt;/strong&gt; on the publish job, never at workflow level&lt;/li&gt;
&lt;li&gt;Pin third-party actions to &lt;strong&gt;commit SHAs&lt;/strong&gt;, not tags. Tags can be moved to malicious commits.&lt;/li&gt;
&lt;li&gt;The repository-owner guard is a cheap extra tripwire&lt;/li&gt;
&lt;li&gt;In the npm trusted publisher settings, under allowed actions, tick only what you use (publish) and drop the rest&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-this-combination-works&quot;&gt;Why this combination works&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the attacker did&lt;/th&gt;
&lt;th&gt;What blocks it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pushed a rogue workflow on a throwaway branch&lt;/td&gt;
&lt;td&gt;Environment restricted to &lt;code&gt;main&lt;/code&gt; → no OIDC claim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reused the trusted workflow’s filename&lt;/td&gt;
&lt;td&gt;Filename no longer sufficient; the branch is checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Could declare &lt;code&gt;environment: release&lt;/code&gt; themselves&lt;/td&gt;
&lt;td&gt;Declaring ≠ receiving; GitHub enforces the rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publish from &lt;code&gt;main&lt;/code&gt; without a second approver&lt;/td&gt;
&lt;td&gt;Required reviewers, if the rule still exists and someone else must approve&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relied on valid provenance to look legitimate&lt;/td&gt;
&lt;td&gt;Provenance valid; the publish does not complete&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;what-this-closes&quot;&gt;What this closes&lt;/h2&gt;
&lt;p&gt;Environment binding blocks the snapshot-branch OIDC bypass: push &lt;code&gt;snapshot-*&lt;/code&gt;, add a rogue &lt;code&gt;release.yml&lt;/code&gt;, publish with valid provenance. Restrict the &lt;code&gt;release&lt;/code&gt; environment to &lt;code&gt;main&lt;/code&gt; and the publish fails before it reaches npm.&lt;/p&gt;
&lt;p&gt;The same June 2026 campaign used other paths. Attackers with stolen credentials pushed commits directly to &lt;code&gt;main&lt;/code&gt;, sometimes with forged commit metadata, and in some cases had enough GitHub privilege to remove branch protection first. Environment binding does not stop that. Pull request review and signed commits still raise the bar, but they help only while those protections still stand and the attacker cannot edit them. See &lt;a href=&quot;https://arrangeactassert.com/posts/the-github-and-npm-settings-open-source-maintainers-should-turn-on-before-they-need-them/&quot;&gt;the GitHub and npm settings checklist&lt;/a&gt; section 2 for that layer.&lt;/p&gt;
&lt;p&gt;The practical way to make that harder is to split authority. Let the account that pushes code be a non-admin maintainer account. Keep rulesets, environments, and recovery on a separate admin identity that is not used for normal development. If you use required reviewers, make that a third identity or a teammate account, not the same session that authors the change. That does not make account compromise harmless. It does stop one stolen day-to-day account from automatically being allowed to dismantle the repo settings first.&lt;/p&gt;
&lt;p&gt;If someone fully controls your GitHub account and can change environment rules or branch protection, no repo setting saves you on its own. Account hygiene (passkeys, credential separation, recovery notes outside GitHub) matters too. Entry in these campaigns is often credential harvest on a dev machine, not a misconfigured workflow.&lt;/p&gt;
&lt;p&gt;One stolen credential should not become silent publishes and silent commits. Different gates for different paths.&lt;/p&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;/h2&gt;
&lt;p&gt;Trusted publishing without an environment binding trusts a workflow filename. Workflow filenames are part of the repository, and an attacker who can push a branch can create a workflow file with the same name.&lt;/p&gt;
&lt;p&gt;The missing control for OIDC publishes is the branch rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the &lt;strong&gt;Environment name&lt;/strong&gt; in npm’s trusted publisher config&lt;/li&gt;
&lt;li&gt;Create the matching &lt;strong&gt;GitHub environment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Restrict it to &lt;code&gt;main&lt;/code&gt;, or to the tags you actually release from&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;required reviewer&lt;/strong&gt; if you have someone else who can approve&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That tightens provenance from “this came from a workflow with the right name” to “this came from a release path you defined.” It would have blocked the snapshot-branch OIDC publishes from the June 2026 campaign, and it blocks the same branch trick next time someone tries it.&lt;/p&gt;
&lt;p&gt;None of this makes a maintainer invincible. Pair it with branch protection, release-file controls, tripwires, and a recovery plan: &lt;a href=&quot;https://arrangeactassert.com/posts/the-github-and-npm-settings-open-source-maintainers-should-turn-on-before-they-need-them/&quot;&gt;the GitHub and npm settings checklist&lt;/a&gt; covers the rest.&lt;/p&gt;
&lt;p&gt;While you harden publishing: the &lt;a href=&quot;https://arrangeactassert.com/posts/the-package-manager-settings-that-would-have-blocked-the-axios-attack/&quot;&gt;package manager settings that would have blocked the Axios attack&lt;/a&gt; protect you as a &lt;em&gt;consumer&lt;/em&gt; of packages. This post protects you as a &lt;em&gt;publisher&lt;/em&gt;. You need both.&lt;/p&gt;
</content:encoded></item><item><title>Secure AI Apps Start With Functions, Not SQL</title><link>https://arrangeactassert.com/posts/secure-ai-apps-start-with-functions-not-sql/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/secure-ai-apps-start-with-functions-not-sql/</guid><pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;If you’re building AI features into your product, the temptation is to hand the model a database connection and let it write SQL.&lt;/p&gt;
&lt;p&gt;It feels powerful. It feels like the modern way.&lt;/p&gt;
&lt;p&gt;It’s the wrong place to start.&lt;/p&gt;
&lt;p&gt;The same reasoning applies whether you’re building a CLI, a Slack bot, an MCP server, or an agent.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Secure AI Apps Start With Functions, Not SQL&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1672px) 1672px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1672&quot; height=&quot;941&quot; src=&quot;https://arrangeactassert.com/_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_Z2oO5Cb.webp&quot; srcset=&quot;/_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_ZrcAYg.webp 640w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_1WLQkS.webp 750w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_Zub2be.webp 828w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_Z1qzVNv.webp 1080w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_2gJoBQ.webp 1280w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_Z2gMow2.webp 1668w, /_astro/secure-ai-apps-start-with-functions-not-sql.f1nJPDYA_Z2oO5Cb.webp 1672w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;tl;dr: Build a typed, composable function layer first. Lock down the database, shape responses with DTOs, redact sensitive fields, and expose only those safe functions to CLIs, Slack bots, MCP servers, and agents. The AI layer is easy to swap. The function layer is what matters.&lt;/p&gt;
&lt;h2 id=&quot;functions-not-prompts&quot;&gt;Functions, not prompts&lt;/h2&gt;
&lt;p&gt;In most product use cases, you don’t need text-to-SQL at all. You need a small set of predefined functions that do useful things.&lt;/p&gt;
&lt;p&gt;If you’re building around payments, that might look like:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getLatestPaymentsForClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;clientId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getFailedPaymentsForClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;clientId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getClientPaymentSummary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;clientId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each function does one thing, takes a fixed set of arguments, and returns predictable JSON. Good JSDoc, typed inputs, typed outputs, a clear purpose. That is the foundation.&lt;/p&gt;
&lt;p&gt;Not prompts. Not agents. Not text-to-SQL. Functions.&lt;/p&gt;
&lt;p&gt;The reason this matters is composability. If a function has a single responsibility and returns structured JSON, anything can sit on top of it: a CLI, a Slack bot, an MCP server, an HTTP API, an agent. The contract is fixed, so you always know what goes in and what comes out.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    DB[(&quot;Approved data source&quot;)]
    Core[&quot;Core functions&amp;lt;br/&amp;gt;typed inputs, safe outputs&quot;]
    CLI[&quot;CLI&quot;]
    Slack[&quot;Slack bot&quot;]
    MCP[&quot;MCP server&quot;]
    API[&quot;HTTP API&quot;]
    Agents[&quot;AI agents&quot;]

    DB --&amp;gt; Core
    Core --&amp;gt; CLI
    Core --&amp;gt; Slack
    Core --&amp;gt; MCP
    Core --&amp;gt; API
    Core --&amp;gt; Agents
&lt;/pre&gt;
&lt;p&gt;Read that diagram as: one safe layer in the middle, many ways for people and machines to use it.&lt;/p&gt;
&lt;h2 id=&quot;build-the-cli-or-slack-bot-first&quot;&gt;Build the CLI or Slack bot first&lt;/h2&gt;
&lt;p&gt;Before you add any AI at all, I’d actually recommend wiring up a CLI or a Slack bot.&lt;/p&gt;
&lt;p&gt;It sounds backwards, but it forces you to design the interaction model properly. Start with a simple menu of domains:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Clients
Payments
Invoices
Orders&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within each domain the user picks an action: latest payments for a client, failed payments, account summary, recent invoices. They’re calling the same predefined functions an agent would call, just through a menu instead of natural language.&lt;/p&gt;
&lt;p&gt;This is a good thing, because the first job is not making it intelligent. The first job is making it safe.&lt;/p&gt;
&lt;h2 id=&quot;least-privilege-starts-at-the-database&quot;&gt;Least privilege starts at the database&lt;/h2&gt;
&lt;p&gt;Do not expose more than you need to.&lt;/p&gt;
&lt;p&gt;Start with a read-only database connection. Better still, create a database user that only has access to the specific tables or collections the tooling needs.&lt;/p&gt;
&lt;p&gt;If your database contains API keys, secrets, admin data, audit logs, or sensitive customer records, your AI tooling should not be able to touch those tables at all. That’s the first security boundary.&lt;/p&gt;
&lt;p&gt;The second boundary is the function itself. Even when the database user can read a table, the function should not return everything from it. This is where DTOs earn their keep.&lt;/p&gt;
&lt;p&gt;A payment record might have twenty internal fields. The function returns six:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;paymentId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pay_123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;clientName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Acme Ltd&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;currency&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GBP&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;paid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;createdAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2026-05-01&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No raw metadata, no internal IDs, no private fields, no PII unless it’s genuinely required.&lt;/p&gt;
&lt;p&gt;That JSON is what the engineer sees. The business user sees something like this in Slack:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acme Ltd&lt;/strong&gt;
Last payment: £1,200 on 1 May 2026
Status: Paid
Outstanding invoices: 2 (£3,400)
Open support tickets: 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Same data, same function call, just rendered for a human instead of piped to another tool. A salesperson can pull that up before a call, a support agent can quote it on a ticket, and an AI agent can read it as context. None of them need direct database access to do it.&lt;/p&gt;
&lt;p&gt;Database permissions can restrict tables and sometimes columns, but they can’t shape responses per use case. DTOs can, and they give you a natural place to redact. If a value should never reach Slack, the CLI, the MCP server, or the model, redact it before it leaves the function. Your AI layer should never be the thing deciding what’s safe.&lt;/p&gt;
&lt;h2 id=&quot;what-youve-actually-built&quot;&gt;What you’ve actually built&lt;/h2&gt;
&lt;p&gt;By this point you have something stronger than “an AI app”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a read-only database user with restricted table access&lt;/li&gt;
&lt;li&gt;a set of approved functions&lt;/li&gt;
&lt;li&gt;DTOs that only expose safe fields&lt;/li&gt;
&lt;li&gt;redaction at the function boundary&lt;/li&gt;
&lt;li&gt;JSON schemas for predictable outputs&lt;/li&gt;
&lt;li&gt;typed inputs and outputs end to end&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And because the output is structured JSON, the CLI gets a useful side effect for free. You can pipe through &lt;code&gt;jq&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;payments list &lt;span class=&quot;token parameter variable&quot;&gt;--client&lt;/span&gt; acme &lt;span class=&quot;token parameter variable&quot;&gt;--json&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq &lt;span class=&quot;token string&quot;&gt;&apos;.[] | select(.status == &quot;failed&quot;)&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s the same composability the AI layer will need, just exposed to humans first. If &lt;code&gt;jq&lt;/code&gt; can chain your tools cleanly, an agent can too.&lt;/p&gt;
&lt;h2 id=&quot;now-youre-ready-for-ai&quot;&gt;Now you’re ready for AI&lt;/h2&gt;
&lt;p&gt;The key is not “give the model SQL access”. The key is deciding which use cases AI should actually support.&lt;/p&gt;
&lt;p&gt;Maybe you need a payments agent, a client insights agent, a support agent, a sales enablement agent. Each one only gets the tools it needs. The payments agent gets payment tools. The support agent gets support tools. No agent gets broad access. No agent invents arbitrary queries.&lt;/p&gt;
&lt;p&gt;You can put a routing agent at the front to send a request to the right specialist, and each specialist can have its own instructions and few-shot examples. But the agents are not the foundation. The tools are. The functions are. The schemas are. The safe data shapes are.&lt;/p&gt;
&lt;p&gt;With TypeScript, Pydantic, Zod, or JSON Schema, the entire chain is type-safe end to end. You know what each tool takes, what it returns, how to validate it, and how to document it. That matters a lot once a function becomes an AI tool, because the description, the name, the schema, and the return shape all become part of the prompt the model reads.&lt;/p&gt;
&lt;p&gt;This is why the core function layer deserves the most effort.&lt;/p&gt;
&lt;h2 id=&quot;a-note-on-the-database-itself&quot;&gt;A note on the database itself&lt;/h2&gt;
&lt;p&gt;Your AI features and internal tools should ideally not hit production directly.&lt;/p&gt;
&lt;p&gt;A read replica is a good first step: a bad query won’t take down the live application. A better setup is change data capture, like CDC or MongoDB change streams. You capture events from production and write them into a separate database that exists specifically for internal tooling, reporting, and AI.&lt;/p&gt;
&lt;p&gt;That database is read-only from the AI app’s perspective. It only contains the fields these tools are allowed to consume. It can store redacted or transformed versions of records. If something ever goes wrong, you revoke one connection string without touching production.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
    Prod[(&quot;Production database&quot;)]
    Stream[&quot;Change events&quot;]
    Tool[(&quot;Tooling database&amp;lt;br/&amp;gt;read-only, redacted&quot;)]
    Core[&quot;Core functions&quot;]
    Users[&quot;CLI / Slack / MCP / Agents&quot;]

    Prod --&amp;gt;|CDC or events| Stream
    Stream --&amp;gt; Tool
    Tool --&amp;gt; Core
    Core --&amp;gt; Users
&lt;/pre&gt;
&lt;p&gt;The arrows only go one way. Nothing on the right can write back to production.&lt;/p&gt;
&lt;p&gt;If you already have event-driven architecture, this is even cleaner. The tooling database is just another subscriber. You can choose between thin events (minimal payload, requires another lookup) and fat events (the full approved payload). For AI and internal tooling, fat events are often more useful, because the event itself can carry exactly what the tools are allowed to see.&lt;/p&gt;
&lt;p&gt;If CDC or events aren’t on the table yet, dual-writing from the application to a tooling database is a fallback. It’s not perfect, but it’s still better than handing AI broad access to production.&lt;/p&gt;
&lt;h2 id=&quot;dont-forget-observability&quot;&gt;Don’t forget observability&lt;/h2&gt;
&lt;p&gt;Whatever shape this takes, you need to know what’s happening: which tools are being called, by whom, with what arguments, what they returned, which agents called which functions, where errors are happening, and whether anyone is trying to use the tools in ways the design didn’t anticipate.&lt;/p&gt;
&lt;p&gt;Security isn’t only about blocking access. It’s also about being able to see what’s going on.&lt;/p&gt;
&lt;h2 id=&quot;what-this-unlocks&quot;&gt;What this unlocks&lt;/h2&gt;
&lt;p&gt;With this foundation, the same function layer powers a lot of useful things at once. Customer support can answer questions faster. Account managers can pull client activity without filing tickets. Sales can get context before a call. Operations can investigate issues without engineering help.&lt;/p&gt;
&lt;p&gt;In the repo, the effort goes into one place: a &lt;code&gt;core&lt;/code&gt; package holding the functions, DTOs, schemas, types, redaction, descriptions, OpenAPI specs, and MCP tool definitions. Everything else just consumes &lt;code&gt;core&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;/packages
  /core
  /cli
  /slackbot
  /mcp-server
  /api
  /agents&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every surface shares the same logic, the same DTOs, the same safety rules.&lt;/p&gt;
&lt;p&gt;The mistake is thinking the AI layer is the product. It usually isn’t.&lt;/p&gt;
&lt;p&gt;The real product is the secure, typed, composable function layer underneath.&lt;/p&gt;
&lt;p&gt;AI is just another interface on top of it, and probably not the last one you’ll add.&lt;/p&gt;
</content:encoded></item><item><title>node-env-resolver Makes Safe, Typed Node Config the Default</title><link>https://arrangeactassert.com/posts/node-env-resolver-makes-safe-typed-node-config-the-default/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/node-env-resolver-makes-safe-typed-node-config-the-default/</guid><pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Liran Tal is spot on in his &lt;a href=&quot;https://lirantal.com/blog/environment-variables-configuration-anti-patterns-node-js-applications&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Environment variables and configuration anti-patterns in Node.js applications&lt;/a&gt; post&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may inadvertently expose sensitive information like database credentials and API keys as part of error messages, stack traces, and other forms of data returned to consuming clients.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He explains why &lt;code&gt;process.env&lt;/code&gt; feels safe right up until it isn’t.&lt;/p&gt;
&lt;p&gt;You add &lt;code&gt;dotenv.config()&lt;/code&gt; on line one, scatter &lt;code&gt;process.env.DB_PASSWORD&lt;/code&gt; across twelve files, then someone’s error reporter serialises a request object and your Stripe key ends up in a third-party log.&lt;/p&gt;
&lt;p&gt;If you’ve shipped a Node app, you’ve probably seen some version of this happen.&lt;/p&gt;
&lt;p&gt;His anti-pattern example nails it:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dbUsername &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_USERNAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dbPassword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dbHost &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; apiBaseUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;API_BASE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; apiToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;API_TOKEN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Untyped. Unvalidated. Globally readable. One step away from leaking through logs, traces, or error reporters.&lt;/p&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Liran’s article names the anti-patterns. It stops short of offering a concrete implementation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node-env-resolver&lt;/code&gt; is a strong answer to that gap. It resolves config into a typed object, limits reliance on global &lt;code&gt;process.env&lt;/code&gt;, blocks &lt;code&gt;.env&lt;/code&gt; files in production by default, and adds runtime redaction safeguards.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;A single Node app reads config from five places:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// server.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// database.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dbUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// auth.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jwtSecret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// routes.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; apiKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// stripe.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stripeKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Five files. Five untyped reads. Zero validation. Five modules that can be tested only by mutating &lt;code&gt;process.env&lt;/code&gt; in &lt;code&gt;beforeEach&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And every one of those values sits in global process state, where any module can reach it and where logs, traces, serialised errors, or child-process boundaries can expose it.&lt;/p&gt;
&lt;h2 id=&quot;one-schema-zero-processenv-writes&quot;&gt;One Schema. Zero process.env Writes&lt;/h2&gt;
&lt;p&gt;With &lt;code&gt;node-env-resolver&lt;/code&gt;, the same app gets one typed config object, assembled at startup, injected into the modules that need it:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolve &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  secret&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; min&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;DATABASE_URL&lt;/code&gt; is missing, the app fails at startup with a descriptive error. Not on the first request. Not in production at 3am. At startup.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;config.PORT&lt;/code&gt; is &lt;code&gt;number&lt;/code&gt;. &lt;code&gt;config.DATABASE_URL&lt;/code&gt; is &lt;code&gt;string&lt;/code&gt; and guaranteed to parse as a Postgres URL. &lt;code&gt;process.env.STRIPE_SECRET_KEY&lt;/code&gt; stays &lt;code&gt;undefined&lt;/code&gt;, because &lt;code&gt;preventProcessEnvWrite&lt;/code&gt; is on by default.&lt;/p&gt;
&lt;p&gt;One typed config object, validated once at boot.&lt;/p&gt;
&lt;h3 id=&quot;which-values-are-enforced&quot;&gt;Which values are enforced?&lt;/h3&gt;
&lt;p&gt;Every key in your schema. Required validators throw if missing. Bare literals act as typed defaults. Array literals become enums:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;                                          &lt;span class=&quot;token comment&quot;&gt;// number, default 3000&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;HOST&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;localhost&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;                                   &lt;span class=&quot;token comment&quot;&gt;// string, default&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// enum, required&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;                            &lt;span class=&quot;token comment&quot;&gt;// required, parsed&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; min&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pattern&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;^[a-zA-Z0-9]+$&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// required, validated&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;safety-rails&quot;&gt;Safety rails&lt;/h3&gt;
&lt;p&gt;In production, &lt;code&gt;node-env-resolver&lt;/code&gt; applies stricter policies automatically: &lt;code&gt;.env&lt;/code&gt; files are blocked, audit logging is on, &lt;code&gt;process.env&lt;/code&gt; writes are prevented, missing required keys fail fast. The application code stays the same, while production gets stricter defaults automatically.&lt;/p&gt;
&lt;h2 id=&quot;manual-processenv-vs-node-env-resolver&quot;&gt;Manual process.env vs node-env-resolver&lt;/h2&gt;
&lt;p&gt;The manual approach reads &lt;code&gt;process.env&lt;/code&gt; directly, with a light dusting of defaults:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual: scattered, untyped, unsafe&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dotenv/config&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDatabase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;DATABASE_URL required&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    poolSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; jwt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    secret&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    expiry&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JWT_EXPIRY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1h&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;node-env-resolver&lt;/code&gt;, config is a typed value you pass in:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolve &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  secret&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  duration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;JWT_EXPIRY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1h&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDatabase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cfg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pick&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DATABASE_URL&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_POOL_SIZE&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; poolSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cfg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pick&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;JWT_SECRET&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;JWT_EXPIRY&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; jwt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secret&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expiry&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JWT_EXPIRY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No &lt;code&gt;process.env&lt;/code&gt; reads inside modules. No coercion. No runtime &lt;code&gt;undefined&lt;/code&gt;. Tests pass a literal config object, no &lt;code&gt;vi.mock&lt;/code&gt; required.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual dotenv / process.env&lt;/th&gt;
&lt;th&gt;node-env-resolver&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;process.env.FOO&lt;/code&gt; may be undefined&lt;/td&gt;
&lt;td&gt;Inferred types: &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, enum literals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Values written to &lt;code&gt;process.env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;preventProcessEnvWrite&lt;/code&gt; on by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.env&lt;/code&gt; works everywhere, including prod&lt;/td&gt;
&lt;td&gt;Blocked in production by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No validation&lt;/td&gt;
&lt;td&gt;Required validators throw at startup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No provenance&lt;/td&gt;
&lt;td&gt;Every value records its source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets may leak via logs/errors&lt;/td&gt;
&lt;td&gt;&lt;code&gt;protect()&lt;/code&gt; patches console and redacts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test by mutating &lt;code&gt;process.env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test by passing a plain object&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;on-dotenv-increases-exposure&quot;&gt;On “dotenv Increases Exposure”&lt;/h2&gt;
&lt;p&gt;He’s right to flag it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dotenv.config()&lt;/code&gt; loads your &lt;code&gt;.env&lt;/code&gt; into &lt;code&gt;process.env&lt;/code&gt;, and &lt;code&gt;process.env&lt;/code&gt; is global state. Any module, any dependency, any serialised error object can read it. That doesn’t guarantee a leak, but it widens the surface area considerably, and most leaks I’ve seen in the wild took this path.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;node-env-resolver&lt;/code&gt; treats &lt;code&gt;process.env&lt;/code&gt; as an input, not an output. Resolved values land in a typed object that only the modules you inject into can see. In production, &lt;code&gt;.env&lt;/code&gt; files are refused by default:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// In production, dotenv is ignored by default.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Config must come from processEnv, secrets managers, or mounted files.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  resolvers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processEnv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;awsSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod/app&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    policies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      enforceAllowedSources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;aws-secrets&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;aws-secrets&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;aws-secrets&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;enforceAllowedSources&lt;/code&gt; means a deploy that accidentally drops &lt;code&gt;STRIPE_SECRET_KEY&lt;/code&gt; into &lt;code&gt;process.env&lt;/code&gt; fails startup instead of silently overriding the value from AWS.&lt;/p&gt;
&lt;h2 id=&quot;runtime-redaction-without-the-boilerplate&quot;&gt;Runtime Redaction Without the Boilerplate&lt;/h2&gt;
&lt;p&gt;Knowing the secrets never reach &lt;code&gt;process.env&lt;/code&gt; is half the battle. The other half is keeping them out of logs and HTTP responses.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolve &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  protect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  createResponseMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/runtime&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; secret &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; unprotect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;protect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Connecting with key: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Connecting with key: [REDACTED]&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createResponseMiddleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Response bodies are scanned for resolved secret values and redacted before send.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;protect()&lt;/code&gt; patches &lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;console.error&lt;/code&gt;, and &lt;code&gt;console.warn&lt;/code&gt; to match the resolved secret values and replace them with &lt;code&gt;[REDACTED]&lt;/code&gt;. The Express and Hono middleware do the same scan on response bodies.&lt;/p&gt;
&lt;p&gt;It’s a safety net, not a silver bullet. If a secret arrives through a different channel, or gets transformed before logging, the redactor won’t catch it. Treat it as defence in depth on top of not leaking in the first place.&lt;/p&gt;
&lt;h2 id=&quot;provenance-when-you-need-it&quot;&gt;Provenance When You Need It&lt;/h2&gt;
&lt;p&gt;When an incident hits and someone asks “where did this value come from”, most apps have no answer. &lt;code&gt;node-env-resolver&lt;/code&gt; records the source of every resolved value, auto-enabled in production:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getAuditLog&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createDebugView &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; events &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getAuditLog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// env_loaded  key=DATABASE_URL  source=processEnv&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// env_loaded  key=API_KEY       source=aws-secrets  resolvedVia=aws-sm://prod/api-key&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; debug &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDebugView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// DATABASE_URL: [REDACTED]  source: processEnv&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// API_KEY:      [REDACTED]  source: aws-secrets&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getAuditLog()&lt;/code&gt; gives event history, &lt;code&gt;createDebugView(config)&lt;/code&gt; gives a redacted current snapshot, and provenance tracks source metadata in both views. Raw values are never included, only names and sources.&lt;/p&gt;
&lt;h2 id=&quot;adopting-it-in-an-existing-app&quot;&gt;Adopting it in an existing app&lt;/h2&gt;
&lt;p&gt;If you’re retrofitting this into a running service, the order matters more than the final shape. I’d do it in three passes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a single &lt;code&gt;config.ts&lt;/code&gt; and resolve everything there. Don’t change any callers yet. Just prove the schema validates at startup in every environment.&lt;/li&gt;
&lt;li&gt;Move modules off direct &lt;code&gt;process.env&lt;/code&gt; reads one at a time, passing &lt;code&gt;Pick&amp;lt;typeof config, ...&amp;gt;&lt;/code&gt; into the functions that need them. Tests get easier with each one.&lt;/li&gt;
&lt;li&gt;Turn on the stricter policies last: &lt;code&gt;enforceAllowedSources&lt;/code&gt;, response middleware, audit logging. By this point the schema is the source of truth and you can tighten without hunting.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The mistake is doing all three at once. Each pass is a small, safe PR. Together they replace the ad-hoc config layer without a big-bang rewrite.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; node-env-resolver
&lt;span class=&quot;token comment&quot;&gt;# Optional integrations&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; node-env-resolver-aws&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Minimal usage, sync:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolve &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; min&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With AWS Secrets Manager, async:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolveAsync &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; processEnv &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/resolvers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; awsSecrets &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver-aws&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  resolvers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processEnv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;awsSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod/app&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Scan a repo for hardcoded secrets before they ship:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx node-env-resolver scan src/
npx node-env-resolver scan &lt;span class=&quot;token parameter variable&quot;&gt;--staged&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-config-you-want&quot;&gt;The Config You Want&lt;/h2&gt;
&lt;p&gt;One file, every environment:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// config.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolve &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  redis&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  duration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  secret&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;REDIS_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; optional&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;CACHE_TTL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;5m&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token constant&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;JWT_EXPIRY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1h&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token constant&quot;&gt;ADMIN_EMAIL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;ENABLE_METRICS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;LOG_LEVEL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;debug&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;info&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;warn&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modules take what they need:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// database.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDatabase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cfg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pick&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DATABASE_URL&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_POOL_SIZE&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; poolSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cfg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// server.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; config &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./config&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createDatabase &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./database&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDatabase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tests stop mocking &lt;code&gt;process.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;connects with the provided URL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createDatabase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;postgres://testuser:testpass@localhost:5432/testdb&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;DB_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// assertions&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Zod and Valibot schemas are supported via &lt;code&gt;resolveZod&lt;/code&gt; and &lt;code&gt;resolveValibot&lt;/code&gt; if you’re already using them.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/node-env-resolver&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/node-env-resolver&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Log the Fingerprint, Not the Secret</title><link>https://arrangeactassert.com/posts/log-the-fingerprint-not-the-secret/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/log-the-fingerprint-not-the-secret/</guid><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;When something goes wrong with your application’s configuration, you need to know what was loaded and where it came from.&lt;/p&gt;
&lt;p&gt;Most tools for answering that question either tell you too much or nothing at all.&lt;/p&gt;
&lt;p&gt;There’s a third option most people haven’t considered.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Log the Fingerprint, Not the Secret&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_1nnlKr.webp&quot; srcset=&quot;/_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_o3sCp.webp 640w, /_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_1WUVNp.webp 750w, /_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_Z5zP4e.webp 828w, /_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_2dqi5l.webp 1080w, /_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_Z1QTYdR.webp 1280w, /_astro/log-the-fingerprint-not-the-secret.C_PSlEL4_1nnlKr.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;tl;dr: At startup, log SHA-256 fingerprints of secrets, not the secrets themselves. You can verify consistency and rotation without exposing credentials.&lt;/p&gt;
&lt;p&gt;It’s 2 a.m. An alert fires… payment processing is down. Your first instinct is a credentials issue: something rotated, or didn’t rotate when it should have.&lt;/p&gt;
&lt;p&gt;You need to know which secrets were loaded at startup, which resolver provided them, and whether the rotation propagated correctly.&lt;/p&gt;
&lt;p&gt;Most config systems leave you with two choices:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option A.&lt;/strong&gt; Add debug logging. Print config values at startup so you can see what the application saw. The answer appears, and so do your database password and payment processor API key, now living in your log aggregator, possibly forwarded to a third-party service, accessible to anyone with log access. You’ve answered the debugging question by widening the blast radius.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option B.&lt;/strong&gt; Don’t log values. Fly blind. Redeploy, restart, check metrics, try to reason about what the application saw without being able to see it directly.&lt;/p&gt;
&lt;p&gt;Neither is good.&lt;/p&gt;
&lt;h2 id=&quot;the-assumption-underneath-both-options&quot;&gt;The assumption underneath both options&lt;/h2&gt;
&lt;p&gt;To debug configuration, people assume they need to see the values. They usually don’t.&lt;/p&gt;
&lt;p&gt;What you need to know in a debugging scenario:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Did this variable resolve at all?&lt;/li&gt;
&lt;li&gt;Which resolver provided it (&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;process.env&lt;/code&gt;, AWS Secrets Manager)?&lt;/li&gt;
&lt;li&gt;Did the rotation work? Is the value different from what it was yesterday?&lt;/li&gt;
&lt;li&gt;Is every pod seeing the same value?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of those questions require seeing the plaintext value. They require an &lt;em&gt;identity signal&lt;/em&gt;: something that lets you verify whether a value is present, correct, and consistent without being the value itself.&lt;/p&gt;
&lt;p&gt;A cryptographic fingerprint is that signal.&lt;/p&gt;
&lt;p&gt;For very low-entropy values (e.g., a boolean flag, a small integer timeout, a known environment name like production), a SHA-256 fingerprint can be brute-forced by an attacker who guesses the few possible inputs.&lt;/p&gt;
&lt;p&gt;In those cases, prefer &lt;code&gt;length&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt; over &lt;code&gt;fingerprint&lt;/code&gt;. For high-entropy secrets (API keys, passwords, tokens), fingerprinting is safe.&lt;/p&gt;
&lt;p&gt;A common middle ground is redaction: logging [REDACTED] in place of the value. That tells you a value existed, but nothing else: not whether it changed, not whether pods are consistent.&lt;/p&gt;
&lt;p&gt;Redaction hides the secret but gives you no verification signal. Fingerprints give you both.&lt;/p&gt;
&lt;h2 id=&quot;what-fingerprints-give-you&quot;&gt;What fingerprints give you&lt;/h2&gt;
&lt;p&gt;A short SHA-256 fingerprint usually gives you enough signal to debug an incident without exposing the secret itself.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;DATABASE_URL&lt;/code&gt; produces fingerprint &lt;code&gt;sha256:4f91b0c2&lt;/code&gt; across all your pods, the value is consistent. If one pod shows &lt;code&gt;sha256:4f91b0c2&lt;/code&gt; and another shows &lt;code&gt;sha256:94e1b7aa&lt;/code&gt;, something is wrong and you’ve located it without printing either credential. If after rotating a secret the fingerprint changes from &lt;code&gt;sha256:4f91b0c2&lt;/code&gt; to &lt;code&gt;sha256:7a3c9f11&lt;/code&gt;, the rotation propagated. If it didn’t change, it didn’t.&lt;/p&gt;
&lt;p&gt;Truncating the hash to eight hex characters leaves about 4 billion possible values. For a handful of config keys per service, the chance of two different secrets producing the same prefix is negligible.&lt;/p&gt;
&lt;p&gt;The prefix is for operational convenience (short log lines, easy to grep), not a security boundary, and the full hash is available if you ever need it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;sha256:&lt;/code&gt; prefix is part of the fingerprint string by convention, which leaves room for a stronger algorithm later (say &lt;code&gt;sha512:&lt;/code&gt; or &lt;code&gt;blake3:&lt;/code&gt;) without breaking consumers that parse the prefix.&lt;/p&gt;
&lt;h2 id=&quot;what-safe-debug-output-looks-like&quot;&gt;What safe debug output looks like&lt;/h2&gt;
&lt;p&gt;In any language, the pattern is the same: compute a SHA-256 fingerprint, log it with metadata like key and source, then discard the plaintext. Here’s how it looks with &lt;a href=&quot;https://github.com/jagreehal/node-env-resolver&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;node-env-resolver&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolveAsync &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; awsSecretHandler &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver-aws&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; debugEntries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  schema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  references&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    handlers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;aws-sm&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; awsSecretHandler&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    debug&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      valueMode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fingerprint&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      includeSource&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;onDebugEntry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; debugEntries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;config_loaded&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; debugEntries &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Config loaded&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each entry looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DATABASE_URL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;resolved&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;process.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;reference&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aws-sm://prod/app/database_url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;resolvedVia&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aws-sm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sensitive&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;length&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;fingerprint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sha256:d0976d8b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preview&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token null keyword&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No plaintext. No partial reveal. Source, provenance, fingerprint. These answer most of the questions you have during an incident.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;reference&lt;/code&gt; and &lt;code&gt;resolvedVia&lt;/code&gt; fields show the full chain: the reference string loaded from &lt;code&gt;process.env&lt;/code&gt;, the handler (&lt;code&gt;aws-sm&lt;/code&gt;) that dereferenced it, and the resulting fingerprint of the final value.&lt;/p&gt;
&lt;h2 id=&quot;incident-response-in-practice&quot;&gt;Incident response in practice&lt;/h2&gt;
&lt;p&gt;Back in the 2 a.m. scenario. You pull the config snapshot from your log aggregator:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jq &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.entries[] | &quot;\(.key) \(.fingerprint // &quot;none&quot;) \(.resolvedVia // .source)&quot;&apos;&lt;/span&gt; config-snapshot-*.json &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;DATABASE_URL sha256:4f91b0c2 aws-sm
STRIPE_SECRET_KEY sha256:7a3c9f11 aws-sm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Across all pods, the fingerprints are consistent and the sources are correct.&lt;/p&gt;
&lt;p&gt;Check whether the rotation propagated:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# yesterday&lt;/span&gt;
DATABASE_URL sha256:e2d9a1c3 aws-sm

&lt;span class=&quot;token comment&quot;&gt;# tonight&lt;/span&gt;
DATABASE_URL sha256:4f91b0c2 aws-sm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fingerprint changed. Rotation worked. Confirmed in thirty seconds, from logs.&lt;/p&gt;
&lt;p&gt;Post-incident rotations are this scenario at scale. After the &lt;a href=&quot;https://vercel.com/kb/bulletin/vercel-april-2026-security-incident&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vercel April 2026 security incident&lt;/a&gt;, affected customers were asked to rotate any credentials stored as non-sensitive environment variables. That means dozens of secrets rotated under time pressure, each requiring confirmation that every pod picked up the new value. Fingerprint logs turn that confirmation into a diff; without them, you’re trusting that rotation worked.&lt;/p&gt;
&lt;h2 id=&quot;the-four-visibility-modes&quot;&gt;The four visibility modes&lt;/h2&gt;
&lt;p&gt;The debug system supports four modes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Key, resolved state, source&lt;/td&gt;
&lt;td&gt;Default production logging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;length&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Above + value length&lt;/td&gt;
&lt;td&gt;Minimal leak risk, basic verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fingerprint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Above + SHA-256 hash, length&lt;/td&gt;
&lt;td&gt;Incident response, rotation verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;masked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Partial preview (first/last chars)&lt;/td&gt;
&lt;td&gt;Never in production, only for local troubleshooting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For production incident diagnostics, &lt;code&gt;fingerprint&lt;/code&gt; is often the most useful choice for high-entropy secrets. Stricter environments may prefer &lt;code&gt;none&lt;/code&gt; by default and only turn on fingerprinting during an incident. &lt;code&gt;length&lt;/code&gt; sits between them when you want the lowest possible leak surface and only need to confirm a value was loaded. &lt;code&gt;masked&lt;/code&gt; exists for local development only: a partial reveal like &lt;code&gt;sk_live_...4f91&lt;/code&gt; still leaks information and should never appear in production logs.&lt;/p&gt;
&lt;p&gt;For hard masking of values that slip into console logs or HTTP responses, libraries like &lt;code&gt;node-env-resolver&lt;/code&gt;’s &lt;code&gt;protect()&lt;/code&gt; replace sensitive values with &lt;code&gt;[REDACTED]&lt;/code&gt; at the output boundary: a different tool, for a different job.&lt;/p&gt;
&lt;h2 id=&quot;log-once-at-startup&quot;&gt;Log once, at startup&lt;/h2&gt;
&lt;p&gt;Log the snapshot once when config loads. The goal is a startup audit trail, not request-level logging.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// At startup, after resolve():&lt;/span&gt;
logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;config_loaded&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    service&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SERVICE_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    entries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; debugEntries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Config loaded successfully&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Store these in a place your security team can access during an incident, such as a separate log stream or dedicated audit index that won’t get mixed in with noisy application logs and rolled off before anyone needs it.&lt;/p&gt;
&lt;h2 id=&quot;the-principle&quot;&gt;The principle&lt;/h2&gt;
&lt;p&gt;The assumption that you need to &lt;em&gt;see&lt;/em&gt; a value to &lt;em&gt;know&lt;/em&gt; it’s correct is wrong. A fingerprint tells you whether a value is present, whether it is consistent across instances, and whether it has changed.&lt;/p&gt;
&lt;p&gt;Observability and security don’t have to conflict. The tension comes from bad tooling. With identity signals, you can verify configuration state without exposing the values themselves.&lt;/p&gt;
&lt;p&gt;If a secret ends up in your logs, your incident response just created a new incident.&lt;/p&gt;
&lt;p&gt;Fingerprints let you answer the question without creating the problem.&lt;/p&gt;
</content:encoded></item><item><title>Your .env File Is Not a Secret Store</title><link>https://arrangeactassert.com/posts/your-env-file-is-a-secret-store/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/your-env-file-is-a-secret-store/</guid><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Most teams make one of two mistakes with secrets.&lt;/p&gt;
&lt;p&gt;The first is obvious.&lt;/p&gt;
&lt;p&gt;The second is more common in teams that have already fixed the first one.&lt;/p&gt;
&lt;p&gt;Both come from the same misunderstanding about what a &lt;code&gt;.env&lt;/code&gt; file is supposed to do.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Your .env File Is Not a Secret Store&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/your-env-file-is-a-secret-store.IcyLlBkj_ZPtJcM.webp&quot; srcset=&quot;/_astro/your-env-file-is-a-secret-store.IcyLlBkj_NfE9b.webp 640w, /_astro/your-env-file-is-a-secret-store.IcyLlBkj_1AvoCm.webp 750w, /_astro/your-env-file-is-a-secret-store.IcyLlBkj_Z1N6OHY.webp 828w, /_astro/your-env-file-is-a-secret-store.IcyLlBkj_Z15eQod.webp 1080w, /_astro/your-env-file-is-a-secret-store.IcyLlBkj_1kwaXU.webp 1280w, /_astro/your-env-file-is-a-secret-store.IcyLlBkj_ZPtJcM.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;tl;dr: Don’t use committed or shared &lt;code&gt;.env&lt;/code&gt; files as a secret store. Load secrets from a dedicated manager at startup. Merge multiple config sources in a single pass.&lt;/p&gt;
&lt;p&gt;Everything can look right on the surface. Let’s take a team that has AWS Secrets Manager set up, credentials rotated on a schedule, production access locked down.&lt;/p&gt;
&lt;p&gt;Application code fetched secrets from the manager at startup. They’d taken the security seriously.&lt;/p&gt;
&lt;p&gt;Then I looked at their &lt;code&gt;.env&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-dotenv&quot; data-language=&quot;dotenv&quot;&gt;&lt;code class=&quot;language-dotenv&quot;&gt;DATABASE_URL=postgres://user:pass@prod-db.internal/app&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application code fetched from AWS, but the &lt;code&gt;.env&lt;/code&gt; held a copy of the same credential: the value someone had pasted in months ago. The secret had rotated twice since. The &lt;code&gt;.env&lt;/code&gt; hadn’t.&lt;/p&gt;
&lt;p&gt;Two sources of truth. No connection between them.&lt;/p&gt;
&lt;h2 id=&quot;the-two-mistakes&quot;&gt;The two mistakes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Mistake one&lt;/strong&gt; is obvious: putting plaintext credentials directly into &lt;code&gt;.env&lt;/code&gt; files. Now everyone on the team effectively has the prod password. It appears in git blame. It gets pasted into Slack when someone shares their config for debugging. This mistake is well understood, and many teams have moved past it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake two&lt;/strong&gt; is less obvious. Teams set up a secret manager (AWS Secrets Manager, Vault, Doppler, 1Password Secrets) and write code to fetch secrets at startup. But nothing links the config system to the secret manager. Someone rotates a secret; the application still reads the old value. The rotation happened; the propagation didn’t.&lt;/p&gt;
&lt;p&gt;Both mistakes come from the same root cause: treating &lt;code&gt;.env&lt;/code&gt; as a configuration database instead of a local convenience.&lt;/p&gt;
&lt;h2 id=&quot;env-is-not-the-environment&quot;&gt;.env is not the environment&lt;/h2&gt;
&lt;p&gt;12-factor says config should come from environment variables injected at runtime. A &lt;code&gt;.env&lt;/code&gt; file is just a development convenience for populating those variables locally.&lt;/p&gt;
&lt;p&gt;It is not the environment itself. The execution environment (a container orchestrator, a cloud platform, a CI runner) can inject values from any number of backing stores.&lt;/p&gt;
&lt;p&gt;The natural extension: secrets should come from secret managers, not from &lt;code&gt;.env&lt;/code&gt; files. Non-secret config can come from &lt;code&gt;.env&lt;/code&gt;, process environment, CLI arguments, or anywhere else.&lt;/p&gt;
&lt;p&gt;Your application should know how to pull from multiple sources and merge them into a single, validated config object.&lt;/p&gt;
&lt;p&gt;This is what it looks like with a resolver-based approach. The pattern is implementable with any config system. The resolver approach shown here is one example:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; resolveAsync&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; processEnv &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; dotenv &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/resolvers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; awsSecrets &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver-aws&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; postgres&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-env-resolver/validators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Non-secret config from .env&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.env&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;LOG_LEVEL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;info&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Secrets from AWS, never touch .env&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;awsSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod/app&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each resolver is a named source. Later resolvers override earlier ones by default. Validators run on the merged result. Your application gets one typed config object and never needs to know where each value came from.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
    A[&quot;.env&quot;]:::config --&amp;gt; D[&quot;merge + validate&quot;]:::decision
    B[&quot;process.env&quot;]:::config --&amp;gt; D
    C[&quot;secrets manager&quot;]:::config --&amp;gt; D
    D --&amp;gt; E[&quot;config object&quot;]:::config

    classDef config fill:#e1f5ff
    classDef decision fill:#fff4e1
&lt;/pre&gt;
&lt;p&gt;The diagram shows three common sources, but any number can participate: SSM Parameter Store, Docker secrets, CLI arguments, custom databases. Each plugs into the same pipeline.&lt;/p&gt;
&lt;h2 id=&quot;local-development&quot;&gt;Local development&lt;/h2&gt;
&lt;p&gt;Running locally without access to a secret manager is the most common objection. The resolver model handles it naturally: swap the source, keep the schema.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Development: secrets from a gitignored .env.secrets&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Production: secrets from AWS&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isProd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.env&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  isProd
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;awsSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod/app&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.env.secrets&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.env.secrets&lt;/code&gt; file stays out of git. Developers populate it once with local test credentials. The schema and validation are identical. Only the source changes.&lt;/p&gt;
&lt;p&gt;If you prefer a single config without conditionals, use priority control. Normally later resolvers override earlier ones; &lt;code&gt;priority: &apos;first&apos;&lt;/code&gt; reverses that:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.env&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.env.secrets&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;awsSecrets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod/app&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postgres&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; priority&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;first&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Local .env.secrets wins if it exists&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In production, &lt;code&gt;.env.secrets&lt;/code&gt; doesn’t exist, so the resolver returns nothing and AWS provides the value.&lt;/p&gt;
&lt;h2 id=&quot;the-operational-payoff&quot;&gt;The operational payoff&lt;/h2&gt;
&lt;p&gt;The practical improvement, no more manual copy-paste after secret rotation, is real. But the bigger gain is structural.&lt;/p&gt;
&lt;p&gt;When config sources are explicit, the data flow is visible. You can see at a glance that &lt;code&gt;DATABASE_URL&lt;/code&gt; comes from a secrets manager and &lt;code&gt;PORT&lt;/code&gt; comes from the environment. You can audit which variables come from which providers. You can verify that production secrets don’t accidentally mix with staging config.&lt;/p&gt;
&lt;p&gt;Provenance becomes part of the code, not tribal knowledge.&lt;/p&gt;
&lt;p&gt;When something goes wrong, you know exactly where to look. Not “it might be the &lt;code&gt;.env&lt;/code&gt;, or it might be the startup script, or it might be the Kubernetes secret.” One resolver, one chain.&lt;/p&gt;
&lt;p&gt;For runtime secret rotation, resolvers fetch at startup by default. Most applications pick up rotated secrets on the next deploy or restart. For those that need live reload, wrapping a resolver in a short-TTL cache and calling resolve on each request works. It trades startup-time simplicity for per-request latency, so it is a deliberate choice rather than a free upgrade.&lt;/p&gt;
&lt;h2 id=&quot;a-concrete-example&quot;&gt;A concrete example&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://vercel.com/kb/bulletin/vercel-april-2026-security-incident&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vercel April 2026 security incident&lt;/a&gt; is a public instance of this failure mode. An attacker compromised a third-party AI tool, pivoted through a Vercel employee’s Google Workspace account, and read environment variables from Vercel projects that were not flagged as “sensitive.” API keys, tokens, and database credentials stored as plain env vars were exposed. Vercel’s guidance after the incident is to mark secrets as “sensitive” going forward, so they can’t be read back from the dashboard.&lt;/p&gt;
&lt;p&gt;That helps. A stronger mitigation is to not store the secret in the platform env layer at all. Keep a reference like &lt;code&gt;aws-sm://prod/stripe-key&lt;/code&gt; in Vercel, and let the secret manager hold the value with its own access controls and audit trail. An attacker reading the dashboard sees a URI, not a credential. The resolver dereferences it at startup.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  resolvers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processEnv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;STRIPE_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  references&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    handlers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;aws-sm&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; awsSecretHandler &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This shifts the blast radius. Compromise of the platform control plane now exposes which secrets a project uses and where they live, not their values.&lt;/p&gt;
&lt;h2 id=&quot;the-principle&quot;&gt;The principle&lt;/h2&gt;
&lt;p&gt;Most teams treat secret managers and configuration systems as separate concerns. One stores secrets; the other loads config. The problem is the gap between them: that’s where values get copied, drift, and go stale.&lt;/p&gt;
&lt;p&gt;Explicit config sources close that gap. They turn config loading into a single, typed pass that pulls from the right places, validates everything, and gives your application a clean config object.&lt;/p&gt;
&lt;p&gt;If your &lt;code&gt;.env&lt;/code&gt; file isn’t safe to read on a shared screen, it’s doing too much.&lt;/p&gt;
</content:encoded></item><item><title>Algebraic Thinking Without the Ceremony</title><link>https://arrangeactassert.com/posts/algebraic-thinking-without-the-ceremony/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/algebraic-thinking-without-the-ceremony/</guid><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Christian Ekrem’s post, &lt;a href=&quot;https://cekrem.github.io/posts/effect-without-effect-ts/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;em&gt;Effect Without Effect-TS: Algebraic Thinking in Plain TypeScript&lt;/em&gt;&lt;/a&gt;, shows something useful: typed errors, explicit dependencies, and composition do not require a framework.&lt;/p&gt;
&lt;p&gt;This post takes the same principles and shows where &lt;a href=&quot;https://jagreehal.github.io/awaitly/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;awaitly&lt;/a&gt; helps once the manual approach starts to repeat. The point is not “no ceremony.”&lt;/p&gt;
&lt;p&gt;The point is where ceremony lives.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;For most code, &lt;code&gt;run()&lt;/code&gt; is the starting point. &lt;code&gt;createWorkflow()&lt;/code&gt; is for orchestration features like retries, caching, observability, or managed dependency wiring.&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Raw async/await       Manual Result pattern      awaitly
──────────────────    ──────────────────────      ──────────────────────
Least setup           Most boilerplate            Moderate setup
Least honesty         Most explicit control       Lower repeated boilerplate
Errors invisible      Errors visible (expected)   Stronger guarantees
                      Unexpected errors: 🤷        Unexpected errors: typed&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-function-that-lies-to-you&quot;&gt;The function that lies to you&lt;/h2&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;signupUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Invalid email&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUserByEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Email already registered&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    passwordHash&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; emailService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;track&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user_signed_up&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Promise&amp;lt;User&amp;gt;&lt;/code&gt; looks honest, but it is not. The function can fail in several ways and depends on external systems. None of that is visible in the signature.&lt;/p&gt;
&lt;h2 id=&quot;idea-1-honest-errors&quot;&gt;Idea 1: Honest errors&lt;/h2&gt;
&lt;p&gt;Manual Result style works:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SignupError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _tag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;InvalidEmail&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _tag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EmailTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _tag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DbError&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; cause&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _tag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EmailServiceDown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Result&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is good engineering. You can share helpers and keep it clean. The maintenance cost appears when each module owns its own error union and every step change modifies that union.&lt;/p&gt;
&lt;h3 id=&quot;awaitly-equivalent&quot;&gt;Awaitly equivalent&lt;/h3&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validateEmail &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INVALID_EMAIL&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;INVALID_EMAIL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; checkDuplicate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EMAIL_TAKEN&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUserByEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;EMAIL_TAKEN&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The difference here is small but practical: an &lt;code&gt;AsyncResult&lt;/code&gt; alias, concise error codes, and &lt;code&gt;ok()&lt;/code&gt; handling void naturally.&lt;/p&gt;
&lt;h2 id=&quot;idea-2-honest-dependencies&quot;&gt;Idea 2: Honest dependencies&lt;/h2&gt;
&lt;p&gt;The dependency-in-signature pattern is excellent. &lt;code&gt;awaitly&lt;/code&gt; supports that same shape in two levels.&lt;/p&gt;
&lt;h3 id=&quot;shape-1-run--errorsof&quot;&gt;Shape 1: &lt;code&gt;run&lt;/code&gt; + &lt;code&gt;ErrorsOf&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Plain functions, with no framework registration:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorsOf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; run &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly/run&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validateEmail &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INVALID_EMAIL&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;isValidEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;INVALID_EMAIL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; findUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_ERROR&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUserByEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; checkNotTaken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EMAIL_TAKEN&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;EMAIL_TAKEN&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_ERROR&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sendWelcome &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;EMAIL_SERVICE_DOWN&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; emailService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  validateEmail&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  findUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  checkNotTaken&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  createUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sendWelcome&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SignupError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ErrorsOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SignupError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;validate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;find&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;checkNotTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNotTaken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; passwordHash&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;welcome&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also keep &lt;code&gt;fn(args, deps)&lt;/code&gt; exactly:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SignupDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SignupErrors&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ErrorsOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SignupDeps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;signupUser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SignupDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SignupErrors&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;validate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;find&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;checkNotTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkNotTaken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; passwordHash&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;welcome&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testability stays the same as manual style: inject fake deps directly.&lt;/p&gt;
&lt;h3 id=&quot;shape-2-createworkflow-for-when-you-need-more&quot;&gt;Shape 2: &lt;code&gt;createWorkflow&lt;/code&gt; for when you need more&lt;/h3&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createWorkflow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; signup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;signup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  validateEmail&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  findUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  checkNotTaken&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  createUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sendWelcome&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; signup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;validate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;find&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;checkNotTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkNotTaken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; passwordHash&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;password&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;welcome&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error union is inferred automatically from registered functions, with no separate &lt;code&gt;ErrorsOf&amp;lt;...&amp;gt;&lt;/code&gt; type needed. You also get step caching, retry/timeout config, and observability events.&lt;/p&gt;
&lt;p&gt;Workflows can also be statically analyzed with &lt;a href=&quot;https://jagreehal.github.io/awaitly/guides/static-analysis/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;awaitly-analyze&lt;/a&gt;, which lets you generate diagrams like this. The result is living documentation that makes onboarding and code reviews easier.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
  VE[&quot;validateEmail&quot;] --&amp;gt;|ok| FU[&quot;findUser&quot;]
  FU[&quot;findUser&quot;] --&amp;gt;|ok| CNT[&quot;checkNotTaken&quot;]
  CNT[&quot;checkNotTaken&quot;] --&amp;gt;|ok| CU[&quot;createUser&quot;]
  CU[&quot;createUser&quot;] --&amp;gt;|ok| SW[&quot;sendWelcome&quot;]
  SW[&quot;sendWelcome&quot;] --&amp;gt;|ok| Done((Success))
  VE --&amp;gt;|err| VEE[&quot;&apos;INVALID_EMAIL&apos;&quot;]
  FU --&amp;gt;|err| FUE[&quot;&apos;DB_ERROR&apos;&quot;]
  CNT --&amp;gt;|err| CNTE[&quot;&apos;EMAIL_TAKEN&apos;&quot;]
  CU --&amp;gt;|err| CUE[&quot;&apos;DB_ERROR&apos;&quot;]
  SW --&amp;gt;|err| SWE[&quot;&apos;EMAIL_SERVICE_DOWN&apos;&quot;]
&lt;/pre&gt;
&lt;h2 id=&quot;idea-3-composition&quot;&gt;Idea 3: Composition&lt;/h2&gt;
&lt;p&gt;Manual &lt;code&gt;andThen&lt;/code&gt; and early-return flows are valid and readable for small chains. As chains grow, composition noise grows too.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;validate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;find&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;checkNotTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNotTaken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; account &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;welcome&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;one-gap-manual-result-often-leaves-open&quot;&gt;One gap manual Result often leaves open&lt;/h2&gt;
&lt;p&gt;The manual approach models expected errors well. A common gap is unexpected throws from dependencies.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;validate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawEmail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;find&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;checkNotTaken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkNotTaken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Imagine createAccount throws internally&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; account &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// result.error:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;INVALID_EMAIL&quot; | &quot;EMAIL_TAKEN&quot; | &quot;DB_ERROR&quot; | UnexpectedError&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can still build this boundary manually (&lt;code&gt;runSafe&lt;/code&gt; wrapper). &lt;code&gt;awaitly&lt;/code&gt; includes it by default.&lt;/p&gt;
&lt;h3 id=&quot;steptry-for-throwing-apis&quot;&gt;&lt;code&gt;step.try()&lt;/code&gt; for throwing APIs&lt;/h3&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;parse&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rawInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;PARSE_FAILED&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;callSDK&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;thirdPartySDK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;onError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SDK_FAILED&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trade-off is one more concept (&lt;code&gt;step.try&lt;/code&gt;), in exchange for not re-writing try/catch-and-map code around every throwing dependency.&lt;/p&gt;
&lt;h2 id=&quot;scorecard&quot;&gt;Scorecard&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Raw async/await&lt;/th&gt;
&lt;th&gt;Manual Result&lt;/th&gt;
&lt;th&gt;awaitly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup cost&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Result&lt;/code&gt; type, &lt;code&gt;ok&lt;/code&gt;/&lt;code&gt;err&lt;/code&gt; helpers, &lt;code&gt;assertNever&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm install&lt;/code&gt;, learn &lt;code&gt;run&lt;/code&gt;/&lt;code&gt;step&lt;/code&gt;/&lt;code&gt;ErrorsOf&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-module cost&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Error union + early returns per call&lt;/td&gt;
&lt;td&gt;&lt;code&gt;step()&lt;/code&gt; calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error visibility&lt;/td&gt;
&lt;td&gt;None (catch unknown)&lt;/td&gt;
&lt;td&gt;Expected errors typed&lt;/td&gt;
&lt;td&gt;Expected + unexpected typed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error union maintenance&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Hand-maintained&lt;/td&gt;
&lt;td&gt;Inferred (&lt;code&gt;ErrorsOf&amp;lt;typeof deps&amp;gt;&lt;/code&gt; or &lt;code&gt;createWorkflow&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unexpected errors&lt;/td&gt;
&lt;td&gt;Uncaught rejections&lt;/td&gt;
&lt;td&gt;Usually uncaught unless you add safe boundary&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UnexpectedError&lt;/code&gt; in union&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composition at scale&lt;/td&gt;
&lt;td&gt;try/catch nesting&lt;/td&gt;
&lt;td&gt;&lt;code&gt;andThen&lt;/code&gt; nesting or early returns&lt;/td&gt;
&lt;td&gt;&lt;code&gt;step()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dep injection&lt;/td&gt;
&lt;td&gt;Module imports&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fn(deps, ...args)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; or &lt;code&gt;createWorkflow&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test story&lt;/td&gt;
&lt;td&gt;Often mocks/stubs&lt;/td&gt;
&lt;td&gt;Pass fake deps&lt;/td&gt;
&lt;td&gt;Pass fake deps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;The original post teaches the right principles and is honest about trade-offs. &lt;code&gt;awaitly&lt;/code&gt; is a lightweight extension on top: infer error unions with &lt;code&gt;ErrorsOf&lt;/code&gt;, reduce repeated early-exit checks with &lt;code&gt;step()&lt;/code&gt;, and include a default boundary for unexpected throws.&lt;/p&gt;
&lt;p&gt;The ideas are similar. The difference is where the ceremony lives: hand-written per module, or centralized behind a small execution boundary.&lt;/p&gt;
</content:encoded></item><item><title>The package manager settings that would have blocked the Axios attack</title><link>https://arrangeactassert.com/posts/the-package-manager-settings-that-would-have-blocked-the-axios-attack/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-package-manager-settings-that-would-have-blocked-the-axios-attack/</guid><pubDate>Tue, 07 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;On the 31st of March 2026, attackers hijacked an npm maintainer account and published malicious versions of &lt;code&gt;axios&lt;/code&gt; with a remote access trojan baked in. npm pulled the bad releases after about two or three hours, but that was enough. Anyone who ran &lt;code&gt;npm install axios&lt;/code&gt; during that window could have installed the trojan. The article &lt;a href=&quot;https://github.com/axios/axios/issues/10636&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Post Mortem: axios npm supply chain compromise&lt;/a&gt; has all the details.&lt;/p&gt;
&lt;p&gt;This kind of attack keeps happening and the playbook barely changes: compromise an account, push a malicious update, hope people install it before anyone notices, get removed a few hours later.&lt;/p&gt;
&lt;p&gt;Every major package manager now lets you defend against this. In this post I’ll show you the setup for npm, pnpm, Bun and Yarn.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-the-axios-attack-worked&quot;&gt;Why the Axios attack worked&lt;/h2&gt;
&lt;p&gt;The malicious versions were published as ordinary patch releases. If your project depended on &lt;code&gt;&quot;axios&quot;: &quot;^1.14.0&quot;&lt;/code&gt; and performed a fresh resolution without a lockfile pinning a safe version, install could resolve to the poisoned version automatically. And if the attacker included a &lt;code&gt;postinstall&lt;/code&gt; script, npm ran it during installation without asking.&lt;/p&gt;
&lt;p&gt;So one &lt;code&gt;npm install&lt;/code&gt; could download the compromised package, run arbitrary code on your machine or CI runner, and exfiltrate credentials, tokens, SSH keys, source code - whatever it wanted.&lt;/p&gt;
&lt;p&gt;The whole thing hinges on two assumptions: you install the bad version quickly, and npm runs the install script. The three settings break both.&lt;/p&gt;
&lt;h3 id=&quot;1-delay-new-releases&quot;&gt;1. Delay new releases&lt;/h3&gt;
&lt;pre class=&quot;language-ini&quot; data-language=&quot;ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token key attr-name&quot;&gt;min-release-age&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells npm to skip any version published in the last 7 days.&lt;/p&gt;
&lt;p&gt;Seven days sounds like a lot. But most malicious releases get caught within hours. The Axios compromise was live for roughly 2-3 hours. With this setting, npm would have refused to resolve those versions until they were a week old, by which point they’d already been yanked.&lt;/p&gt;
&lt;p&gt;Every major package manager has an equivalent, though the config key and units differ. npm calls this setting &lt;code&gt;min-release-age&lt;/code&gt; (in days); pnpm and Bun call it &lt;code&gt;minimumReleaseAge&lt;/code&gt; (minutes and seconds respectively); Yarn uses &lt;code&gt;npmMinimalAgeGate&lt;/code&gt; (human-readable durations).&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# pnpm-workspace.yaml (minutes, so 10080 = 7 days)&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;minimumReleaseAge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10080&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-toml&quot; data-language=&quot;toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# bunfig.toml (seconds, so 604800 = 7 days)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;minimumReleaseAge&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;604800&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .yarnrc.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;npmMinimalAgeGate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;7d&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-disable-install-scripts-globally&quot;&gt;2. Disable install scripts globally&lt;/h3&gt;
&lt;pre class=&quot;language-ini&quot; data-language=&quot;ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token key attr-name&quot;&gt;ignore-scripts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;npm packages can define lifecycle hooks (&lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;postinstall&lt;/code&gt;) and by default npm runs them automatically. Attackers exploit this because their code executes during installation. You don’t even need to import the package.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;ignore-scripts=true&lt;/code&gt;, npm downloads the package but refuses to run any install-time code. The install-time RAT payload described in the Axios compromise would not have executed during install.&lt;/p&gt;
&lt;h2 id=&quot;the-tradeoff&quot;&gt;The tradeoff&lt;/h2&gt;
&lt;p&gt;Some legitimate packages need install scripts, especially native modules: &lt;code&gt;sharp&lt;/code&gt;, &lt;code&gt;bcrypt&lt;/code&gt;, &lt;code&gt;sqlite3&lt;/code&gt;, &lt;code&gt;esbuild&lt;/code&gt;, &lt;code&gt;puppeteer&lt;/code&gt;. If something breaks, rebuild only the packages you trust:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; ci --ignore-scripts
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; rebuild sharp esbuild&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also override per project if you need to:&lt;/p&gt;
&lt;pre class=&quot;language-ini&quot; data-language=&quot;ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# project/.npmrc&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;ignore-scripts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-pin-exact-versions&quot;&gt;3. Pin exact versions&lt;/h3&gt;
&lt;pre class=&quot;language-ini&quot; data-language=&quot;ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token key attr-name&quot;&gt;save-exact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default npm saves dependencies with a caret (&lt;code&gt;^1.14.0&lt;/code&gt;), which means future patch and minor versions get pulled in automatically. That’s the convenience that made the Axios attack possible.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;save-exact=true&lt;/code&gt;, npm records &lt;code&gt;&quot;axios&quot;: &quot;1.14.0&quot;&lt;/code&gt;. No range, no floating. You still update dependencies, but through a PR or lockfile update. Not because someone pushed a release five minutes ago.&lt;/p&gt;
&lt;h2 id=&quot;setup-for-your-package-manager&quot;&gt;Setup for your package manager&lt;/h2&gt;
&lt;p&gt;Pick yours, copy the config, and you are done.&lt;/p&gt;
&lt;h3 id=&quot;npm&quot;&gt;npm&lt;/h3&gt;
&lt;p&gt;Requires npm v11.10.0 or later. To make sure your team is on a compatible version, add &lt;code&gt;engines&lt;/code&gt; to your &lt;code&gt;package.json&lt;/code&gt; and set &lt;code&gt;engine-strict=true&lt;/code&gt; in &lt;code&gt;.npmrc&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-ini&quot; data-language=&quot;ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ~/.npmrc (or project .npmrc)&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;ignore-scripts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;min-release-age&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;save-exact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;engine-strict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token value attr-value&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;pnpm&quot;&gt;pnpm&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;minimumReleaseAge&lt;/code&gt; uses minutes. 10080 = 7 days.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# pnpm-workspace.yaml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;minimumReleaseAge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10080&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;onlyBuiltDependencies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; sharp
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; esbuild&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pnpm can block arbitrary install scripts using &lt;code&gt;onlyBuiltDependencies&lt;/code&gt;. Once configured, only the listed packages may run build/install scripts. Without it, lifecycle scripts still run normally.&lt;/p&gt;
&lt;h3 id=&quot;bun&quot;&gt;Bun&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;minimumReleaseAge&lt;/code&gt; uses seconds. 604800 = 7 days. Bun is more restrictive by default: it does not run arbitrary dependency lifecycle scripts, uses a built-in allowlist for many common packages, and lets you allow additional ones with &lt;code&gt;trustedDependencies&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;. If you want to disable lifecycle scripts entirely, use &lt;code&gt;bun install --ignore-scripts&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot; data-language=&quot;toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# bunfig.toml&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;minimumReleaseAge&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;604800&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// package.json&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;trustedDependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sharp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;esbuild&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;yarn-current-releases&quot;&gt;Yarn (current releases)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npmMinimalAgeGate&lt;/code&gt; accepts human-readable durations. Disable scripts globally and allow them per package with &lt;code&gt;dependenciesMeta&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; data-language=&quot;yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .yarnrc.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;npmMinimalAgeGate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;7d&apos;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;enableScripts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;dependenciesMeta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;sharp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;built&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;esbuild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;built&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;lockfiles-and-ci&quot;&gt;Lockfiles and CI&lt;/h2&gt;
&lt;p&gt;Even with these settings, commit your lockfile. A committed &lt;code&gt;package-lock.json&lt;/code&gt; (or &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;, &lt;code&gt;bun.lock&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;) means CI gets the same dependency graph every time, fresh installs don’t resolve to something unexpected, and dependency updates show up in PRs where you can actually review them.&lt;/p&gt;
&lt;p&gt;In CI, always use the lockfile-only install command for your package manager:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; ci              &lt;span class=&quot;token comment&quot;&gt;# not npm install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --frozen-lockfile
bun &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --frozen-lockfile
&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--immutable&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt; in CI can silently update the lockfile and pull in new versions. &lt;code&gt;npm ci&lt;/code&gt; refuses to do that. The other managers behave the same way with their respective flags.&lt;/p&gt;
&lt;p&gt;Commit the lockfile. Review lockfile diffs. Update dependencies on purpose. Don’t let CI grab whatever happens to be newest.&lt;/p&gt;
&lt;h2 id=&quot;why-this-combination-works&quot;&gt;Why this combination works&lt;/h2&gt;
&lt;p&gt;The Axios attack needed three things to go right: the victim installs quickly, the dependency range floats to the bad version, and install scripts run automatically.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What the attacker needs&lt;/th&gt;
&lt;th&gt;What blocks it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install before the package is noticed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min-release-age=7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-upgrade to the newest release&lt;/td&gt;
&lt;td&gt;&lt;code&gt;save-exact=true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute malware during install&lt;/td&gt;
&lt;td&gt;Disable install scripts / allowlist trusted packages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most supply chain attacks follow the same pattern. These settings won’t stop everything, but they would have stopped this one, and they will probably stop the next few too.&lt;/p&gt;
&lt;h2 id=&quot;stay-safe-out-there&quot;&gt;Stay safe out there&lt;/h2&gt;
&lt;p&gt;Scroll up to the &lt;a href=&quot;#setup-for-your-package-manager&quot;&gt;Setup for your package manager&lt;/a&gt;, pick your package manager, and paste the config.&lt;/p&gt;
&lt;p&gt;Commit your lockfiles, use lockfile-only installs in CI, review dependency changes in PRs, and keep an allowlist for packages that genuinely need install scripts.&lt;/p&gt;
</content:encoded></item><item><title>Engineering decisions are bets, not proofs</title><link>https://arrangeactassert.com/posts/engineering-decisions-are-bets-not-proofs/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/engineering-decisions-are-bets-not-proofs/</guid><pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Most engineering decisions are not proofs.&lt;/p&gt;
&lt;p&gt;They are bets.&lt;/p&gt;
&lt;p&gt;You choose a direction with incomplete information, under time pressure, and with trade-offs you cannot fully test in advance.&lt;/p&gt;
&lt;p&gt;That does not make the decision weak.&lt;/p&gt;
&lt;p&gt;It makes it real.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Engineering decisions are bets, not proofs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2816px) 2816px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2816&quot; height=&quot;1536&quot; src=&quot;https://arrangeactassert.com/_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_1rtYjP.webp&quot; srcset=&quot;/_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_1s73qy.webp 640w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_Z2zcLq.webp 750w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_2uORRu.webp 828w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_1CdnLk.webp 1080w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_Z1dVhje.webp 1280w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_1NmNzM.webp 1668w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_Z1Tr45r.webp 2048w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_BCFVM.webp 2560w, /_astro/engineering-decisions-are-bets-not-proofs.DLYI0JAl_1rtYjP.webp 2816w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;https://arrangeactassert.com/posts/why-design-by-committee-leaves-engineering-change-unfinished/&quot;&gt;previous post&lt;/a&gt;, I wrote about how design by committee leaves engineering change unfinished. The deeper reason is simple: many organisations treat technical decisions as though they should be certain before the work begins. But most meaningful engineering decisions are not certainties. They are bets.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Annie Duke puts this well in &lt;a href=&quot;https://www.amazon.co.uk/Thinking-Bets-Making-Smarter-Decisions/dp/0735216355&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Thinking in Bets&lt;/a&gt;. Decision-making is more like poker than chess. In chess, everything is visible. In poker, you work with hidden information, incomplete knowledge, and luck. You can play the hand perfectly and still lose.&lt;/p&gt;
&lt;p&gt;Engineering decisions work the same way. You choose a direction based on what you know now, not what you will know in six months. The quality of a decision is not whether it later turned out to be right. It is whether it was a good bet given the information available at the time.&lt;/p&gt;
&lt;h2 id=&quot;the-outcome-trap&quot;&gt;The outcome trap&lt;/h2&gt;
&lt;p&gt;Teams often judge decisions by outcomes alone: good outcome, good decision; bad outcome, bad decision.&lt;/p&gt;
&lt;p&gt;But that is too simple. A good decision can have a bad outcome. A bad decision can get lucky.&lt;/p&gt;
&lt;p&gt;Norman Kerth put it well in his Prime Directive for retrospectives:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the team made a reasonable bet with the information they had, the fact that it did not work out does not mean the decision was wrong. It means the context changed, or something was unknowable.&lt;/p&gt;
&lt;p&gt;I have seen teams adopt a framework that later proved the wrong fit, and conclude that the decision-making process itself was broken. But when you looked back at the information they had at the time, the decision was reasonable. What changed was the context. New requirements appeared. The team’s needs shifted. The framework’s maintainer abandoned it.&lt;/p&gt;
&lt;p&gt;I have also seen teams make a questionable architectural choice that happened to work because the product never scaled past the point where the weakness mattered. That is not a good decision. That is luck.&lt;/p&gt;
&lt;p&gt;If you only evaluate decisions by results, you learn the wrong lessons. You punish reasonable bets that did not pay off and reward reckless ones that happened to land. The right response is to update the bet, not to blame the people who made it.&lt;/p&gt;
&lt;h2 id=&quot;what-good-bets-look-like-in-engineering&quot;&gt;What good bets look like in engineering&lt;/h2&gt;
&lt;h3 id=&quot;why-now&quot;&gt;Why now?&lt;/h3&gt;
&lt;p&gt;Not every decision needs to be made upfront. We once delayed a data model decision on purpose because the first integration was still unclear. Two weeks later, the integration taught us what mattered and the choice became obvious.&lt;/p&gt;
&lt;p&gt;When a decision does need to be made, there should be an honest answer to “why this, why now.”&lt;/p&gt;
&lt;h3 id=&quot;what-are-the-trade-offs&quot;&gt;What are the trade-offs?&lt;/h3&gt;
&lt;p&gt;The useful conversation is usually about what gets worse, not what gets better. You can feel it when someone says, “This speeds up deploys, but on-call gets harder for teams without strong Kubernetes skills.” That is a real trade-off.&lt;/p&gt;
&lt;h3 id=&quot;how-small-can-we-make-the-bet&quot;&gt;How small can we make the bet?&lt;/h3&gt;
&lt;p&gt;Instead of migrating the whole platform, move one service first. You learn more from the first awkward deployment than from three meetings about what might happen.&lt;/p&gt;
&lt;h3 id=&quot;how-will-we-test-it&quot;&gt;How will we test it?&lt;/h3&gt;
&lt;p&gt;If you are betting that Kubernetes will simplify deployment, the first migrated service should tell you whether that is true. If you are betting on event-driven architecture, the first event contract usually exposes the integration pain you were hand-waving in diagrams.&lt;/p&gt;
&lt;h3 id=&quot;what-would-make-us-change-our-mind&quot;&gt;What would make us change our mind?&lt;/h3&gt;
&lt;p&gt;This is where teams fool themselves. The useful question is, “What result would make us stop and rethink?” A short ADR helps when it captures what we believed and what would trigger a change, not when it tries to predict every edge case.&lt;/p&gt;
&lt;h3 id=&quot;is-it-reversible&quot;&gt;Is it reversible?&lt;/h3&gt;
&lt;p&gt;Not every decision can be reversed cheaply, but reversible bets should move with less ceremony. If a choice can be rolled back in a day, decide quickly and learn. If it locks you into years of tooling and contracts, slow down and pressure-test it harder.&lt;/p&gt;
&lt;p&gt;Some teams formalise this by constraining time and scope. Basecamp’s Shape Up process, for example, treats projects as bounded bets: decide how much time something is worth, shape the work to fit, and if it does not ship within six weeks it does not automatically get more time. The principle is simple. Smaller bets create faster learning.&lt;/p&gt;
&lt;h2 id=&quot;the-learning-loop&quot;&gt;The learning loop&lt;/h2&gt;
&lt;p&gt;At University Press, when we migrated services onto a new platform, we treated each service as a bet. We expected some assumptions to be wrong. The point was not to be right the first time. It was to make being wrong early cheap.&lt;/p&gt;
&lt;p&gt;One team discovered that their networking assumptions were off. Another found that the deployment configuration needed to be more flexible than anyone had anticipated. Those were not failures. That was the loop working.&lt;/p&gt;
&lt;p&gt;That is the learning loop: make the decision, observe what happened, separate what was skill from what was luck, and update your beliefs.&lt;/p&gt;
&lt;p&gt;Most teams skip the middle step. They see a result and jump to “we were right” or “we were wrong” without asking how much came from the decision itself versus circumstances outside their control.&lt;/p&gt;
&lt;p&gt;The lesson should not be “we should have known.” It should be “we learned, and now we update.”&lt;/p&gt;
&lt;h2 id=&quot;two-heads-are-better-than-one-but-not-twenty&quot;&gt;Two heads are better than one, but not twenty&lt;/h2&gt;
&lt;p&gt;Getting a second perspective helps you spot blind spots, challenge assumptions, and test whether your reasoning holds up. Duke calls this the “buddy system” and I think she is right about it.&lt;/p&gt;
&lt;p&gt;Two or three people pressure-testing a decision is valuable. But there is a threshold where adding more people stops improving the decision and starts slowing it down. That threshold is lower than most organisations think.&lt;/p&gt;
&lt;p&gt;The best engineering decisions I have been part of involved a small group who understood the problem, had the relevant context, and were willing to disagree with each other. The worst involved large groups where nobody had enough context to push back meaningfully, so the discussion became about politics and risk aversion rather than trade-offs and evidence.&lt;/p&gt;
&lt;p&gt;This is the same dynamic that turns ADRs into bureaucracy. The instinct is to involve more people to reduce risk. But past a certain point, involvement does not reduce risk. It diffuses ownership.&lt;/p&gt;
&lt;h2 id=&quot;pre-mortem-and-backcasting&quot;&gt;Pre-mortem and backcasting&lt;/h2&gt;
&lt;p&gt;In her book there are two techniques Duke discusses.&lt;/p&gt;
&lt;p&gt;A pre-mortem starts with a simple question: imagine this decision failed. Why? This forces the team to think about risks they might otherwise dismiss because they are optimistic about the outcome. It is not about pessimism. It is about preparation.&lt;/p&gt;
&lt;p&gt;Backcasting asks the opposite: imagine this decision succeeded. What did we do to get there? This helps identify the steps that actually matter and separates them from the busywork that feels productive but does not move the needle.&lt;/p&gt;
&lt;p&gt;Both work backwards from reality rather than forwards from assumptions. They are also quick. A fifteen-minute pre-mortem before a significant decision is worth more than a two-hour planning meeting that tries to account for every scenario.&lt;/p&gt;
&lt;h2 id=&quot;adrs-as-bet-records&quot;&gt;ADRs as bet records&lt;/h2&gt;
&lt;p&gt;If you think of decisions as bets, ADRs become something different. They are not proof that the team thought carefully. They are a record of the bet.&lt;/p&gt;
&lt;p&gt;What did we believe at the time? What information did we have? What were the alternatives? What trade-offs did we accept? What confidence level did we have? And what would cause us to revisit this?&lt;/p&gt;
&lt;p&gt;That is a useful document. It helps future teams understand not just what was decided, but the state of knowledge at the time. It makes it easier to judge whether the decision should be revisited because the context has changed, or whether the original reasoning still holds.&lt;/p&gt;
&lt;p&gt;The key is brevity. A bet record should be short because the bet itself should be bounded. If the ADR is long, the decision is probably too big.&lt;/p&gt;
&lt;h2 id=&quot;show-dont-tell&quot;&gt;Show, don’t tell&lt;/h2&gt;
&lt;p&gt;The best teams I have seen do not close a migration plan and declare certainty. They move one service, hit a rough edge, update the record, then move the second service with better knowledge.&lt;/p&gt;
&lt;p&gt;You can watch the behaviour: an assumption breaks, the team rewrites the ADR while the details are fresh, guardrails get sharper, and the next team starts from a better place than the one before.&lt;/p&gt;
&lt;p&gt;That is what good decision-making looks like in engineering. Not proving the future on paper, but learning faster than the uncertainty in front of you.&lt;/p&gt;
</content:encoded></item><item><title>Why design by committee leaves engineering change unfinished</title><link>https://arrangeactassert.com/posts/why-design-by-committee-leaves-engineering-change-unfinished/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/why-design-by-committee-leaves-engineering-change-unfinished/</guid><pubDate>Sun, 05 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Engineering change often gets stuck for the same reason: design by committee. Not because anyone has bad intentions, but because the pursuit of alignment quietly replaces the pursuit of learning.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Why design by committee leaves engineering change unfinished&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_ZdA29g.webp&quot; srcset=&quot;/_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_ZBi8B1.webp 640w, /_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_Z2bcpRW.webp 750w, /_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_Z1m7Xa9.webp 828w, /_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_Z1SRQE4.webp 1080w, /_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_Z2ffQkf.webp 1280w, /_astro/why-design-by-committee-leaves-engineering-change-unfinished.BKMGL0kv_ZdA29g.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;p&gt;It usually starts with good intentions. People want alignment, consistency, and lower risk. So a proposed change gets pulled into more meetings, more reviews, more stakeholders. Before long, the goal is no longer to try something, learn from it, and improve it. The goal becomes finding one perfect solution for every team.&lt;/p&gt;
&lt;p&gt;That is usually where momentum dies.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Because in real organisations, there is rarely one perfect solution. Teams carry different risks and constraints, and those differences show up the moment delivery starts.&lt;/p&gt;
&lt;p&gt;I have watched plans look complete in review and come apart in week one because one service had awkward networking, another had brittle deployment scripts, and a third had compliance constraints nobody raised in the room.&lt;/p&gt;
&lt;p&gt;That is not failure. That is normal.&lt;/p&gt;
&lt;p&gt;The failure is building a process that treats learning as a problem instead of the whole point.&lt;/p&gt;
&lt;h2 id=&quot;the-biggest-risk-is-not-just-slowness&quot;&gt;The biggest risk is not just slowness&lt;/h2&gt;
&lt;p&gt;When change is driven by committee, the biggest problem is often not speed. It is that it never really finishes.&lt;/p&gt;
&lt;p&gt;Instead of delivering something small and useful, organisations create another half-complete initiative stranded in no man’s land. The old way has already been disrupted. The new way is not fully in place. The documentation no longer matches reality. Teams are unclear on what they are supposed to follow. And the organisation is carrying the cost of both the old world and the new one without getting the full benefit of either.&lt;/p&gt;
&lt;p&gt;That is how things get worse, not better.&lt;/p&gt;
&lt;p&gt;You end up with yet another initiative that started with a grand ambition and ended with confusion and drift. Nobody can clearly say it succeeded, but everyone has to live with the mess it left behind.&lt;/p&gt;
&lt;p&gt;To me, that is one of the strongest arguments against trying to solve too much upfront.&lt;/p&gt;
&lt;p&gt;If you make the scope too broad and the coordination too heavy, you massively increase the chance that nothing lands cleanly. You do not just delay progress. You create unfinished change.&lt;/p&gt;
&lt;p&gt;And unfinished change is expensive.&lt;/p&gt;
&lt;h2 id=&quot;the-silver-bullet-mindset&quot;&gt;The silver bullet mindset&lt;/h2&gt;
&lt;p&gt;There is a belief that enough meetings and smart people in a room can design the final answer upfront. It sounds responsible. It often produces the opposite of progress.&lt;/p&gt;
&lt;p&gt;A new platform, architecture, or engineering practice cannot be discussed into existence. The assumptions that look sensible in a slide deck are not the same ones that survive contact with a real codebase, a real deployment pipeline, or a real team under pressure.&lt;/p&gt;
&lt;p&gt;That is why I keep coming back to a simple pattern:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make it work. Make it good. Make it fast.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In that order.&lt;/p&gt;
&lt;p&gt;Too many organisations invert that. They try to make it perfect before they have made it real.&lt;/p&gt;
&lt;h2 id=&quot;adrs-are-not-the-problem&quot;&gt;ADRs are not the problem&lt;/h2&gt;
&lt;p&gt;I am not against ADRs. Martin Fowler’s description of what they should be is close to what I actually want. Short. A page, maybe two. One decision per record. The context that led to it, the alternatives considered, the trade-offs, the consequences. Immutable once accepted. If the thinking changes, you write a new record that supersedes the old one.&lt;/p&gt;
&lt;p&gt;Fowler also makes a point I think is underappreciated: the act of writing an ADR is often more valuable than the record itself. Writing a document of consequence forces you to say what you actually believe and why. In a group, that surfaces disagreements that might otherwise stay hidden until implementation. That clarifying effect is the real value.&lt;/p&gt;
&lt;p&gt;If every team used ADRs the way Fowler describes, I would have nothing to write about. But they do not. My problem with ADRs has never been the format. It is what happens to them in practice.&lt;/p&gt;
&lt;p&gt;Michael Nygard &lt;a href=&quot;https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;coined the term in 2011&lt;/a&gt;. His argument was simple: large documents are never kept up to date, nobody reads them, and without understanding the rationale behind a decision people either blindly accept it or blindly change it. Both are bad. His solution was a short text file, one or two pages, written as a conversation with a future developer. Context, decision, consequences. That is it.&lt;/p&gt;
&lt;p&gt;Fifteen years on, teams still get this wrong in the same ways.&lt;/p&gt;
&lt;p&gt;The failure modes are well documented by people like Zimmermann, Keeling, and others. Reviewing wording instead of decision quality. Skipping alternatives. Reopening accepted records instead of superseding them. ADRs becoming architecture bureaucracy. Records written long after the decision was forgotten, or written up after the fact to justify a choice already made in a hallway conversation.&lt;/p&gt;
&lt;p&gt;I have seen most of these in person. ADRs that try to be mini design documents. ADRs so short they record the decision but not the reasoning. Records created after implementation rather than before. Documentation theatre, where the ADR exists to satisfy a process rather than support a decision.&lt;/p&gt;
&lt;p&gt;ADRs absorb the habits of the organisation using them. When a company falls into design by committee, ADRs become one of the places that habit shows up. Instead of recording a decision, they become a vehicle for trying to eliminate uncertainty upfront. They stop being a note of what we believe now and start becoming an attempt to define the whole future before the work begins.&lt;/p&gt;
&lt;p&gt;That is when they start to behave like waterfall.&lt;/p&gt;
&lt;p&gt;A bloated ADR tries to solve the needs of many teams, in many contexts, all at once. It leaves little room to say, “This is our current bet, but what we learn in step one may change step three.” It starts sounding less like a decision record and more like a contract with a future nobody fully understands yet.&lt;/p&gt;
&lt;p&gt;A good record should follow the inverted pyramid: the decision and rationale first, details later. It should say what we think, why we think it, what constraints matter, and what we expect to learn. If there is supporting material, link to it. And when reality gives us better information, we write a new record that supersedes the old one. That way there is a clear log of decisions and how long each one governed the work.&lt;/p&gt;
&lt;p&gt;I am not arguing against ADRs, and I am not arguing for chaos. Written decisions can be useful. The problem starts when teams treat them as a way to discover the final answer before they have learned enough to know it. In practice, meaningful engineering change is iterative. You make a sensible bet, try it in a real context, learn from the result, and refine the decision. The real question is not whether you wrote an ADR. It is whether the process helped you move, learn, and adapt.&lt;/p&gt;
&lt;h2 id=&quot;two-migrations-two-approaches&quot;&gt;Two migrations, two approaches&lt;/h2&gt;
&lt;p&gt;I have seen both sides of this.&lt;/p&gt;
&lt;p&gt;At a previous company, the leader announced to the entire organisation that everything would be on Kubernetes within three months. The decision had the confidence and theatre of certainty, but not the evidence. I remember sketching the iceberg model to show how much of the real implementation work was still hidden beneath the surface. The three-month target was not a plan. It was a guess dressed up as a commitment.&lt;/p&gt;
&lt;p&gt;Unsurprisingly, we missed the target. A follow-up message had to explain that it had not happened. You cannot commit to a deadline for something you do not yet understand.&lt;/p&gt;
&lt;p&gt;At University Press, we approached a similar migration very differently. We moved services onto Kubernetes across multiple teams. We did not rely on formal ADRs or a large upfront design exercise. Instead, teams stayed aligned through regular cross-team conversations, a shared direction of travel, and a leaner implementation approach. We did just enough to move forward, learned from the work, and adapted based on reality.&lt;/p&gt;
&lt;p&gt;I have &lt;a href=&quot;https://arrangeactassert.com/posts/before-you-change-the-process-understand-the-problem/&quot;&gt;written before about the importance of understanding the problem before changing the process&lt;/a&gt;. That is what we did here.&lt;/p&gt;
&lt;p&gt;We started with one service. That gave us real information very quickly. We learned what deployment actually needed, what configuration mattered, what the rough edges were, and what flexibility teams would need in practice. From there, the ops people could define sensible constraints without pretending they should dictate every implementation detail for every team.&lt;/p&gt;
&lt;p&gt;That effort succeeded not because we had the perfect document, but because we created the conditions to learn. One was decree first, learning later. The other was vision first, learning through execution.&lt;/p&gt;
&lt;p&gt;Large-scale engineering change always contains unknown unknowns. Some things can be reasoned about upfront. Others only reveal themselves in delivery. That is why the goal should not be to eliminate uncertainty on paper, but to reduce it through small moves, fast feedback, and real learning.&lt;/p&gt;
&lt;h2 id=&quot;one-pattern-does-not-mean-one-identical-solution&quot;&gt;One pattern does not mean one identical solution&lt;/h2&gt;
&lt;p&gt;Success does not mean every team ends up using the exact same solution in the exact same way. In fact, that is often a sign the standard is too rigid. A service with complex networking needs is not the same as a simpler internal application. A mature team with strong operational habits is not in the same place as a team still dealing with legacy systems. If you force both into the same implementation, one of them will carry unnecessary pain.&lt;/p&gt;
&lt;p&gt;So the goal should not be to impose one identical answer for everybody.&lt;/p&gt;
&lt;p&gt;The goal should be to define the lines clearly enough that teams can colour within them, while still having the agency to choose what works best for their own problem.&lt;/p&gt;
&lt;p&gt;That is not a failure of standardisation. It is a smarter form of it.&lt;/p&gt;
&lt;p&gt;The platform team might define the shape of the contract: security expectations, deployment structure, required interfaces, observability standards, the mechanism by which a service is discovered and deployed. But within those boundaries, teams should have room to decide what makes sense for their service’s lifecycle, networking needs, runtime, and operational realities.&lt;/p&gt;
&lt;p&gt;For example, if an organisation adopts event driven architecture, it may matter that events follow the same naming conventions, versioning rules, and schema standards. It may matter that teams agree what guarantees exist around ordering, retries, and idempotency. But it does not necessarily matter whether one team uses Kafka and another uses RabbitMQ, if both satisfy the same contract.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good standards define the boundaries that let teams work together. Bad standards try to make every team solve the problem in exactly the same way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You want consistency where consistency is valuable, and flexibility where flexibility is necessary.&lt;/p&gt;
&lt;h2 id=&quot;how-you-drive-change-determines-what-kind-of-team-you-get&quot;&gt;How you drive change determines what kind of team you get&lt;/h2&gt;
&lt;p&gt;When change is imposed through a committee mandate and a rigid document, you can see disengagement quickly. Teams attend the meeting, stop challenging assumptions, wait for the approved pattern, and implement the minimum needed to satisfy the document. The awkward edge cases sit unowned because nobody feels accountable for improving the model itself.&lt;/p&gt;
&lt;p&gt;When change is driven by people who go first and learn in public, behaviour changes. One team solves secrets management first. Another finds the networking issues. Another improves the deployment path. Those lessons feed back into shared guidance so the next team starts with fewer mistakes.&lt;/p&gt;
&lt;p&gt;That is how organisations learn well. Not through one giant design produced centrally, but through smaller experiments feeding better knowledge back into the system.&lt;/p&gt;
&lt;h2 id=&quot;stop-confusing-alignment-with-progress&quot;&gt;Stop confusing alignment with progress&lt;/h2&gt;
&lt;p&gt;One reason design by committee is so seductive is that it looks productive.&lt;/p&gt;
&lt;p&gt;There are meetings, diagrams, approvals, and a polished document. It feels like progress because everyone is busy.&lt;/p&gt;
&lt;p&gt;Then the mess shows up. The old approach is half-deprecated. The new one is half-adopted. Documentation contradicts what teams are actually doing. Different teams believe they are compliant while making different trade-offs. The committee keeps meeting because nobody wants to say the grand plan never fully landed.&lt;/p&gt;
&lt;p&gt;Activity is not the same as learning, and it is not the same as delivery.&lt;/p&gt;
&lt;p&gt;A finished small success is worth more than a grand cross-team programme that drifts into another unfinished initiative. One leaves you with evidence and something to build on. The other leaves you with partial adoption, confused teams, and stale documentation.&lt;/p&gt;
&lt;h2 id=&quot;my-view&quot;&gt;My view&lt;/h2&gt;
&lt;p&gt;As usual, the answer is balance. Doing nothing is one extreme. Decisions live in people’s heads, get forgotten, and get relitigated six months later. That is how organisations lose institutional memory. Trying to design the final, absolute answer upfront is the other extreme. That is how organisations lose momentum.&lt;/p&gt;
&lt;p&gt;Engineering change is not a finite problem you can solve on paper. It is an ongoing process of making bets, learning from them, and adjusting. Good organisations build that learning into the way they make decisions, not around it. The goal is not to be certain upfront. It is to make the best bet you can with the information you have, then update quickly as reality gives you better information. I wrote more about this in &lt;a href=&quot;https://arrangeactassert.com/posts/engineering-decisions-are-bets-not-proofs/&quot;&gt;Engineering decisions are bets, not proofs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ADRs are a tool. A good one, when used well. But no document can substitute for actually doing the work and learning from it.&lt;/p&gt;
&lt;p&gt;I am not anti-ADR. I am anti-pretending that a document can replace learning. In engineering change, you usually understand more by getting something real into motion than by trying to agree the whole future in advance.&lt;/p&gt;
&lt;p&gt;Start small.
Make a bet.
Try it in practice.
Give teams guardrails, not handcuffs.
Let them learn what works for their own context.
Finish something real.
Then spread what you learned.&lt;/p&gt;
&lt;p&gt;That is how change becomes real.&lt;/p&gt;
&lt;p&gt;Make it work.
Make it good.
Make it fast.&lt;/p&gt;
</content:encoded></item><item><title>fn(args, deps) Is Not Anti-Mock</title><link>https://arrangeactassert.com/posts/fn-args-deps-is-not-anti-mock/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-is-not-anti-mock/</guid><pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;People hear “don’t use &lt;code&gt;vi.mock&lt;/code&gt;” and assume the alternative is “don’t mock anything.” That is not the argument.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;fn(args, deps) is not anti-mock&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 832px) 832px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;832&quot; height=&quot;1248&quot; src=&quot;https://arrangeactassert.com/_astro/fn-args-deps-is-not-anti-mock.BS_lkN15_ZsWlYJ.webp&quot; srcset=&quot;/_astro/fn-args-deps-is-not-anti-mock.BS_lkN15_1j6Ldn.webp 640w, /_astro/fn-args-deps-is-not-anti-mock.BS_lkN15_Z24Typ3.webp 750w, /_astro/fn-args-deps-is-not-anti-mock.BS_lkN15_Z1K27KV.webp 828w, /_astro/fn-args-deps-is-not-anti-mock.BS_lkN15_ZsWlYJ.webp 832w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The real distinction is simpler: mock explicit collaborators, not implicit imports.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;The &lt;a href=&quot;https://arrangeactassert.com/posts/to-mock-or-not/&quot;&gt;earlier post&lt;/a&gt; argued that &lt;code&gt;vi.mock&lt;/code&gt; tends to couple tests to module wiring, while dependency injection tends to couple tests to the contract your code actually depends on.&lt;/p&gt;
&lt;p&gt;That remains true.&lt;/p&gt;
&lt;p&gt;But it leaves a follow-up question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the function already follows &lt;code&gt;fn(args, deps)&lt;/code&gt;, what should the test use for &lt;code&gt;deps&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The answer is simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for unit tests, pass a fake &lt;code&gt;deps&lt;/code&gt; object&lt;/li&gt;
&lt;li&gt;if you want the nicest ergonomics, generate that object with &lt;code&gt;vitest-mock-extended&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;reserve &lt;code&gt;vi.mock&lt;/code&gt; for the cases where you truly cannot inject the dependency cleanly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is not a different philosophy. It is the same one, applied consistently. The &lt;code&gt;fn(args, deps)&lt;/code&gt; pattern makes dependencies explicit, local, and easy to substitute in tests. Tests should pass &lt;code&gt;deps&lt;/code&gt; as data, not intercept the module system with global shared state.&lt;/p&gt;
&lt;h2 id=&quot;the-misunderstanding&quot;&gt;The misunderstanding&lt;/h2&gt;
&lt;p&gt;Here is the mistaken mental model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vi.mock&lt;/code&gt; = mocking&lt;/li&gt;
&lt;li&gt;dependency injection = no mocking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the wrong split.&lt;/p&gt;
&lt;p&gt;The real split is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;module mocking&lt;/strong&gt;: replacing what code imports&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dependency mocking&lt;/strong&gt;: passing in a fake implementation of what the function declares it needs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those are not the same thing.&lt;/p&gt;
&lt;p&gt;The first changes module resolution. The second passes a different argument.&lt;/p&gt;
&lt;p&gt;That is why &lt;code&gt;fn(args, deps)&lt;/code&gt; fits so naturally with test doubles. The pattern already separates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what varies per call: &lt;code&gt;args&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;what the function needs from the outside world: &lt;code&gt;deps&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That separation is the boundary. The test just supplies a different &lt;code&gt;deps&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-default-many-teams-reach-for&quot;&gt;The default many teams reach for&lt;/h2&gt;
&lt;p&gt;Take a simple use case:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; saveUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./db&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sendWelcomeEmail &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./mailer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To unit test this, the usual move is:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./db&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  saveUser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./mailer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  sendWelcomeEmail&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That works.&lt;/p&gt;
&lt;p&gt;It also couples the test to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the file paths&lt;/li&gt;
&lt;li&gt;the export names&lt;/li&gt;
&lt;li&gt;Vitest’s hoisting rules&lt;/li&gt;
&lt;li&gt;global mock state that has to be managed between tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the architecture critique behind the anti-&lt;code&gt;vi.mock&lt;/code&gt; argument: the test is asserting on module wiring, not just behavior. &lt;code&gt;vi.mock&lt;/code&gt; relies on global shared state, while &lt;code&gt;fn(args, deps)&lt;/code&gt; uses direct injection and each test owns its own dependencies.&lt;/p&gt;
&lt;h2 id=&quot;the-shape-we-actually-want&quot;&gt;The shape we actually want&lt;/h2&gt;
&lt;p&gt;Now look at the same use case with explicit dependencies:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the unit test has no reason to touch &lt;code&gt;vi.mock&lt;/code&gt; at all:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vi &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./createUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;createUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;creates a user and sends welcome email&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; save&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sendWelcome&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sendWelcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No hoisting. No path coupling. No module interception. The mock is just an object. The function signature makes the seam explicit, and the test uses it. That is exactly the testing story &lt;code&gt;fn(args, deps)&lt;/code&gt; is designed to support.&lt;/p&gt;
&lt;h2 id=&quot;where-vitest-mock-extended-fits&quot;&gt;Where vitest-mock-extended fits&lt;/h2&gt;
&lt;p&gt;The obvious objection is ergonomic.&lt;/p&gt;
&lt;p&gt;Manually writing fake dependency objects is fine at first. But once the dependency surface gets slightly deeper, hand-writing every nested &lt;code&gt;vi.fn()&lt;/code&gt; becomes repetitive.&lt;/p&gt;
&lt;p&gt;That is where &lt;code&gt;vitest-mock-extended&lt;/code&gt; earns its keep.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mock &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest-mock-extended&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./createUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;createUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;creates a user and sends welcome email&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockUser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CreateUserDeps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;save&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sendWelcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is not a compromise with the pattern. It is the pattern with better tooling. &lt;code&gt;mock&amp;lt;CreateUserDeps&amp;gt;()&lt;/code&gt; produces an object with the right methods, backed by &lt;code&gt;vi.fn()&lt;/code&gt;, while TypeScript enforces the shape. If a dep method gets renamed, the test fails to compile instead of drifting into runtime surprises.&lt;/p&gt;
&lt;h2 id=&quot;why-this-is-different-from-vimock&quot;&gt;Why this is different from vi.mock&lt;/h2&gt;
&lt;p&gt;Both approaches use the word “mock,” but the mechanics are very different.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;vi.mock&lt;/code&gt;, the test reaches out into the runtime and says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;when code imports this module, secretly replace it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With &lt;code&gt;mock&amp;lt;CreateUserDeps&amp;gt;()&lt;/code&gt;, the test says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;here is the deps object this function asked for&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One relies on indirection. The other relies on explicitness.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;fn(args, deps)&lt;/code&gt; is not primarily a testing pattern. It is an architectural boundary. The same shape that makes unit tests simple also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;keeps business logic independent from infrastructure&lt;/li&gt;
&lt;li&gt;maps cleanly onto &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;ports and adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;makes &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition roots&lt;/a&gt; straightforward&lt;/li&gt;
&lt;li&gt;makes abstractions &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-composition/&quot;&gt;cheap to extract and cheap to undo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is why the pattern shows up repeatedly across the other posts in this series. In the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;hexagonal architecture piece&lt;/a&gt;, the function signature itself becomes the boundary between the application core and external capabilities. In the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-composition/&quot;&gt;composition piece&lt;/a&gt;, growing deps signal when a responsibility has stabilized into its own function. In the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-bringing-order-to-chaos-without-breaking-anything/&quot;&gt;legacy code piece&lt;/a&gt;, &lt;code&gt;fn(args, deps = defaultDeps)&lt;/code&gt; becomes the seam that lets you migrate safely without breaking callers.&lt;/p&gt;
&lt;p&gt;Testing is just where the benefits become obvious first.&lt;/p&gt;
&lt;h2 id=&quot;a-rule-of-thumb&quot;&gt;A rule of thumb&lt;/h2&gt;
&lt;p&gt;Here is the rule I would actually give a team:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mock explicit collaborators, not implicit imports.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if your function takes &lt;code&gt;deps&lt;/code&gt;, mock &lt;code&gt;deps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if the deps object is annoying to hand-write, use &lt;code&gt;vitest-mock-extended&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;if the code under test imports a third-party module directly and you cannot introduce a seam yet, use &lt;code&gt;vi.mock&lt;/code&gt; pragmatically&lt;/li&gt;
&lt;li&gt;if you own the business logic, prefer explicit injection over module interception&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That rule preserves the core distinction.&lt;/p&gt;
&lt;p&gt;It says “yes” to mocks as test doubles.&lt;/p&gt;
&lt;p&gt;It says “no by default” to mocking the module system.&lt;/p&gt;
&lt;h2 id=&quot;a-worked-example-repository--mailer&quot;&gt;A worked example: repository + mailer&lt;/h2&gt;
&lt;p&gt;Here is the full progression.&lt;/p&gt;
&lt;h3 id=&quot;hidden-imports&quot;&gt;Hidden imports&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./db&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./mailer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inviteUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendInvite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;module-mocked-test&quot;&gt;Module-mocked test&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./db&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    users&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      insert&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./mailer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    sendInvite&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;explicit-deps&quot;&gt;Explicit deps&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InviteUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InviteUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    users&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;sendInvite&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inviteUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; InviteUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; InviteUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendInvite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;typed-test-with-vitest-mock-extended&quot;&gt;Typed test with vitest-mock-extended&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mock &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest-mock-extended&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inviteUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InviteUserDeps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./inviteUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;inviteUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;creates a user and sends an invite&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;u1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;InviteUserDeps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;insert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inviteUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sendInvite&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the pattern at its cleanest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;app code wires real deps at the boundary&lt;/li&gt;
&lt;li&gt;test code passes fake deps directly&lt;/li&gt;
&lt;li&gt;no module interception needed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-about-partial-application&quot;&gt;What about partial application?&lt;/h2&gt;
&lt;p&gt;One concern people have is call-site noise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do I really have to pass deps through every call?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;The core implementation stays:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But at the boundary you can bind deps once and expose a clean function to the rest of the app:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bindDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Out&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; Out&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So application code can use:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inviteUserWithDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bindDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inviteUser&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;realDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inviteUserWithDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While tests still hit the core function directly:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inviteUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;InviteUserDeps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That preserves the explicit core while keeping wiring ergonomic at the composition boundary. Implement in the explicit &lt;code&gt;fn(args, deps)&lt;/code&gt; form, then partially apply deps where it improves ergonomics.&lt;/p&gt;
&lt;h2 id=&quot;when-vimock-is-still-the-right-tool&quot;&gt;When vi.mock is still the right tool&lt;/h2&gt;
&lt;p&gt;None of this means &lt;code&gt;vi.mock&lt;/code&gt; is forbidden.&lt;/p&gt;
&lt;p&gt;There are still legitimate uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;third-party libraries that call globals internally&lt;/li&gt;
&lt;li&gt;platform APIs in code you do not control&lt;/li&gt;
&lt;li&gt;legacy modules where introducing a seam is not yet practical&lt;/li&gt;
&lt;li&gt;migration steps where &lt;code&gt;defaultDeps&lt;/code&gt; or wrappers are still being introduced&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Defaults are acceptable as a &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-bringing-order-to-chaos-without-breaking-anything/&quot;&gt;strangler-fig migration seam&lt;/a&gt;, and &lt;code&gt;vi.mock&lt;/code&gt; still has legitimate uses when the dependency is truly external or not yet injectable.&lt;/p&gt;
&lt;p&gt;The problem is not mocking as such.&lt;/p&gt;
&lt;p&gt;The problem is using module mocking as the default testing architecture for business code you control.&lt;/p&gt;
&lt;h2 id=&quot;the-pattern-in-one-sentence&quot;&gt;The pattern in one sentence&lt;/h2&gt;
&lt;p&gt;Here is the simplest way to say it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; is not anti-mock. It is anti-hidden dependency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that is why &lt;code&gt;vitest-mock-extended&lt;/code&gt; fits so well.&lt;/p&gt;
&lt;p&gt;It does not undermine the pattern. It reinforces it.&lt;/p&gt;
&lt;p&gt;It says:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;keep dependencies explicit&lt;/li&gt;
&lt;li&gt;keep tests local&lt;/li&gt;
&lt;li&gt;keep the type system honest&lt;/li&gt;
&lt;li&gt;mock the collaborator, not the module system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the same architectural move from a different angle.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;If your function already follows &lt;code&gt;fn(args, deps)&lt;/code&gt;, then &lt;code&gt;vitest-mock-extended&lt;/code&gt; is not a compromise. It is one of the best ways to test that function.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;vi.mock&lt;/code&gt; when you are forced to intercept a module boundary.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;mock&amp;lt;Deps&amp;gt;()&lt;/code&gt; when the function has already declared its boundary explicitly.&lt;/p&gt;
&lt;p&gt;That is the whole point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;explicit deps in production&lt;/li&gt;
&lt;li&gt;typed fake deps in unit tests&lt;/li&gt;
&lt;li&gt;real wiring at the boundary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No magic. No hidden state. No pretending the import graph is the contract.&lt;/p&gt;
&lt;p&gt;Just functions, data, and capabilities.&lt;/p&gt;
</content:encoded></item><item><title>Before You Change the Process, Understand the Problem</title><link>https://arrangeactassert.com/posts/before-you-change-the-process-understand-the-problem/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/before-you-change-the-process-understand-the-problem/</guid><pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Strong opinions should be earned, not borrowed. If you want to propose a change, do the work first.&lt;/p&gt;
&lt;p&gt;Understand the trade-offs before you walk into the room.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Before You Change the Process, Understand the Problem&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 832px) 832px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;832&quot; height=&quot;1248&quot; src=&quot;https://arrangeactassert.com/_astro/before-you-change-the-process-understand-the-problem.BSOBdS9P_1EXLe7.webp&quot; srcset=&quot;/_astro/before-you-change-the-process-understand-the-problem.BSOBdS9P_Z2bj0yl.webp 640w, /_astro/before-you-change-the-process-understand-the-problem.BSOBdS9P_1PzbU3.webp 750w, /_astro/before-you-change-the-process-understand-the-problem.BSOBdS9P_Z1MGMMA.webp 828w, /_astro/before-you-change-the-process-understand-the-problem.BSOBdS9P_1EXLe7.webp 832w&quot;&gt;&lt;/p&gt;
&lt;p&gt;I see the same pattern again and again in software teams. Someone reads a blog post, watches a conference talk, picks up a new buzzword, or sees how a company like Spotify talks about working, and by the next meeting they are proposing that the whole team change how it works.&lt;/p&gt;
&lt;p&gt;The idea often sounds compelling at first. But the moment you ask about the trade-offs, the case falls apart. There is no real research, no serious risk assessment, and no clear plan for what to do if the change creates new problems rather than solving the old ones.&lt;/p&gt;
&lt;p&gt;That gap between enthusiasm and understanding is where teams get into trouble.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-real-world-test&quot;&gt;The real-world test&lt;/h2&gt;
&lt;p&gt;When I returned to University Press as &lt;a href=&quot;https://arrangeactassert.com/posts/getting-people-to-believe-in-your-vision/&quot;&gt;principal architect on a project called Higher Education&lt;/a&gt;, my team lead, &lt;a href=&quot;https://www.linkedin.com/in/claretunstall/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clare&lt;/a&gt;, and I had to make a foundational decision on day one.&lt;/p&gt;
&lt;p&gt;How should the team work?&lt;/p&gt;
&lt;p&gt;The team had grown up inside a Scrum process that had become rigid and overly ceremonial.&lt;/p&gt;
&lt;p&gt;All the artefacts were there, but the collaboration was not. In practice, the work moved in sequence. Design finished and handed over to development. Development finished and handed over to test. It was Scrum in structure, but not in spirit.&lt;/p&gt;
&lt;p&gt;That was the real problem.&lt;/p&gt;
&lt;p&gt;The answer was not to throw out Scrum and replace it with something fashionable. It was to understand why the team was struggling and improve the way we worked within a process people already knew.&lt;/p&gt;
&lt;p&gt;Clare asked me a simple question: “You’re the principal. What do you think we should do?”&lt;/p&gt;
&lt;p&gt;I told her I wanted to come back with a proper answer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Clare and I were not best friends, but there was trust and respect between us. She had brought Agile into University Press and had given talks about it, which helped me enormously. She challenged my thinking, gave me honest feedback, and I learned a huge amount from her. I will always be grateful for that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I went back to first principles. Back to what I had learned during my degree, when we studied Agile, Taylorism, Denning, and the different ways of thinking about work. I went back through lean and agile articles, books, and talks, and grounded myself in a simple truth. Process should reflect the nature of the work.&lt;/p&gt;
&lt;p&gt;What we were doing was not repetitive factory production. It was creative, uncertain, collaborative product development. That kind of work depends on fast feedback, shared ownership, and people working together early, not passing work between silos.&lt;/p&gt;
&lt;p&gt;So when I came back to Clare, I was not proposing a new methodology. I was proposing a better way of working.&lt;/p&gt;
&lt;p&gt;The case was simple. Keep the parts of Scrum that were helping, remove the behaviours that were creating walls, and increase collaboration across the team.&lt;/p&gt;
&lt;p&gt;In practice, that meant changing how we planned and delivered features. When it came to planning, we brought together the stakeholders, the engineer, and the tester, and used a Three Amigos approach to discuss the change. We started with the business outcome, then planned a verifiable, incremental way of delivering the feature.&lt;/p&gt;
&lt;p&gt;Testing did not sit at the end waiting for development to finish. It happened during development. We made sure testers had what they needed to test the way they wanted. Everyone on the team could draw the same high-level picture of the services involved and the data needed. We talked through the happy path and the known knowns up front.&lt;/p&gt;
&lt;p&gt;That did not remove uncertainty, but it changed how we dealt with it. The mindset became simple. Unknowns will happen. Problems will happen. Our job was to design and communicate in a way that made reproducing, identifying, and resolving issues faster when they did.&lt;/p&gt;
&lt;p&gt;Day to day, the work no longer felt disconnected. Everyone felt involved. Everyone knew the context. By the time we came into meetings, people were already aligned. The ceremony was naturally reduced because less time was spent catching people up or reconnecting work that had been split apart. Time wasted dropped. Communication increased.&lt;/p&gt;
&lt;p&gt;Just as importantly, I was clear about the risks. The team was used to working in a certain way. More collaboration would feel uncomfortable at first. It would require people to communicate more openly, share ownership more actively, and adjust habits they had built over time.&lt;/p&gt;
&lt;p&gt;But that honesty strengthened the proposal. I was not selling a silver bullet. I was showing the team where I thought this would help, where it might be difficult, and how we would know whether it was actually improving things.&lt;/p&gt;
&lt;p&gt;That is what made the conversation credible.&lt;/p&gt;
&lt;h2 id=&quot;what-most-people-miss&quot;&gt;What most people miss&lt;/h2&gt;
&lt;p&gt;Too often, people frame process change as a choice between named methodologies.&lt;/p&gt;
&lt;p&gt;Scrum or Kanban.
SAFe or no SAFe.
Estimates or no estimates.&lt;/p&gt;
&lt;p&gt;But most team problems are not solved by picking a new label. They are solved by understanding the actual constraint.&lt;/p&gt;
&lt;p&gt;Sometimes the problem is too many handoffs.
Sometimes it is weak communication.
Sometimes, it is unclear ownership.
Sometimes it is a process that has become disconnected from the people doing the work.&lt;/p&gt;
&lt;p&gt;If you misdiagnose the problem, even a good framework will be applied badly.&lt;/p&gt;
&lt;p&gt;Something is not right for your team just because it sounded good in a book, looked good in a case study, or became famous because a company like Spotify talked about it. Many teams copy labels, rituals, or structures without understanding what made them work in the first place. That is how people end up cargo-culting someone else’s model instead of solving their own problem.&lt;/p&gt;
&lt;h2 id=&quot;the-difference-in-practice&quot;&gt;The difference in practice&lt;/h2&gt;
&lt;h3 id=&quot;the-anti-pattern&quot;&gt;The anti-pattern&lt;/h3&gt;
&lt;p&gt;“We should switch to Kanban. I read that it works really well for high-performing teams.”&lt;/p&gt;
&lt;h3 id=&quot;the-standard&quot;&gt;The standard&lt;/h3&gt;
&lt;p&gt;“Our problem is not Scrum itself. Our problem is that work is moving through silos. I think we should keep the useful structure, reduce the handoffs, increase collaboration, and review in two weeks whether flow, communication, and delivery have improved.”&lt;/p&gt;
&lt;p&gt;That is a much stronger proposal because it is rooted in the team’s reality rather than borrowed from somebody else’s context.&lt;/p&gt;
&lt;h2 id=&quot;what-i-took-away&quot;&gt;What I took away&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Start with the problem, not the framework.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Teams get into trouble when they inherit solutions before they understand the issue. Diagnose first. Change second.&lt;/p&gt;
&lt;p&gt;This happens in sports all the time. Football teams do not choose one strategy in August and stick to it until May, no matter what. They adapt game by game based on the opposition, the conditions, injuries, and the strengths and weaknesses in front of them. Teams at work should be no different.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Improve before you replace.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You do not always need a new methodology. Often, you need to remove friction, reduce handoffs, and help the team collaborate more effectively within the process they already understand.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Present the risks as clearly as the benefits.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Anyone can sell the upside. Credibility comes from being able to say, “Here is where this may be harder than it sounds, and here is how we will know if it is working.”&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Process should serve the team.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a ceremony helps, keep it. If it creates a delay without adding value, challenge it. If someone is blocked, they should not have to wait for tomorrow’s stand-up to get help. Good process supports communication, ownership, and flow. It does not replace them.&lt;/p&gt;
&lt;h2 id=&quot;the-standard-worth-aiming-for&quot;&gt;The standard worth aiming for&lt;/h2&gt;
&lt;p&gt;The best proposals do not just answer the question, “What should we change?”&lt;/p&gt;
&lt;p&gt;They answer, “What problem are we actually solving?” and “How will we know if this is better?”&lt;/p&gt;
&lt;p&gt;That is the difference between borrowing an opinion and earning one.&lt;/p&gt;
&lt;p&gt;That mindset led to a lot of changes that were a first for University Press. We were the first team to use &lt;a href=&quot;https://arrangeactassert.com/posts/introducing-typescript-at-cambridge-university-press/&quot;&gt;TypeScript&lt;/a&gt; and &lt;a href=&quot;https://arrangeactassert.com/posts/introducing-tailwind-at-cambridge-university-press/&quot;&gt;Tailwind&lt;/a&gt;. We introduced feature branches. We focused on DORA metrics and on delivering value to the business, rather than obsessing over velocity points.&lt;/p&gt;
&lt;p&gt;Each time, I said the same thing to the team: “Let’s try it. If it is not working in a month, we will remove it.”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We never had to remove a single thing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And in leadership, that difference matters.&lt;/p&gt;
</content:encoded></item><item><title>fn(args, deps) and Composition — Know When to Nest the Dolls</title><link>https://arrangeactassert.com/posts/fn-args-deps-and-composition/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-and-composition/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Just because two pieces of code look the same does not mean they are the same.&lt;/p&gt;
&lt;p&gt;The most common architecture mistake is not too little abstraction. It is too much, too early. You see duplication, you extract a shared module, and six months later that module is a monster held together by special cases and boolean flags.&lt;/p&gt;
&lt;p&gt;Dan Abramov gave a talk about this called &lt;a href=&quot;https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The Wet Codebase&lt;/a&gt;. The core argument: the wrong abstraction is far more expensive than duplication. Once an abstraction exists, it creates inertia. Nobody wants to be the person who suggests copy-paste.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;fn(args, deps) changes this calculus. It makes abstractions cheap to create, cheap to test, and cheap to undo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When a function’s deps grow too large, that can be a signal that some responsibility has stabilized into its own function — and that new function itself follows &lt;code&gt;fn(args, deps)&lt;/code&gt;. (This is basically SRP pressure showing up in your signature; see the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-solid-principles/&quot;&gt;SOLID post&lt;/a&gt; for that framing.)&lt;/p&gt;
&lt;p&gt;Russian dolls. Each layer independently testable. Each layer reversible.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;fn(args, deps) is all you need&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/fn-args-deps-and-composition.BOfD-Rlk_ZvtEeq.webp&quot; srcset=&quot;/_astro/fn-args-deps-and-composition.BOfD-Rlk_ZMGb2a.webp 640w, /_astro/fn-args-deps-and-composition.BOfD-Rlk_Z1DaKnu.webp 750w, /_astro/fn-args-deps-and-composition.BOfD-Rlk_1zsFrM.webp 828w, /_astro/fn-args-deps-and-composition.BOfD-Rlk_Z22kCL3.webp 1080w, /_astro/fn-args-deps-and-composition.BOfD-Rlk_1giTP8.webp 1280w, /_astro/fn-args-deps-and-composition.BOfD-Rlk_ZvtEeq.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-wrong-abstraction-creates-inertia&quot;&gt;The wrong abstraction creates inertia&lt;/h2&gt;
&lt;p&gt;Abramov tells a familiar story. Two modules share similar code. A colleague extracts a shared abstraction. Then a third use case arrives that is almost the same, but not quite. So you add a parameter. Then a special case. Then another.&lt;/p&gt;
&lt;p&gt;Each step makes sense to the person writing and reviewing it. But if you lose track of what the abstraction was supposed to represent, you end up with a module nobody wants to touch.&lt;/p&gt;
&lt;p&gt;The real damage is social, not technical. Even when the team agrees the abstraction is bad, unwinding it is expensive, especially if other teams depend on it, if nobody knows how to test the inlined version, or if nobody wants to be the one who decreases code coverage.&lt;/p&gt;
&lt;p&gt;Abramov’s advice: restrain yourself. Let the code stabilize before you extract. And when you do extract, test the concrete behavior, not the abstraction — so that refactoring stays safe.&lt;/p&gt;
&lt;p&gt;That advice is exactly right. And &lt;code&gt;fn(args, deps)&lt;/code&gt; is what makes it practical.&lt;/p&gt;
&lt;p&gt;When deps are explicit data, inlining an abstraction becomes much more mechanical. Copy the function body back, merge the deps types, and let the compiler show you the remaining seams. There is no module mocking to untangle, no framework wiring to redo, no decorator chain to unravel. The abstraction is just a function. Removing it is just removing a function.&lt;/p&gt;
&lt;h2 id=&quot;the-smell-too-many-deps&quot;&gt;The smell: too many deps&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn(args, deps)&lt;/code&gt; equivalent of “too many constructor parameters” is a deps type that keeps growing.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProcessOrderArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  quantity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  paymentMethod&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentMethod&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProcessOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;findProduct&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Product&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; qty&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; qty&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentMethod&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ChargeResult&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; meta&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seven deps. That is a signal, not a sin. The question is not “should I abstract?” It is “have some of these deps stabilized into a coherent responsibility?”&lt;/p&gt;
&lt;p&gt;If you are on day one and this is the first function that uses these deps — leave it flat. You do not know yet which deps belong together. Premature grouping is how you get Abramov’s monster.&lt;/p&gt;
&lt;p&gt;But if you have been living with this code for a while, and you see &lt;code&gt;findProduct&lt;/code&gt;, &lt;code&gt;checkInventory&lt;/code&gt;, and &lt;code&gt;reserveStock&lt;/code&gt; showing up together in multiple functions, and they always represent the same concern — inventory fulfillment — then you probably have an abstraction waiting to be named.&lt;/p&gt;
&lt;h2 id=&quot;consolidate-when-the-responsibility-is-clear&quot;&gt;Consolidate when the responsibility is clear&lt;/h2&gt;
&lt;p&gt;Some of those deps cluster naturally. &lt;code&gt;findProduct&lt;/code&gt;, &lt;code&gt;checkInventory&lt;/code&gt;, and &lt;code&gt;reserveStock&lt;/code&gt; are all inventory concerns. &lt;code&gt;chargePayment&lt;/code&gt; is a payment concern.&lt;/p&gt;
&lt;p&gt;The move is to extract new functions that each follow &lt;code&gt;fn(args, deps)&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FulfillOrderArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  quantity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FulfillOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;findProduct&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Product&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; qty&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; qty&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fulfillOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FulfillOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FulfillOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; product &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findProduct&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;productId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; available &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;productId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;available&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;out-of-stock&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;productId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; product &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the parent function’s deps get simpler:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProcessOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;fulfillOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FulfillOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FulfillResult&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentMethod&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ChargeResult&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; meta&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From seven deps to four. And &lt;code&gt;fulfillOrder&lt;/code&gt; is itself &lt;code&gt;fn(args, deps)&lt;/code&gt;. It has its own deps — &lt;code&gt;findProduct&lt;/code&gt;, &lt;code&gt;checkInventory&lt;/code&gt;, &lt;code&gt;reserveStock&lt;/code&gt; — wired at the &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And now the parent function reads like a plan:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProcessOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProcessOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Processing order&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;productId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fulfillment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fulfillOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;productId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    quantity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;fulfillment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; fulfillment&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; charge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    fulfillment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;price &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paymentMethod&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;charge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment-failed&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; product&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fulfillment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; chargeId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; charge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parent does not reach into fulfillment’s internals. It only knows the shape: give me a product and quantity, get back a result.&lt;/p&gt;
&lt;p&gt;Each layer is independently testable. You can test &lt;code&gt;fulfillOrder&lt;/code&gt; with fake product lookups. You can test &lt;code&gt;processOrder&lt;/code&gt; with a fake &lt;code&gt;fulfillOrder&lt;/code&gt; that always succeeds. The layers stay decoupled.&lt;/p&gt;
&lt;h2 id=&quot;extract-only-when-the-responsibility-is-clear&quot;&gt;Extract only when the responsibility is clear&lt;/h2&gt;
&lt;p&gt;This is where Abramov’s lesson matters most.&lt;/p&gt;
&lt;p&gt;Do not create &lt;code&gt;fulfillOrder&lt;/code&gt; on day one. Start with the flat deps list. Write the code. Ship it. Let it stabilize.&lt;/p&gt;
&lt;p&gt;The signal that it is time to extract:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The same cluster of deps appears across multiple functions&lt;/li&gt;
&lt;li&gt;Those deps represent a coherent responsibility, not just accidental proximity&lt;/li&gt;
&lt;li&gt;You can name the new function after what it does, not after how it is implemented&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you cannot name it clearly, you do not understand the responsibility yet. Wait.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; makes this safe in both directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Extract:&lt;/strong&gt; create a new &lt;code&gt;fn(args, deps)&lt;/code&gt;, move the clustered deps into it, wire it at the composition root&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inline:&lt;/strong&gt; if the abstraction was wrong, copy the body back, merge the deps types — no framework ceremony to undo&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The right time to abstract is when you understand the responsibility, not when you notice the duplication.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;why-this-scales&quot;&gt;Why this scales&lt;/h2&gt;
&lt;p&gt;Each layer is just &lt;code&gt;fn(args, deps)&lt;/code&gt;. Same testing story. Same composition root wiring. Same explicit dependency surface.&lt;/p&gt;
&lt;p&gt;No inheritance hierarchies. No decorator chains. No middleware stacks. No framework registration.&lt;/p&gt;
&lt;p&gt;You can zoom in and test &lt;code&gt;fulfillOrder&lt;/code&gt; in isolation with three simple deps. Or you can stay at the higher layer and test &lt;code&gt;processOrder&lt;/code&gt; with a fake &lt;code&gt;fulfillOrder&lt;/code&gt; that returns a canned result.&lt;/p&gt;
&lt;p&gt;The pattern does not fight you when you change your mind. Because every layer is just a function that takes data and capabilities. If a layer turns out to be wrong, you delete it and move on. The types tell you exactly what to fix.&lt;/p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;Composition is not about having the right abstraction from the start. It is about making abstractions cheap to create, cheap to test, and cheap to undo.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; gives you all three,  because every layer is just a function that takes data and capabilities. Nest them when the responsibility is clear. Flatten them when it is not.&lt;/p&gt;
&lt;p&gt;That is the Russian dolls model: layers you can add when the responsibility is clear, and remove when it is not.&lt;/p&gt;
</content:encoded></item><item><title>fn(args, deps) Is Programming to Interfaces — And That&apos;s How You Control Nondeterminism</title><link>https://arrangeactassert.com/posts/fn-args-deps-and-determinism/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-and-determinism/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Many software systems fail for one very boring reason.&lt;/p&gt;
&lt;p&gt;Not because of microservices. Not because of monoliths. Not because of whatever methodology war is trending this week.&lt;/p&gt;
&lt;p&gt;They fail because they are unpredictable.&lt;/p&gt;
&lt;p&gt;If you make a change and you cannot reliably determine the impact, you cannot safely evolve the system. And when you cannot evolve it, it starts behaving like legacy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Determinism is the bridge between “works on my machine” and “works every time, everywhere.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; gets you there — not because it is a clever trick, but because it makes boundaries explicit. Your logic programs to interfaces, which is what lets you control sources of nondeterminism.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Dave Farley makes this argument better than almost anyone. If you have not seen his talk on determinism and evolutionary architecture, it is worth your time:&lt;/p&gt;
&lt;iframe
  src=&quot;https://www.youtube.com/embed/uHatwKrYY_c&quot;
  style=&quot;width:100%; aspect-ratio:16/9;&quot;
  frameborder=&quot;0&quot;
  allowfullscreen
&gt;&lt;/iframe&gt;
&lt;p&gt;What follows is not a recap of that talk. It is about one specific claim: that &lt;code&gt;fn(args, deps)&lt;/code&gt; is a concrete, function-level way to implement the core of what Farley is describing.&lt;/p&gt;
&lt;h2 id=&quot;determinism-is-the-prerequisite&quot;&gt;Determinism is the prerequisite&lt;/h2&gt;
&lt;p&gt;You cannot evolve what you cannot measure. You cannot measure what you cannot repeat. And you cannot repeat what you cannot reliably reproduce.&lt;/p&gt;
&lt;p&gt;Flaky tests, intermittent builds, and concurrency heisenbugs turn your delivery pipeline from a learning system into release theater.&lt;/p&gt;
&lt;p&gt;Determinism is the prerequisite for trust. Without it, your feedback loops degrade and your architecture rots quietly in the background.&lt;/p&gt;
&lt;p&gt;With it, you can run thousands of experiments per day, detect unintended consequences, and move fast without gambling. That is an evolutionary capability.&lt;/p&gt;
&lt;p&gt;Continuous delivery depends on pipelines, but pipelines only earn trust when the system beneath them is deterministic. The pipeline is just the amplifier.&lt;/p&gt;
&lt;h2 id=&quot;separate-the-code-that-decides-from-the-code-that-acts&quot;&gt;Separate the code that decides from the code that acts&lt;/h2&gt;
&lt;p&gt;Farley frames this as the deterministic core and the imperative shell.&lt;/p&gt;
&lt;p&gt;The deterministic core is &lt;em&gt;reproducible logic under controlled inputs&lt;/em&gt;. State in, decision out. No hidden database calls, no hidden clock, no hidden randomness.&lt;/p&gt;
&lt;p&gt;The imperative shell is the messy part. Talk to the database, talk to the network, read the clock, execute side effects.&lt;/p&gt;
&lt;p&gt;You can map this to “ports and adapters,” but the point here is simpler: “how do I make behavior predictable?”&lt;/p&gt;
&lt;p&gt;If you have read the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;earlier post on hexagonal architecture&lt;/a&gt;, the structure is familiar. What changes here is the reason it matters.&lt;/p&gt;
&lt;h2 id=&quot;fnargs-deps-is-programming-to-interfaces&quot;&gt;fn(args, deps) is programming to interfaces&lt;/h2&gt;
&lt;p&gt;This is the connection most people miss.&lt;/p&gt;
&lt;p&gt;When you write a deps type, you are writing an interface. Not a Java-style &lt;code&gt;interface&lt;/code&gt; with a keyword and a class that &lt;code&gt;implements&lt;/code&gt; it. Just a type that describes what capabilities the function needs from the outside world.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetExpiringItemsDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;findItemsExpiringBefore&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cutoff&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That type is the interface. The function programs to it. The &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt; decides what implements it.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expirationCutoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;windowMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getExpiringItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetExpiringItemsDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findItemsExpiringBefore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expirationCutoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function does not know whether &lt;code&gt;now&lt;/code&gt; returns the real time or a frozen timestamp. It does not know whether &lt;code&gt;findItemsExpiringBefore&lt;/code&gt; queries Postgres or returns a hardcoded array. It is deliberately indifferent.&lt;/p&gt;
&lt;p&gt;That is what programming to interfaces means: your logic does not reach behind the contract. It stays on the surface—capabilities in, results out.&lt;/p&gt;
&lt;p&gt;And that is what makes the logic &lt;em&gt;reproducible under controlled inputs&lt;/em&gt;. Once sources of nondeterminism are explicit, you can control or replace them for the purpose of a call.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The deps type is the interface. The function programs to it. That is all programming to interfaces ever needed to be.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-clock-example&quot;&gt;The clock example&lt;/h2&gt;
&lt;p&gt;Here is the simplest way to see it.&lt;/p&gt;
&lt;p&gt;If your code calls &lt;code&gt;Date.now()&lt;/code&gt; directly, you have pulled time into the middle of your logic. The same explicit input tomorrow can produce a different output, because time is now a hidden input. You &lt;em&gt;can&lt;/em&gt; still test it, but tests get harder to make reliable and harder to replay exactly.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// nondeterministic — the output depends on when you run it&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getExpiringItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cutoff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; windowMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findItemsExpiringBefore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cutoff&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, inject a clock. Pass time as data. Treat &lt;code&gt;now&lt;/code&gt; as an input.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// reproducible under controlled deps — the output depends on what you pass in&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expirationCutoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;windowMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getExpiringItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetExpiringItemsDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findItemsExpiringBefore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expirationCutoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now something powerful happens. You can freeze time. You can fast-forward it. You can reproduce production bugs by replaying timestamps (assuming the rest of your dependencies are similarly controlled for the replay).&lt;/p&gt;
&lt;p&gt;You have turned the universe into a parameter.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;finds items expiring within the window&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; frozenNow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2026-03-19T12:00:00Z&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getExpiringItems&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; windowMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60_000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; frozenNow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;findItemsExpiringBefore&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Trial&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expiresAt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2026-03-19T11:59:30Z&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Trial&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No module patching. No hoisted mocks. No test framework reaching into module internals. Just explicit test doubles passed as data.&lt;/p&gt;
&lt;p&gt;This works because the function programs to the deps interface, not to the real clock or the real database.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters-for-evolutionary-architecture&quot;&gt;Why this matters for evolutionary architecture&lt;/h2&gt;
&lt;p&gt;When your core logic is written against explicit deps instead of reaching into the world, you can test it without monkey-patching, module interception, or elaborate scaffolding.&lt;/p&gt;
&lt;p&gt;You pass in state. You assert on output. You can run thousands of tests in milliseconds.&lt;/p&gt;
&lt;p&gt;Those are your fitness functions at scale. And when you have fitness functions you can trust, your architecture can evolve safely, one function at a time.&lt;/p&gt;
&lt;p&gt;Determinism is not a coding trick. It is a systems property. &lt;code&gt;fn(args, deps)&lt;/code&gt; does not create determinism by magic—it makes the boundaries around nondeterminism explicit. Once they are explicit, you can control them, replace them, and replay them.&lt;/p&gt;
&lt;h2 id=&quot;the-chain&quot;&gt;The chain&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; is programming to interfaces without the ceremony.&lt;/p&gt;
&lt;p&gt;Programming to interfaces makes sources of nondeterminism explicit.&lt;/p&gt;
&lt;p&gt;Explicit nondeterminism is controllable and testable.&lt;/p&gt;
&lt;p&gt;Controllable, testable behavior is what makes deterministic systems possible.&lt;/p&gt;
&lt;p&gt;Deterministic systems are what make evolutionary architecture possible.&lt;/p&gt;
&lt;p&gt;That chain — from function signature to system capability — is why the pattern matters.&lt;/p&gt;
</content:encoded></item><item><title>How fn(args, deps) supports SOLID-style design in TypeScript</title><link>https://arrangeactassert.com/posts/fn-args-deps-and-solid-principles/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-and-solid-principles/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;A lot of developers learn the SOLID principles through class-heavy examples.&lt;/p&gt;
&lt;p&gt;That is probably why the conversation so often gets stuck there.&lt;/p&gt;
&lt;p&gt;People start to associate SOLID with inheritance hierarchies, interface forests, service classes, and object-oriented ceremony.&lt;/p&gt;
&lt;p&gt;But the useful part is not the ceremony.&lt;/p&gt;
&lt;p&gt;It is the design pressure.&lt;/p&gt;
&lt;div&gt;
  &lt;img
    src=&quot;https://arrangeactassert.com/static/images/fn-args-deps-and-solid-principles.png&quot;
    alt=&quot;fn(args, deps) and SOLID principles&quot;
    class=&quot;w-full h-auto bg-white&quot;
  /&gt;
&lt;/div&gt;
&lt;p&gt;One of the simplest ways to apply that pressure in plain TypeScript is this shape:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;args&lt;/code&gt; is the input for this call and &lt;code&gt;deps&lt;/code&gt; is the set of collaborators the function needs.
You can read that as: data in, capabilities in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; is not a replacement for SOLID. It is a simple function shape that makes several SOLID ideas easier to apply without forcing you into class-heavy design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;solid-is-about-design-pressure-not-class-ceremony&quot;&gt;SOLID is about design pressure, not class ceremony&lt;/h2&gt;
&lt;p&gt;SOLID is often taught as though it naturally implies classes, interfaces, and object hierarchies.&lt;/p&gt;
&lt;p&gt;But the principles themselves are broader than that.&lt;/p&gt;
&lt;p&gt;They are really about questions like these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;does this unit of code have one clear reason to change?&lt;/li&gt;
&lt;li&gt;can behavior vary without editing unrelated logic?&lt;/li&gt;
&lt;li&gt;are abstractions helping or just adding indirection?&lt;/li&gt;
&lt;li&gt;are dependencies pointing in the right direction?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those questions still matter in plain TypeScript, even if you are writing functions instead of classes.&lt;/p&gt;
&lt;p&gt;That is where &lt;code&gt;fn(args, deps)&lt;/code&gt; becomes useful.&lt;/p&gt;
&lt;p&gt;It gives you a simple way to separate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;call-specific data&lt;/li&gt;
&lt;li&gt;long-lived collaborators&lt;/li&gt;
&lt;li&gt;application logic&lt;/li&gt;
&lt;li&gt;infrastructure concerns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That separation does not automatically make code good, but it does make good design easier to see and bad design harder to hide.&lt;/p&gt;
&lt;h2 id=&quot;a-small-example&quot;&gt;A small example&lt;/h2&gt;
&lt;p&gt;Consider a use case like this:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  userRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UserRepo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Mailer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Creating user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userRepo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just a function.&lt;/p&gt;
&lt;p&gt;But even in this small example, the shape already encourages several useful design properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the input is explicit&lt;/li&gt;
&lt;li&gt;the collaborators are explicit&lt;/li&gt;
&lt;li&gt;side-effecting collaborators are visible in the signature&lt;/li&gt;
&lt;li&gt;the business operation is separated from how dependencies are created&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is why this shape works well with SOLID-style design pressure.&lt;/p&gt;
&lt;p&gt;Not because it turns functions into objects.&lt;/p&gt;
&lt;p&gt;Because it makes responsibilities and dependencies visible.&lt;/p&gt;
&lt;h2 id=&quot;single-responsibility-principle&quot;&gt;Single Responsibility Principle&lt;/h2&gt;
&lt;p&gt;The Single Responsibility Principle is often paraphrased badly, but the useful version is simple:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A unit of code should have one coherent reason to change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; helps because it encourages you to keep one function focused on one job, while pushing infrastructure concerns outward.&lt;/p&gt;
&lt;p&gt;In the example above, &lt;code&gt;createUser&lt;/code&gt; is responsible for the user-creation workflow.&lt;/p&gt;
&lt;p&gt;It is not also responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constructing a database client&lt;/li&gt;
&lt;li&gt;configuring a mail transport&lt;/li&gt;
&lt;li&gt;locating a logger&lt;/li&gt;
&lt;li&gt;deciding which concrete implementations exist in production&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those concerns live elsewhere.&lt;/p&gt;
&lt;p&gt;That matters because a lot of SRP violations show up when one unit mixes workflow logic with setup logic and environment logic.&lt;/p&gt;
&lt;p&gt;This is a more obvious violation:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mailer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeMailer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeLogger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Creating user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the function has multiple reasons to change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the user creation flow changes&lt;/li&gt;
&lt;li&gt;database construction changes&lt;/li&gt;
&lt;li&gt;mail setup changes&lt;/li&gt;
&lt;li&gt;logging setup changes&lt;/li&gt;
&lt;li&gt;environment configuration changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is exactly the kind of responsibility bleed that &lt;code&gt;fn(args, deps)&lt;/code&gt; helps prevent.&lt;/p&gt;
&lt;h2 id=&quot;openclosed-principle&quot;&gt;Open/Closed Principle&lt;/h2&gt;
&lt;p&gt;The Open/Closed Principle is usually summarized as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open for extension, closed for modification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, the useful question is:&lt;/p&gt;
&lt;p&gt;Can I change how this function behaves by changing its collaborators, without rewriting the function itself?&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;fn(args, deps)&lt;/code&gt;, the answer is often yes.&lt;/p&gt;
&lt;p&gt;You can change the repository, mailer, or logger without changing the core workflow:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    userRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cachedUserRepo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; noopMailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; structuredLogger&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a practical form of extension through composition.&lt;/p&gt;
&lt;p&gt;You are not subclassing anything.
You are not overriding a method.
You are varying behavior by supplying different collaborators.&lt;/p&gt;
&lt;p&gt;That is often a much simpler way to satisfy the spirit of OCP in TypeScript.&lt;/p&gt;
&lt;p&gt;The important caveat is that this only works well when the function depends on meaningful capabilities rather than concrete setup details.&lt;/p&gt;
&lt;p&gt;If your &lt;code&gt;deps&lt;/code&gt; object is full of leaky implementation specifics, you are not really extending cleanly. You are just moving complexity around.&lt;/p&gt;
&lt;h2 id=&quot;liskov-substitution-principle&quot;&gt;Liskov Substitution Principle&lt;/h2&gt;
&lt;p&gt;LSP is one of the principles people invoke most and understand least.&lt;/p&gt;
&lt;p&gt;In class-heavy design, it is about whether a subtype can stand in for its base type without breaking expectations.&lt;/p&gt;
&lt;p&gt;LSP does not map as directly to function-oriented design as SRP, ISP, or DIP.
But the same substitution concern still shows up at dependency boundaries.&lt;/p&gt;
&lt;p&gt;The useful question becomes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can one dependency implementation be substituted for another without breaking the expectations of the function that uses it?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If &lt;code&gt;createUser&lt;/code&gt; depends on a &lt;code&gt;Mailer&lt;/code&gt;, then different mailers should behave in ways the workflow can safely rely on.&lt;/p&gt;
&lt;p&gt;For example, these might both be valid substitutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a real SMTP mailer&lt;/li&gt;
&lt;li&gt;a fake test mailer&lt;/li&gt;
&lt;li&gt;a mailer that writes to an outbox table&lt;/li&gt;
&lt;li&gt;a mailer that queues background jobs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What matters is that they preserve the contract the use case expects.&lt;/p&gt;
&lt;p&gt;That is not unique to &lt;code&gt;fn(args, deps)&lt;/code&gt;, but the pattern makes the substitution point explicit.&lt;/p&gt;
&lt;p&gt;Instead of inheritance hiding the boundary, the dependency boundary is right there in the function signature.&lt;/p&gt;
&lt;p&gt;That visibility is useful because substitution problems become easier to spot. If the function keeps needing special cases for one implementation, that is often a signal that the abstraction is wrong.&lt;/p&gt;
&lt;h2 id=&quot;interface-segregation-principle&quot;&gt;Interface Segregation Principle&lt;/h2&gt;
&lt;p&gt;The Interface Segregation Principle says consumers should not be forced to depend on methods they do not use.&lt;/p&gt;
&lt;p&gt;This is one place where &lt;code&gt;fn(args, deps)&lt;/code&gt; can be better than large service objects.&lt;/p&gt;
&lt;p&gt;Because dependencies are passed per function, you can keep them narrow.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  userRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pick&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;UserRepo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;findById&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetUserDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userRepo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a very small dependency surface.&lt;/p&gt;
&lt;p&gt;The function does not need the entire repository API. It only needs the capability it actually uses.&lt;/p&gt;
&lt;p&gt;This is an underrated advantage of the pattern.&lt;/p&gt;
&lt;p&gt;When dependencies are explicit and local to the function, oversized interfaces start to feel awkward immediately.&lt;/p&gt;
&lt;p&gt;That friction is good. It pushes you toward smaller, more honest contracts.&lt;/p&gt;
&lt;h2 id=&quot;dependency-inversion-principle&quot;&gt;Dependency Inversion Principle&lt;/h2&gt;
&lt;p&gt;This is the SOLID principle most obviously related to dependency injection.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;High-level policy should not depend directly on low-level details. Both should depend on abstractions or stable boundaries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; makes that easier because it naturally separates use-case logic from infrastructure wiring.&lt;/p&gt;
&lt;p&gt;The use case says what it needs:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  userRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UserRepo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Mailer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application edge decides what satisfies those needs:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./create-user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makePostgresUserRepo &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/postgres-user-repo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeSesMailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/ses-mailer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeLogger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/logger&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userRepo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makePostgresUserRepo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mailer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeSesMailer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeLogger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userRepo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is Dependency Inversion without needing a container to make it feel real.&lt;/p&gt;
&lt;p&gt;The use case does not know how the dependencies were created. It only knows the capabilities it was given.&lt;/p&gt;
&lt;p&gt;That is the important part.&lt;/p&gt;
&lt;h2 id=&quot;this-does-not-mean-use-abstractions-everywhere&quot;&gt;This does not mean “use abstractions everywhere”&lt;/h2&gt;
&lt;p&gt;This is where SOLID conversations often go off the rails.&lt;/p&gt;
&lt;p&gt;Once people hear “Dependency Inversion” or “Interface Segregation,” they start introducing abstractions for everything.&lt;/p&gt;
&lt;p&gt;That is usually a mistake.&lt;/p&gt;
&lt;p&gt;Not every helper needs to be abstracted.
Not every utility needs to be injected.
Not every module needs an interface.&lt;/p&gt;
&lt;p&gt;For pure logic, direct imports are often the better choice:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; normalizeEmail &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./normalize-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toUserRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That helper is deterministic, side-effect free, and not especially interesting as a substitution point. Passing it through &lt;code&gt;deps&lt;/code&gt; would add ceremony without buying much.&lt;/p&gt;
&lt;p&gt;A good rule of thumb:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use direct imports for pure logic and stable helpers&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;deps&lt;/code&gt; for collaborators that touch the outside world, vary by environment, or matter in tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is how you keep SOLID from turning into ritual.&lt;/p&gt;
&lt;h2 id=&quot;composition-still-happens-at-the-edge&quot;&gt;Composition still happens at the edge&lt;/h2&gt;
&lt;p&gt;One common objection is that explicit dependencies will make every call site noisy.&lt;/p&gt;
&lt;p&gt;Sometimes they will.&lt;/p&gt;
&lt;p&gt;That is why composition belongs at the edge of the application.&lt;/p&gt;
&lt;p&gt;You can bind dependencies once and expose a simpler API:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;makeCreateUser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then your startup code can assemble the real version:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createUserWithServices &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeCreateUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  userRepo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  logger&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUserWithServices&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is important for two reasons.&lt;/p&gt;
&lt;p&gt;First, it keeps the use case explicit about what it needs.&lt;/p&gt;
&lt;p&gt;Second, it keeps the wiring in one honest place instead of scattering it across the codebase.&lt;/p&gt;
&lt;p&gt;That is good design whether you talk about &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition roots&lt;/a&gt;, DI, or SOLID.&lt;/p&gt;
&lt;h2 id=&quot;where-this-pattern-actually-helps&quot;&gt;Where this pattern actually helps&lt;/h2&gt;
&lt;p&gt;The value of &lt;code&gt;fn(args, deps)&lt;/code&gt; is not that it magically makes code SOLID.&lt;/p&gt;
&lt;p&gt;No function signature can do that.&lt;/p&gt;
&lt;p&gt;The value is that it nudges the codebase in useful directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;responsibilities are easier to isolate&lt;/li&gt;
&lt;li&gt;dependency surfaces are easier to shrink&lt;/li&gt;
&lt;li&gt;substitution points are easier to see&lt;/li&gt;
&lt;li&gt;infrastructure stays at the edge more often&lt;/li&gt;
&lt;li&gt;tests become simpler because collaborators are already explicit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is why I think this shape is such a strong default for many application-level functions in TypeScript.&lt;/p&gt;
&lt;p&gt;It supports the intent behind SOLID without forcing you into all the class-oriented baggage that often comes with SOLID discussions.&lt;/p&gt;
&lt;h2 id=&quot;why-fnargs-deps-works-well-with-solid-style-design&quot;&gt;Why fn(args, deps) works well with SOLID-style design&lt;/h2&gt;
&lt;p&gt;If SOLID only works when wrapped in inheritance hierarchies, giant interfaces, and framework-controlled injection, then it is not much use in a lot of modern TypeScript code.&lt;/p&gt;
&lt;p&gt;The better view is simpler:&lt;/p&gt;
&lt;p&gt;SOLID is a set of design pressures. &lt;code&gt;fn(args, deps)&lt;/code&gt; is one practical way to apply several of them in TypeScript.&lt;/p&gt;
&lt;p&gt;It helps you keep responsibilities narrower.
It helps you keep dependency boundaries visible.
It helps you vary collaborators without hiding where they come from.
And it helps you keep infrastructure wiring out of business logic.&lt;/p&gt;
&lt;p&gt;In plain TypeScript, that is often more valuable than a perfectly textbook interpretation of SOLID.&lt;/p&gt;
&lt;p&gt;Because the goal is not to perform the principles.&lt;/p&gt;
&lt;p&gt;It is to write code that stays understandable as the application grows.&lt;/p&gt;
</content:encoded></item><item><title>fn(args, deps) — Bringing Order to Chaos Without Breaking Anything</title><link>https://arrangeactassert.com/posts/fn-args-deps-bringing-order-to-chaos-without-breaking-anything/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-bringing-order-to-chaos-without-breaking-anything/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;There’s a major disconnect in AI-assisted development right now. Most of the conversation assumes you’re building something new, or working from the kind of clean, stable foundation that barely exists in real engineering teams.&lt;/p&gt;
&lt;p&gt;The reality is that most engineering teams live in legacy systems under high load, with god classes, global singletons, and &lt;code&gt;console.log&lt;/code&gt; as observability. The kind of code where every change is a gamble.&lt;/p&gt;
&lt;p&gt;This post shows what happens when you apply &lt;a href=&quot;https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/&quot;&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/jagreehal/autotel&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;autotel&lt;/a&gt; to those codebases. &lt;code&gt;fn(args, deps)&lt;/code&gt; creates the seam for safe change; production telemetry captures the behavioural record that survives when every other spec has decayed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;John Bercow shouting “Order!” in the House of Commons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 640px) 640px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;640&quot; height=&quot;356&quot; src=&quot;https://arrangeactassert.com/_astro/john-bercow-order.BNcaFJ5s_2m3glg.webp&quot; srcset=&quot;/_astro/john-bercow-order.BNcaFJ5s_2m3glg.webp 640w&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To prove the point, we’ll do this in plain JavaScript, not TypeScript.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- Excerpt End --&gt;
&lt;blockquote&gt;
&lt;p&gt;Companion repo: &lt;a href=&quot;https://github.com/jagreehal/fn-args-deps-bringing-order-to-chaos-without-breaking-anything&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;fn-args-deps-bringing-order-to-chaos-without-breaking-anything&lt;/a&gt;: every step is independently runnable, in plain JavaScript, with no TypeScript required.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;three-fields-three-realities&quot;&gt;Three Fields, Three Realities&lt;/h2&gt;
&lt;p&gt;Greenfield is what the demos show: net new code, explicit intent, and a spec you still trust.&lt;/p&gt;
&lt;p&gt;Brownfield is where most teams actually work: an existing system, still evolving, where intent is only partially recoverable.&lt;/p&gt;
&lt;p&gt;Blackfield is something else again: legacy systems under load, on a deprecation path everyone agrees on and nobody has time to execute.&lt;/p&gt;
&lt;p&gt;This post starts in Blackfield. Features are still being bolted on because the business can’t wait for the rewrite. Original authors are gone. Tests, if they exist, describe the system as it was. Documentation, if it exists, lies.&lt;/p&gt;
&lt;p&gt;That isn’t just a codebase with worse docs. It’s a different engineering posture. You’re not trying to improve something. You’re trying not to break something while slowly making it possible to change. AI agents, trained to build forward and iterate toward green tests, are carrying the wrong assumptions into that room.&lt;/p&gt;
&lt;h2 id=&quot;the-spec-problem-nobody-admits&quot;&gt;The Spec Problem Nobody Admits&lt;/h2&gt;
&lt;p&gt;Spec-driven development has a hidden premise: you know what your system is supposed to do.&lt;/p&gt;
&lt;p&gt;In Greenfield, true. In Brownfield, partially true. In Blackfield, false.&lt;/p&gt;
&lt;p&gt;Legacy systems accumulate behaviour nobody planned. Business rules encoded in conditionals that outlived everyone who understood them. When you ask an agent to work here without a spec, you haven’t freed it from needing one. You’ve made the spec implicit, and the inferred spec will be wrong in ways that are hard to detect and expensive to discover.&lt;/p&gt;
&lt;p&gt;The spec problem isn’t solved by better prompts. It’s solved by better sources of truth.&lt;/p&gt;
&lt;p&gt;Here’s what a typical legacy system looks like:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./db.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; paymentGateway &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./payment-gateway.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; emailService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./email-service.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inventoryService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./inventory-service.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderProcessor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; paymentGateway&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; emailService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inventory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inventoryService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Business rules hardcoded in the constructor.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Someone added these in a hotfix. Nobody documented why.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;discountRules &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;silver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bronze&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taxRate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TAX_RATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0.08&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[OrderProcessor] Processing order for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;customerId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; customer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;customer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Customer not found: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;customerId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stockResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inventory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;stockResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;available&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Insufficient inventory&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; subtotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;sum&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;priceInCents &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; discount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;discountRules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; discountedTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subtotal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; discount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalWithTax &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;discountedTotal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taxRate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paymentResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Payment failed: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inventory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;ord_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;totalInCents&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;confirmed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;createdAt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; savedOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;Order Confirmed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Your order &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; for $&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalWithTax &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; has been confirmed.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[OrderProcessor] Order &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; completed in &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; orderProcessor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; OrderProcessor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderProcessor &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four dependencies wired to global singletons. &lt;code&gt;console.log&lt;/code&gt; as observability. Business rules in a constructor added during a hotfix. &lt;code&gt;require()&lt;/code&gt; at the top of the file, no way to inject alternatives.&lt;/p&gt;
&lt;p&gt;An AI agent will see a class with methods. It’ll mock the constructor, write tests that pass, and produce output that looks correct. But it can’t see the invisible contracts: the payment gateway that rejects amounts over $10,000. The discount rules that were a regulatory requirement. The call ordering that matters because the inventory service has side effects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The agent has the code but not the contract.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It cannot see which paths are load-bearing in production, which edge cases still matter to real users, or which invisible constraints came from compliance, operations, or business reality rather than code aesthetics.&lt;/p&gt;
&lt;p&gt;In legacy systems, the sequence is not write a spec, generate code, run tests. It is observe production, extract behaviour, lock it with tests, then change code safely.&lt;/p&gt;
&lt;h2 id=&quot;characterization-tests-as-archaeology&quot;&gt;Characterization Tests as Archaeology&lt;/h2&gt;
&lt;p&gt;Michael Feathers’ &lt;em&gt;Working Effectively with Legacy Code&lt;/em&gt; introduced characterization tests, written not to verify correct behaviour, but to document current behaviour. You capture what the system does so that when you change something, you can see what moved.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not a goalpost. A tripwire.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Blackfield systems, system tests matter for the same reason characterization tests do: they preserve behaviour when intent is no longer trustworthy.&lt;/p&gt;
&lt;p&gt;A black-box test anchored to user-visible outcomes often survives the decay that kills lower-level tests tied too closely to implementation.&lt;/p&gt;
&lt;p&gt;For our order processor, characterization tests are ugly. They have to be. The code gives us no other choice:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../src/db.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;checkStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../src/payment-gateway.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;paymentGateway&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;refund&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../src/email-service.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;emailService&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../src/inventory-service.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;inventoryService&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;reserve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four &lt;code&gt;jest.mock()&lt;/code&gt; calls before we’ve tested a single thing. In this shape of legacy code, module-level mocking is the only way in—until you create an explicit seam.&lt;/p&gt;
&lt;p&gt;This is exactly the sort of environment where an agent can look productive while misunderstanding the system. It can satisfy mocked tests without discovering the behavioural contracts hidden in call ordering, side effects, and production traffic.&lt;/p&gt;
&lt;p&gt;But now we can lock the contract:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;returns a confirmed order with correctly calculated total&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; processor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEST_CUSTOMER_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TEST_ITEMS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Characterize the current pricing math:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//   subtotal = (2 * 1000) + (1 * 2500) = 4500&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//   gold discount = 15% -&amp;gt; Math.round(4500 * 0.85) = 3825&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//   tax = 8% -&amp;gt; Math.round(3825 * 1.08) = 4131&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalInCents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4131&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;confirmed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;throws when payment fails — and does NOT reserve inventory&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  mockPayment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;charge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Amount exceeds limit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    processor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEST_CUSTOMER_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TEST_ITEMS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rejects&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toThrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Payment failed: Amount exceeds limit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockInventory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reserve&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockDb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;saveOrder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are not the same as old tests that may have drifted. Old tests describe what the system was &lt;em&gt;designed&lt;/em&gt; to do; characterization tests, written now against observed behaviour, describe what it &lt;em&gt;actually&lt;/em&gt; does.&lt;/p&gt;
&lt;p&gt;A green test suite on a Blackfield system is not always confidence. Sometimes it is a fossil record.&lt;/p&gt;
&lt;p&gt;If the code has a bug in the pricing math, these tests enshrine that bug. We fix bugs after we have safe refactoring coverage.&lt;/p&gt;
&lt;p&gt;The point isn’t quality. The point is: &lt;em&gt;don’t make things worse&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-seam-fnargs-deps--defaultdeps&quot;&gt;The Seam: fn(args, deps = defaultDeps)&lt;/h2&gt;
&lt;p&gt;Now we can move. The strangler fig pattern starts here: extract one function at a time from the god class. Give it explicit dependencies. Provide defaults so existing callers keep working.&lt;/p&gt;
&lt;p&gt;I’ll keep everything in CommonJS (&lt;code&gt;require()&lt;/code&gt; / &lt;code&gt;module.exports&lt;/code&gt;) because that’s what most legacy Node.js codebases actually look like. The seam is the point, not the module syntax.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;defaultDeps&lt;/code&gt; object imports the existing singletons, so the class can delegate to this function without any caller knowing:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; defaultDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;amountInCents&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; amount &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; inventoryService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reserve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalInCents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalInCents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;discountRules&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;silver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bronze&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;taxRate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TAX_RATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0.08&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defaultDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; customer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;customer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Customer not found: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;customerId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stockResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;stockResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;available&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Insufficient inventory&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; subtotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;sum&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;priceInCents &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; discount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;discountRules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; discountedTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subtotal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; discount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalWithTax &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;discountedTotal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taxRate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paymentResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Payment failed: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;ord_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;totalInCents&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;confirmed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;createdAt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; savedOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; processOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class can still exist and delegate. In most cases the public call sites don’t need to change, though in real systems, watch for import timing and module side effects that can leak outward.&lt;/p&gt;
&lt;p&gt;Now look at the tests:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;overrides &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cust_1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alice@test.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;loyaltyTier&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;transactionId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;txn_123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockImplementation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;discountRules&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;silver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bronze&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;taxRate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.08&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;overrides&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;processes a successful order with correct total&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;productId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;p1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Widget&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;quantity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;priceInCents&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cust_1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// subtotal = 2000, gold 15% =&amp;gt; 1700, tax 8% =&amp;gt; 1836&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalInCents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1836&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;confirmed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;chargePayment&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cust_1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1836&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;throws on payment failure — stock is never reserved&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Card declined&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cust_1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sampleItems &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rejects&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toThrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Payment failed: Card declined&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reserveStock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No module interception. No &lt;code&gt;jest.mock()&lt;/code&gt;. No constructor ceremony. You mock exactly what the function uses by passing explicit test doubles as data.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;= defaultDeps&lt;/code&gt; is not laziness. It’s a strangler fig — temporary scaffolding that buys you a test seam without breaking existing callers. New callers and tests get clean injection. When every caller has migrated, you remove the default. (The &lt;a href=&quot;https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/&quot;&gt;foundational post&lt;/a&gt; is explicit: defaults are allowed only for migration.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the full pattern, see &lt;a href=&quot;https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/&quot;&gt;If You Only Enforce One Rule for AI Code, Make It fn(args, deps)&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;production-telemetry-is-the-spec-that-survived&quot;&gt;Production Telemetry Is the Spec That Survived&lt;/h2&gt;
&lt;p&gt;When everything else rots (the documentation, the tests, the original ticket) production telemetry is often the most reliable surviving record of behaviour. Users kept showing up. They kept logging in, hitting endpoints, triggering workflows.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; is the extraction pattern that makes legacy code testable; tracing and structured telemetry are what make that behaviour legible enough for humans and agents to change safely.&lt;/p&gt;
&lt;p&gt;Charity Majors has argued for years that production is where you find out how your system actually behaves. Her framing is forward-looking: instrument as you build, observe as you deploy. But the same logic applies backward, to systems that nobody instrumented properly when they were young.&lt;/p&gt;
&lt;p&gt;Telemetry is not a normative spec. It cannot tell you whether behaviour is correct. It can only tell you what behaviour survived contact with production. Production behaviour can encode accidents as readily as intent. But in a legacy system where every other artefact has decayed, observed behaviour is often the safer place to start.&lt;/p&gt;
&lt;p&gt;The deeper question is not just how to observe production, but how to make telemetry queryable as a spec — not as a dashboard, but as a source of truth for safe change. &lt;code&gt;fn(args, deps)&lt;/code&gt; gives us the seam to start adding that telemetry to systems that never had it.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-with-trace&quot;&gt;Wrapping With trace()&lt;/h2&gt;
&lt;p&gt;Now that our functions have the shape &lt;code&gt;fn(args, deps)&lt;/code&gt;, we can wrap them with autotel’s &lt;code&gt;trace()&lt;/code&gt;. The business logic does not change. Existing tests often pass unchanged.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trace &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; processOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defaultDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.customerId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.itemCount&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// ... exact same business logic ...&lt;/span&gt;

  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.totalInCents&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalWithTax&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;customer.loyaltyTier&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; processOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One-time setup in your entry point:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; init &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;order-api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;development&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nested traced functions create child spans automatically:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;processOrder (span)
├── checkInventory (child span)
├── chargePayment (child span)
└── sendConfirmation (child span)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You wrapped it. You didn’t rewrite it. The tests still pass. But now you can see it in production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wire-at-the-boundary&quot;&gt;Wire at the Boundary&lt;/h2&gt;
&lt;p&gt;Once callers have been updated, remove the defaults and wire everything once in a &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createOrderService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findCustomer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;checkInventory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;checkStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkStock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;chargePayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; paymentGateway&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;charge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;sendConfirmation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;sendEmail&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;to&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; emailService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;discountRules&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;silver&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bronze&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;taxRate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TAX_RATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0.08&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createOrderService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The god class is gone. The singletons still exist in &lt;code&gt;infra/&lt;/code&gt; but they’re wired at the boundary, not imported everywhere. The route handler stays clean:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; orderService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createOrderService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/orders&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; orderService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; items &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;201&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-spec-you-can-query&quot;&gt;The Spec You Can Query&lt;/h2&gt;
&lt;p&gt;Here’s the payoff. Three layers of observability, each using real tools:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Span attributes via autotel&lt;/strong&gt;: business context attached to every trace:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.customerId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;customer.loyaltyTier&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.totalInCents&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalInCents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;payment.transactionId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transactionId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Structured logging via pino&lt;/strong&gt;: JSON log lines with scoped context, injected as a dependency:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; log &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;processOrder&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;customerName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;loyaltyTier&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;customer found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; subtotalInCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; discountInCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taxInCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalInCents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;totals calculated&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;transactionId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; paymentResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transactionId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment charged&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalInCents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;order completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Business event tracking via &lt;code&gt;track()&lt;/code&gt;&lt;/strong&gt;: analytics events for downstream consumers:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;track&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; savedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customerId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  totalInCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;itemCount&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;loyaltyTier&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; customer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  discountInCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Structured errors with &lt;code&gt;OrderError&lt;/code&gt;&lt;/strong&gt;: a plain JS class that tells callers &lt;em&gt;why&lt;/em&gt; it failed and &lt;em&gt;how to fix it&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderError&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OrderError&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;why &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;why&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fix&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Payment failed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;402&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;PAYMENT_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;why&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Payment processor declined&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;fix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Try a different payment method&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Together, traces, logs, events, and structured errors turn legacy behaviour from something implicit and anecdotal into something queryable.&lt;/p&gt;
&lt;p&gt;Every log line is JSON. Every span has business attributes. Conceptually, once logs and trace attributes are structured, you can ask questions like:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Find all failed orders for gold customers&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; loyaltyTier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;gold&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Average order value by loyalty tier&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AVG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalInCents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;confirmed&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; loyaltyTier&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-sequence&quot;&gt;The Sequence&lt;/h2&gt;
&lt;p&gt;For legacy systems, the sequence isn’t:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Write a spec → generate code → run tests&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It’s:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Observe production → extract behavioural contracts → encode as tests → use those as the spec → then bring the agent in&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What Changes&lt;/th&gt;
&lt;th&gt;Public API changes?&lt;/th&gt;
&lt;th&gt;What You Get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Nothing. This is the mess&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Starting point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Add characterization tests&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Behavioural lock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Extract to &lt;code&gt;fn(args, deps = defaultDeps)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Usually none&lt;/td&gt;
&lt;td&gt;Testable seams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Wrap with &lt;code&gt;trace()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Remove defaults, wire at boundary&lt;/td&gt;
&lt;td&gt;Callers update at boundary&lt;/td&gt;
&lt;td&gt;Clean architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Structured logging + actionable errors&lt;/td&gt;
&lt;td&gt;Error shapes change&lt;/td&gt;
&lt;td&gt;Observable system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;UUID IDs, webhook notifier, config&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Features on a clean codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Steps 0–5 are the refactoring. Step 6 is the payoff: three features land safely because the architecture supports them: UUID order IDs (one line change), a webhook notifier (new domain function + feature flag in the composition root), and centralized config. None of them touch existing domain code. None of them break existing tests.&lt;/p&gt;
&lt;p&gt;That’s the whole point. You don’t refactor for the sake of refactoring. You refactor so that the next feature is easy.&lt;/p&gt;
&lt;p&gt;The tools already exist: characterization tests, strangler figs, contract testing, observability. The legacy code community discovered them before AI entered the picture. The point is not to invent a new discipline for agents. It is to carry forward the disciplines that made legacy change survivable in the first place.&lt;/p&gt;
&lt;p&gt;We hand agents the codebase, the tests, the docs, the specs, the commit history. But in legacy systems, the most trustworthy surviving artefact is often runtime behaviour itself.&lt;/p&gt;
&lt;p&gt;Capture that behaviour as structured, queryable context, and the system becomes legible again — to humans first, and then to agents.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;The ideas in this piece draw on Michael Feathers’ &lt;a href=&quot;https://www.oreilly.com/library/view/working-effectively-with/0131177052/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt; (characterization tests, seams, the legacy code change algorithm), Joost Visser’s &lt;a href=&quot;https://www.oreilly.com/library/view/building-maintainable-software/9781491955987/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Building Maintainable Software&lt;/a&gt; (maintainability guidelines, loose coupling), and x(&lt;a href=&quot;https://charity.wtf/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://charity.wtf/&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>What `fn(args, deps)` actually gives you in DDD-style TypeScript</title><link>https://arrangeactassert.com/posts/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Domain-Driven Design comes with a lot of vocabulary: aggregates, repositories, domain services, bounded contexts, ubiquitous language, anemic models.&lt;/p&gt;
&lt;p&gt;That vocabulary can make DDD sound heavier than it really is.&lt;/p&gt;
&lt;p&gt;The useful idea is simpler: keep domain behavior and domain boundaries central, and keep infrastructure, persistence, and framework wiring secondary.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; does not do that modeling for you. What it gives you is a clear shape for application-layer code in TypeScript: one place for use-case input, one place for collaborators, and less room for domain decisions to drift into wiring.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;fn(args, deps) and Domain-Driven Design&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2076px) 2076px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2076&quot; height=&quot;1296&quot; src=&quot;https://arrangeactassert.com/_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_Z29y0VJ.webp&quot; srcset=&quot;/_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_sBC6V.webp 640w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_Z4rC4T.webp 750w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_Z279cY5.webp 828w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_2lz8ww.webp 1080w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_824kq.webp 1280w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_Z2cdB8T.webp 1668w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_ZCiqFg.webp 2048w, /_astro/what-fn-args-deps-actually-gives-you-in-ddd-style-typescript.4A4pGy0q_Z29y0VJ.webp 2076w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;ddd-as-pressure-not-prescription&quot;&gt;DDD as pressure, not prescription&lt;/h2&gt;
&lt;p&gt;A lot of DDD discussions get pulled into implementation details too early.&lt;/p&gt;
&lt;p&gt;People hear “DDD” and picture layered systems, elaborate abstractions, or class-heavy code full of patterns used more out of loyalty than necessity.&lt;/p&gt;
&lt;p&gt;That is not the useful part.&lt;/p&gt;
&lt;p&gt;The useful pressure from DDD is much more direct:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;focus on the language of the domain&lt;/li&gt;
&lt;li&gt;protect important invariants&lt;/li&gt;
&lt;li&gt;define boundaries around aggregates&lt;/li&gt;
&lt;li&gt;keep infrastructure secondary to business behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That pressure matters whether your code uses classes, plain objects, pure functions, or a mix.&lt;/p&gt;
&lt;p&gt;This is where &lt;code&gt;fn(args, deps)&lt;/code&gt; becomes useful.&lt;/p&gt;
&lt;p&gt;Not as a substitute for DDD, but as a repeatable way to structure application code around the model instead of around the framework.&lt;/p&gt;
&lt;p&gt;That is a narrower claim than “this is DDD,” but it is also the more useful one.&lt;/p&gt;
&lt;h2 id=&quot;aggregates-and-invariants-in-typescript&quot;&gt;Aggregates and invariants in TypeScript&lt;/h2&gt;
&lt;p&gt;In plain terms, an aggregate is a consistency boundary.&lt;/p&gt;
&lt;p&gt;It is a boundary around related domain state that must remain valid through rules enforced by a single root. The aggregate root is the entry point through which those invariants are protected.&lt;/p&gt;
&lt;p&gt;That sounds abstract, so here is a small example.&lt;/p&gt;
&lt;p&gt;Imagine an order that can contain line items, can be cancelled, and can be shipped. One invariant might be that a cancelled order cannot be shipped.&lt;/p&gt;
&lt;p&gt;Another might be that you cannot add lines once the order has shipped.&lt;/p&gt;
&lt;p&gt;In TypeScript, that does not require a giant inheritance hierarchy. The domain model can stay small and direct.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderStatus&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;draft&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;placed&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cancelled&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;shipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderLine&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  productId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  quantity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OrderId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OrderStatus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  lines&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OrderLine&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; addLine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OrderLine&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;shipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot add lines to a shipped order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cancelled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot add lines to a cancelled order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;quantity &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Quantity must be greater than zero&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    lines&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ship &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cancelled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot ship a cancelled order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot ship an order with no lines&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;shipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In production code, I would usually prefer explicit domain error types over generic &lt;code&gt;Error&lt;/code&gt; values, but &lt;code&gt;Error&lt;/code&gt; keeps the examples smaller here.&lt;/p&gt;
&lt;p&gt;This is already recognizable as domain logic.&lt;/p&gt;
&lt;p&gt;The important point is not whether this is written as a class or as pure functions over a value.&lt;/p&gt;
&lt;p&gt;The important point is that the rules live with the domain behavior, not buried in controllers, handlers, or database code.&lt;/p&gt;
&lt;p&gt;That part is standard DDD. The more interesting question is what happens once an application use case has to load that model, persist it, and coordinate what comes next.&lt;/p&gt;
&lt;h2 id=&quot;where-fnargs-deps-actually-helps&quot;&gt;Where &lt;code&gt;fn(args, deps)&lt;/code&gt; actually helps&lt;/h2&gt;
&lt;p&gt;In a DDD-influenced system, &lt;code&gt;fn(args, deps)&lt;/code&gt; fits most naturally in the application layer.&lt;/p&gt;
&lt;p&gt;That means it acts like a use case or application service. It loads an aggregate, invokes domain behavior, persists the result, and coordinates side effects.&lt;/p&gt;
&lt;p&gt;If you like the “inside vs outside” framing, this is the same boundary idea as &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;hexagonal architecture&lt;/a&gt;. The wiring still happens at the edge in a &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That last part matters.&lt;/p&gt;
&lt;p&gt;The function shape is helpful only if the application layer stays a coordinator. The model should still carry the meaning of the business rules.&lt;/p&gt;
&lt;p&gt;A simple &lt;code&gt;shipOrder(args, deps)&lt;/code&gt; might look like this:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShipOrderArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShipOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Order &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  domainEvents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shipOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Order not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shippedOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ship&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainEvents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OrderShipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a clean split here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;args&lt;/code&gt; is command-shaped input&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deps&lt;/code&gt; contains infrastructure-facing collaborators&lt;/li&gt;
&lt;li&gt;the domain rule stays in domain behavior&lt;/li&gt;
&lt;li&gt;the function itself orchestrates the use case&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For teams that want clear boundaries without a heavy framework or a class hierarchy, that is already a meaningful improvement.&lt;/p&gt;
&lt;h2 id=&quot;avoiding-anemic-domain-models-without-overcorrecting&quot;&gt;Avoiding anemic domain models without overcorrecting&lt;/h2&gt;
&lt;p&gt;One of the standard critiques in DDD discussions is the anemic domain model: objects that carry data while the important decisions live elsewhere.&lt;/p&gt;
&lt;p&gt;That critique is still useful.&lt;/p&gt;
&lt;p&gt;But there is also a common overcorrection where people assume every bit of behavior must live on a large entity class or the design has somehow failed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; helps with the first problem without forcing the second.&lt;/p&gt;
&lt;p&gt;Here is the weak version:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CancelOrderArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CancelOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Order &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cancelOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CancelOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CancelOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Order not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;shipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot cancel a shipped order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot cancel an empty order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cancelled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works, but the use case is making domain decisions directly.&lt;/p&gt;
&lt;p&gt;The order is mostly a data bag.&lt;/p&gt;
&lt;p&gt;When that happens repeatedly, the code may use DDD vocabulary without really letting the domain model do domain work.&lt;/p&gt;
&lt;p&gt;A better version moves the decision back into domain behavior:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cancel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;shipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot cancel a shipped order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lines&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot cancel an empty order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cancelled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cancelOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CancelOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CancelOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Order not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the distinction that matters.&lt;/p&gt;
&lt;p&gt;The point of the pattern is not to drag decisions upward into orchestration. It is to keep orchestration honest while leaving the rules with the model.&lt;/p&gt;
&lt;h2 id=&quot;aggregate-boundaries-become-easier-to-see&quot;&gt;Aggregate boundaries become easier to see&lt;/h2&gt;
&lt;p&gt;One practical side effect of &lt;code&gt;fn(args, deps)&lt;/code&gt; is that aggregate boundaries become easier to see.&lt;/p&gt;
&lt;p&gt;In DDD-style systems, repositories are often modeled around aggregate roots. That means the dependency list for a use case often acts as feedback on the shape of the model.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ApproveInvoiceDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  invoices&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; InvoiceRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  customers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CustomerRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  creditPolicies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreditPolicyService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  outbox&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OutboxWriter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes that is perfectly reasonable.&lt;/p&gt;
&lt;p&gt;Sometimes it is a warning sign.&lt;/p&gt;
&lt;p&gt;If a single use case keeps needing multiple repositories, cross-aggregate reads, extra coordination services, and transaction workarounds, the code is often telling you something about the boundary you picked.&lt;/p&gt;
&lt;p&gt;That is one of the more practical benefits of the pattern.&lt;/p&gt;
&lt;p&gt;Because dependencies are explicit, awkward boundaries become harder to ignore. Instead of disappearing into injected class state or framework wiring, the complexity stays visible in the use case signature.&lt;/p&gt;
&lt;p&gt;That is useful in code review, in refactoring, and in the earlier stages of figuring out where aggregate boundaries really belong.&lt;/p&gt;
&lt;h2 id=&quot;transactions-are-where-reality-starts&quot;&gt;Transactions are where reality starts&lt;/h2&gt;
&lt;p&gt;This is also where the pattern stops being self-explanatory.&lt;/p&gt;
&lt;p&gt;The earlier &lt;code&gt;shipOrder(args, deps)&lt;/code&gt; example is fine as a teaching example, but real systems have to care about failure between steps. If &lt;code&gt;orders.save&lt;/code&gt; succeeds and &lt;code&gt;outbox.append&lt;/code&gt; fails, you have now persisted new state without recording the event the rest of the system may depend on.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; does not solve that problem by itself.&lt;/p&gt;
&lt;p&gt;What it does do is give you an obvious place to model the transactional boundary explicitly:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShipOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;withTransaction&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      orders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Order &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      outbox&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shipOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withTransaction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Order not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shippedOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ship&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OrderShipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can model that as a unit of work, a transaction wrapper, an outbox writer inside a transaction, or something equivalent.&lt;/p&gt;
&lt;p&gt;The abstraction can vary. What matters is that transaction coordination is an explicit application-layer decision, not an invisible assumption.&lt;/p&gt;
&lt;h2 id=&quot;domain-events-are-a-design-choice-not-a-freebie&quot;&gt;Domain events are a design choice, not a freebie&lt;/h2&gt;
&lt;p&gt;Domain events are another place where &lt;code&gt;fn(args, deps)&lt;/code&gt; fits naturally.&lt;/p&gt;
&lt;p&gt;Some teams model domain events as part of the domain result. Others derive them in the application layer after a domain operation. Either way, &lt;code&gt;fn(args, deps)&lt;/code&gt; gives you a clear place to persist state and then hand those events to an explicit dependency such as an event publisher or outbox writer.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SaveResult&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shipWithEvents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SaveResult &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shippedOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ship&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OrderShipped&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; shippedOrder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShipOrderWithOutboxDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Order &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  outbox&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shipOrderWithOutbox &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ShipOrderWithOutboxDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Order not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shipWithEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;order&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outbox&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;events&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this version, the domain operation returns events rather than storing them on the aggregate itself.&lt;/p&gt;
&lt;p&gt;That is a design choice, not a law of DDD.&lt;/p&gt;
&lt;p&gt;Some teams prefer aggregates to collect events internally and expose them after the operation. In function-oriented code, returning the events directly often keeps side effects more visible and avoids hidden mutable state. But that is a stylistic preference, not something the domain model forced on you.&lt;/p&gt;
&lt;p&gt;The main win is simpler than that: the eventing concern stays explicit without smuggling infrastructure mechanics into every domain type.&lt;/p&gt;
&lt;h2 id=&quot;keep-typescript-dependency-typing-practical&quot;&gt;Keep TypeScript dependency typing practical&lt;/h2&gt;
&lt;p&gt;One fair criticism of this style is that dependency typing can get repetitive in large codebases.&lt;/p&gt;
&lt;p&gt;If every use case hand-writes an inline repository shape with &lt;code&gt;getById&lt;/code&gt; and &lt;code&gt;save&lt;/code&gt;, the code stays explicit but starts to feel noisy.&lt;/p&gt;
&lt;p&gt;That is usually a sign to standardize the building blocks without giving up the narrow dependency surface:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Repository&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;getById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShipOrderDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pick&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Repository&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Order&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;getById&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;save&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  outbox&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OutboxWriter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That keeps the use case honest about what it needs while avoiding copy-pasting the same method signatures across dozens of files.&lt;/p&gt;
&lt;p&gt;The useful constraint is not “write every dependency type from scratch forever.”&lt;/p&gt;
&lt;p&gt;The useful constraint is “make dependencies explicit and keep them narrower than the whole container.”&lt;/p&gt;
&lt;h2 id=&quot;why-teams-tend-to-like-this-shape&quot;&gt;Why teams tend to like this shape&lt;/h2&gt;
&lt;p&gt;The appeal is not theoretical purity. It is consistency.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;useCase(args, deps)&lt;/code&gt; gives teams a predictable entry point, makes collaborators easy to inspect, keeps testing straightforward, and exposes anemic designs by making repeated decisions easier to notice.&lt;/p&gt;
&lt;p&gt;In practice, that means less hunting through framework wiring to figure out where a business action starts and what it actually depends on.&lt;/p&gt;
&lt;h2 id=&quot;where-this-pattern-stops&quot;&gt;Where this pattern stops&lt;/h2&gt;
&lt;p&gt;It is worth being precise here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; does not solve strategic DDD. It does not define bounded contexts, create a ubiquitous language, discover aggregate boundaries, or model long-running workflows for you.&lt;/p&gt;
&lt;p&gt;And tidy function signatures definitely do not guarantee a good domain model.&lt;/p&gt;
&lt;p&gt;Those things still require domain knowledge, modeling effort, and iteration.&lt;/p&gt;
&lt;p&gt;Once a business process crosses multiple aggregates, multiple transactions, or multiple services, a tidy &lt;code&gt;useCase(args, deps)&lt;/code&gt; per step is no longer the whole story. You now need workflow coordination, retry behavior, idempotency, and eventual consistency concerns that live above a single aggregate use case.&lt;/p&gt;
&lt;p&gt;That is not a failure of the pattern. It is just the boundary of what the pattern is for.&lt;/p&gt;
&lt;p&gt;What this pattern does give you is a low-ceremony way to express application-layer decisions clearly once you have started making them.&lt;/p&gt;
&lt;h2 id=&quot;why-this-still-matters&quot;&gt;Why this still matters&lt;/h2&gt;
&lt;p&gt;DDD is about domain focus, domain language, and domain boundaries.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; does not do that work for you. What it does do is give the work a clear place to live: domain rules in domain behavior, coordination in the application layer, and infrastructure at the edges.&lt;/p&gt;
&lt;p&gt;None of this removes the need to model responsibilities well inside the domain; it only gives those responsibilities a cleaner application boundary.&lt;/p&gt;
&lt;p&gt;That is a modest promise, but in real TypeScript systems it is often the difference between code that merely mentions DDD and code that can actually support it.&lt;/p&gt;
</content:encoded></item><item><title>fn(args, deps) and Hexagonal Architecture</title><link>https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Hexagonal architecture often gets introduced with a lot of diagrams, vocabulary, and ceremony.&lt;/p&gt;
&lt;p&gt;Ports.
Adapters.
Application core.
Inbound and outbound boundaries.&lt;/p&gt;
&lt;p&gt;That framing is useful, but it can also make the idea feel more abstract than it really is.&lt;/p&gt;
&lt;div&gt;
  &lt;img
    src=&quot;https://arrangeactassert.com/static/images/fn-args-deps-and-hexagonal-architecture.png&quot;
    alt=&quot;fn(args, deps) and hexagonal architecture&quot;
    class=&quot;w-full h-auto bg-white&quot;
  /&gt;
&lt;/div&gt;
&lt;p&gt;You may also hear this called “ports and adapters” — same idea, different name. The port is what a function needs; the adapter is what fulfils it.&lt;/p&gt;
&lt;p&gt;A simpler way to understand it is this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hexagonal architecture is mostly about keeping business logic independent from delivery and infrastructure details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One practical way to do that in plain TypeScript is this shape:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;args&lt;/code&gt; is the input for this use case, and &lt;code&gt;deps&lt;/code&gt; is the set of external capabilities it needs.
You can read that as: data in, capabilities in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In plain TypeScript, &lt;code&gt;fn(args, deps)&lt;/code&gt; is a simple way to implement the core idea of hexagonal architecture without turning the pattern into ceremony.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-real-point-of-hexagonal-architecture&quot;&gt;The real point of hexagonal architecture&lt;/h2&gt;
&lt;p&gt;A lot of explanations make hexagonal architecture sound like the point is drawing a boundary around “the domain.”&lt;/p&gt;
&lt;p&gt;That is not wrong, but it is incomplete.&lt;/p&gt;
&lt;p&gt;The real point is to stop business logic from being tangled up with transport, frameworks, and infrastructure.&lt;/p&gt;
&lt;p&gt;You do not want your core use case to care whether it was called from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP&lt;/li&gt;
&lt;li&gt;a CLI&lt;/li&gt;
&lt;li&gt;a queue consumer&lt;/li&gt;
&lt;li&gt;a cron job&lt;/li&gt;
&lt;li&gt;a test&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And you do not want it tightly coupled to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a specific database client&lt;/li&gt;
&lt;li&gt;a specific mail provider&lt;/li&gt;
&lt;li&gt;a framework request object&lt;/li&gt;
&lt;li&gt;a logger singleton&lt;/li&gt;
&lt;li&gt;process-wide global state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the architectural problem hexagonal architecture is trying to solve.&lt;/p&gt;
&lt;h2 id=&quot;a-use-case-can-just-be-a-function&quot;&gt;A use case can just be a function&lt;/h2&gt;
&lt;p&gt;In plain TypeScript, a use case does not need to be a class to have a boundary.&lt;/p&gt;
&lt;p&gt;It can just be a function.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;User&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; meta&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Creating user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;saveUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That function already has the important boundary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;args&lt;/code&gt; is what the use case needs from the caller&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deps&lt;/code&gt; is what the use case needs from the outside world&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is a very direct way to express the “inside versus outside” split that hexagonal architecture cares about.&lt;/p&gt;
&lt;h2 id=&quot;args-and-deps-map-cleanly-to-the-hexagon&quot;&gt;args and deps map cleanly to the hexagon&lt;/h2&gt;
&lt;p&gt;This is the useful connection.&lt;/p&gt;
&lt;p&gt;In hexagonal architecture, people often talk about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;inbound adapters&lt;/li&gt;
&lt;li&gt;outbound adapters&lt;/li&gt;
&lt;li&gt;ports&lt;/li&gt;
&lt;li&gt;the application core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those ideas can sound bigger than they are.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;fn(args, deps)&lt;/code&gt;, the mapping is usually straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;args&lt;/code&gt; comes from an inbound adapter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deps&lt;/code&gt; is implemented by outbound adapters&lt;/li&gt;
&lt;li&gt;the function body is the application core&lt;/li&gt;
&lt;li&gt;the function signature is the boundary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those adapters get assembled at the application edge — your &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an HTTP handler can translate a request into &lt;code&gt;args&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a Postgres repository can implement part of &lt;code&gt;deps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;an email provider can implement part of &lt;code&gt;deps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the use case itself stays unaware of Express, Fastify, Postgres, or SES&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is hexagonal architecture in practice, not just in a diagram.&lt;/p&gt;
&lt;h2 id=&quot;the-http-layer-becomes-an-adapter-not-the-center&quot;&gt;The HTTP layer becomes an adapter, not the center&lt;/h2&gt;
&lt;p&gt;Here is a simple HTTP adapter:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../application/create-user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeCreateUserDeps &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../composition-root&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postUsersHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeCreateUserDeps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;201&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The handler does three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reads transport-specific input&lt;/li&gt;
&lt;li&gt;calls the use case&lt;/li&gt;
&lt;li&gt;translates the result back to transport-specific output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is adapter work.&lt;/p&gt;
&lt;p&gt;The business logic is not in the handler. The handler is not the center of the system. It is just one way into the core.&lt;/p&gt;
&lt;p&gt;That is one of the biggest practical wins of hexagonal architecture: the delivery mechanism becomes replaceable.&lt;/p&gt;
</content:encoded></item><item><title>Composition Roots and fn(args, deps)</title><link>https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/</guid><pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;A lot of developers hear “dependency injection” and immediately think of containers, decorators, registration APIs, lifecycle scopes, and framework magic.&lt;/p&gt;
&lt;p&gt;That reaction is understandable.&lt;/p&gt;
&lt;p&gt;But that association often leads people to overcomplicate a problem that has a much simpler starting point.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Composition roots and fn(args, deps)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1670px) 1670px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1670&quot; height=&quot;550&quot; src=&quot;https://arrangeactassert.com/_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_qUENc.webp&quot; srcset=&quot;/_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_GPOgu.webp 640w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_26hfxt.webp 750w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_jaad1.webp 828w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_2aOh8h.webp 1080w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_2lJeXB.webp 1280w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_1407ak.webp 1668w, /_astro/composition-roots-and-fn-args-deps.Bm4yRfMA_qUENc.webp 1670w&quot;&gt;&lt;/p&gt;
&lt;p&gt;At its core, dependency injection just means this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pass collaborators in explicitly instead of reaching for them implicitly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of the simplest ways to do that in plain TypeScript is this shape (introduced in the series starting point: &lt;a href=&quot;https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/&quot;&gt;fn(args, deps)&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;args&lt;/code&gt; is call-specific input and &lt;code&gt;deps&lt;/code&gt; is the set of collaborators the function needs.&lt;/p&gt;
&lt;p&gt;You can read that as: data in, capabilities in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fn(args, deps)&lt;/code&gt; is flexible enough to support composition, testing, and clean application wiring without forcing you into a DI framework.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-explicit-dependencies-matter&quot;&gt;Why explicit dependencies matter&lt;/h2&gt;
&lt;p&gt;Consider a function like this:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Database&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Mailer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Creating user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendWelcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The signature tells you almost everything you need to know about this function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what input the function needs&lt;/li&gt;
&lt;li&gt;what external capabilities it relies on&lt;/li&gt;
&lt;li&gt;what has to be provided in tests&lt;/li&gt;
&lt;li&gt;what has to be wired at the edge of the app&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nothing is hidden in global state.
Nothing is implied through a class instance.
Nothing relies on framework wiring happening somewhere else.&lt;/p&gt;
&lt;p&gt;That explicitness is the payoff.&lt;/p&gt;
&lt;h2 id=&quot;this-is-just-a-function-shape-not-a-framework&quot;&gt;This is just a function shape, not a framework&lt;/h2&gt;
&lt;p&gt;fn(args, deps) is not a DI framework.&lt;/p&gt;
&lt;p&gt;It does not require a container, decorators, runtime lookup, reflection, registration, or auto-wiring:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is just a function with explicit collaborators, and that is exactly why it is useful.&lt;/p&gt;
&lt;p&gt;If you can call a function, you already know how to use this pattern.&lt;/p&gt;
&lt;p&gt;In many TypeScript codebases, that is enough, and it is often better than introducing a container prematurely.&lt;/p&gt;
&lt;h2 id=&quot;the-composition-root-is-where-the-wiring-happens&quot;&gt;The composition root is where the wiring happens&lt;/h2&gt;
&lt;p&gt;fn(args, deps) does not mean manually passing dependencies through every layer forever.&lt;/p&gt;
&lt;p&gt;The function stays explicit about what it needs. The application satisfies those dependencies at the edge.&lt;/p&gt;
&lt;p&gt;That edge is your composition root.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// main.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./create-user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeDb &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/db&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeMailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/mailer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; makeLogger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./infra/logger&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DATABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mailer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeMailer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeLogger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; productionDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  productionDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That startup file is the composition root, the place where infrastructure gets created and connected to application logic.&lt;/p&gt;
&lt;p&gt;In a CLI, this might be &lt;code&gt;bin/main.ts&lt;/code&gt;. In a web application, it might be the HTTP server bootstrap or the framework entrypoint.&lt;/p&gt;
&lt;p&gt;It is usually worth creating small factory functions for reusable infrastructure, things like &lt;code&gt;makeLogger&lt;/code&gt;, &lt;code&gt;makeDb&lt;/code&gt;, and &lt;code&gt;makeMailer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These are the primitive building blocks of the composition root: small functions that construct infrastructure without mixing in domain logic.&lt;/p&gt;
&lt;p&gt;They give the composition root reusable infrastructure pieces, while &lt;code&gt;fn(args, deps)&lt;/code&gt; shows how those pieces are combined into application logic.&lt;/p&gt;
&lt;h2 id=&quot;bind-dependencies-when-it-helps-ergonomics&quot;&gt;Bind dependencies when it helps ergonomics&lt;/h2&gt;
&lt;p&gt;If you do not want every call site to pass both args and deps, bind dependencies once and expose a simpler function:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;makeCreateUser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then at the composition root:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createUserWithServices &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;makeCreateUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUserWithServices&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tests can still call the base function directly:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ada&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ada@example.com&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fakeDb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fakeMailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fakeLogger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pattern supports direct calls, partial application, and pre-wired functions without hiding the dependency boundary.&lt;/p&gt;
&lt;p&gt;If you bind every function eagerly you can end up with a forest of factories. Reach for &lt;code&gt;makeX&lt;/code&gt; when there are multiple call sites or when you are crossing a boundary such as from routes or controllers into domain logic. Otherwise, calling &lt;code&gt;fn(args, deps)&lt;/code&gt; directly is fine.&lt;/p&gt;
&lt;h2 id=&quot;when-plain-imports-are-better&quot;&gt;When plain imports are better&lt;/h2&gt;
&lt;p&gt;Not every dependency needs to be injected.&lt;/p&gt;
&lt;p&gt;For pure helpers with no side effects, direct imports are usually simpler:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; normalizeEmail &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./normalize-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toUserRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CreateUserArgs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Passing it through &lt;code&gt;deps&lt;/code&gt; would add ceremony without much value.&lt;/p&gt;
&lt;p&gt;A useful rule of thumb (also echoed in the &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-solid-principles/&quot;&gt;SOLID post&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use direct imports for pure logic&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;deps&lt;/code&gt; for things that touch the outside world, vary by environment, or matter in tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can think of &lt;code&gt;deps&lt;/code&gt; as the things that talk to the world or differ by environment. Pure helpers are regular imports, not missing dependencies.&lt;/p&gt;
&lt;h2 id=&quot;what-this-pattern-prevents&quot;&gt;What this pattern prevents&lt;/h2&gt;
&lt;p&gt;A lot of the value comes from the mistakes it makes harder to hide.&lt;/p&gt;
&lt;p&gt;When dependencies are explicit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hidden coupling is harder to introduce&lt;/li&gt;
&lt;li&gt;tests are easier to write honestly&lt;/li&gt;
&lt;li&gt;dependency growth shows up in the signature&lt;/li&gt;
&lt;li&gt;wiring lives at the edge instead of being smeared across the codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compare these two versions:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Hidden dependency: reaches into infrastructure directly&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../infra/db&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUserHidden&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Explicit dependency: db is part of the signature&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUserExplicit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Database &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the first version, tests have to mock the module import or spin up a real database. In the second, you pass in whatever you want.&lt;/p&gt;
&lt;h2 id=&quot;the-real-case-for-fnargs-deps&quot;&gt;The real case for fn(args, deps)&lt;/h2&gt;
&lt;p&gt;The case for this pattern is simple: it keeps dependencies explicit, wiring honest, and complexity optional.&lt;/p&gt;
&lt;p&gt;Used consistently, it gives you a codebase where side effects are visible in signatures, tests are straightforward to wire, and application assembly happens in one honest place.&lt;/p&gt;
&lt;p&gt;That is the appeal of &lt;code&gt;fn(args, deps)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In plain TypeScript, it is a better default than reaching for framework-style DI before your code actually demands it.&lt;/p&gt;
</content:encoded></item><item><title>AI Makes It Easy to Build. That Doesn’t Mean We Should Ship More</title><link>https://arrangeactassert.com/posts/ai-makes-it-easy-to-build-that-doesnt-mean-we-should-ship-more/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-makes-it-easy-to-build-that-doesnt-mean-we-should-ship-more/</guid><pubDate>Thu, 12 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Dax is spot on.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;sent this to the team today&lt;br&gt;&lt;br&gt;everything great comes from being able to delay gratification for as long as possible&lt;br&gt;&lt;br&gt;and it feels like we&amp;#39;re collectively losing our ability to do that &lt;a href=&quot;https://t.co/HlIpY86eJn&quot;&gt;pic.twitter.com/HlIpY86eJn&lt;/a&gt;&lt;/p&gt;&amp;mdash; dax (@thdxr) &lt;a href=&quot;https://twitter.com/thdxr/status/2031377117007454421?ref_src=twsrc%5Etfw&quot;&gt;March 10, 2026&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;A couple of weeks ago, I attended the Cambridge Product Management meetup.&lt;/p&gt;
&lt;p&gt;During a discussion, someone said their company had given everyone AI tools and that they were now shipping faster than ever.&lt;/p&gt;
&lt;p&gt;I told him that it risked being irresponsible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When it becomes trivial to build things, the bar for what deserves to ship often drops.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Suddenly, every idea can become a feature.&lt;/p&gt;
&lt;p&gt;First, bombarding users with constant changes is confusing. Even with feature flags. If every time someone opens your product, something has changed, you risk frustrating them rather than helping them.&lt;/p&gt;
&lt;p&gt;Second, features need time to bed in.&lt;/p&gt;
&lt;p&gt;You need time to explain them: marketing, emails, videos, blog posts, support docs.&lt;/p&gt;
&lt;p&gt;You cannot compress this process.&lt;/p&gt;
&lt;p&gt;Like a good wine, some things simply take time. You need an inspect-and-adapt loop that produces insights you can actually base decisions on.&lt;/p&gt;
&lt;p&gt;Just because AI makes it easier to build things doesn’t mean we should ship more of them.&lt;/p&gt;
&lt;p&gt;Everything great comes from delaying gratification.&lt;/p&gt;
</content:encoded></item><item><title>When it comes to using AI, be like Luke</title><link>https://arrangeactassert.com/posts/when-it-comes-to-using-ai-be-like-luke/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/when-it-comes-to-using-ai-be-like-luke/</guid><pubDate>Mon, 09 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I love using AI coding tools. As someone who definitely gets their money’s worth, I feel more productive than ever.&lt;/p&gt;
&lt;p&gt;But sometimes, just like Obi-Wan told Luke, you need to let go.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;When it comes to using AI, be like Luke&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 832px) 832px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;832&quot; height=&quot;1248&quot; src=&quot;https://arrangeactassert.com/_astro/when-it-comes-to-using-ai-be-like-luke.B9FSlYWd_Z1yk7yh.webp&quot; srcset=&quot;/_astro/when-it-comes-to-using-ai-be-like-luke.B9FSlYWd_ZVT2wO.webp 640w, /_astro/when-it-comes-to-using-ai-be-like-luke.B9FSlYWd_A5Hww.webp 750w, /_astro/when-it-comes-to-using-ai-be-like-luke.B9FSlYWd_SFTz7.webp 828w, /_astro/when-it-comes-to-using-ai-be-like-luke.B9FSlYWd_Z1yk7yh.webp 832w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Control the instinct to reach for AI all the time.&lt;/p&gt;
&lt;p&gt;Trust yourself.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Yes, AI can help you ship faster. I feel that too. But if every hard problem is handed off to a tool, you slowly lose the feel for the craft. The ability to reason through a problem, explore the codebase, and figure things out.&lt;/p&gt;
&lt;p&gt;One way I like to mix things up is through Software Craftsmanship meetups.&lt;/p&gt;
&lt;p&gt;At my local Cambridge meetup, we sometimes pair up and work through coding activities using good old pair programming.&lt;/p&gt;
&lt;p&gt;The last time I did this, we switched off the AI completely and just enjoyed solving the problem together.&lt;/p&gt;
&lt;p&gt;No copilots. No prompts. Just thinking, experimenting, and learning.&lt;/p&gt;
&lt;p&gt;And that’s the thing. Sometimes stepping away from the tools reminds you why you enjoyed programming in the first place.&lt;/p&gt;
&lt;p&gt;Stretch those muscles. Don’t become stiff and stale.&lt;/p&gt;
</content:encoded></item><item><title>Why Matt Pocock Is Right About Making Codebases AI Agents Love</title><link>https://arrangeactassert.com/posts/why-matt-pocock-is-right-about-making-codebases-ai-agents-love/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/why-matt-pocock-is-right-about-making-codebases-ai-agents-love/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Matt Pocock is once again on the money in his video “How To Make Codebases AI Agents Love”.&lt;/p&gt;
&lt;iframe
  src=&quot;https://www.youtube.com/embed/uC44zFz7JSM&quot;
  style=&quot;width:100%; aspect-ratio:16/9;&quot;
  title=&quot;YouTube video player&quot;
  frameborder=&quot;0&quot;
  allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;Here’s why I agree with him.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;The Memento analogy for how AI sees a codebase is spot on. And the idea of deep modules as progressive disclosure of complexity makes a lot of sense.&lt;/p&gt;
&lt;p&gt;One thing that has worked well for me, especially when using AI coding agents on legacy codebases, is enforcing a simple code constraint.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defaultDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a non-breaking change, and it has proven very reliable.&lt;/p&gt;
&lt;p&gt;I wrote about it here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/&quot;&gt;If You Only Enforce One Rule for AI Generated Code, Make It fn(args, deps)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When he said “the interface sits at the top and explains what the module does”, that idea translates nicely inside the module too.&lt;/p&gt;
&lt;p&gt;The Deps type makes the dependency boundary explicit (the same “inside vs outside” idea as &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;ports and adapters&lt;/a&gt;). It says exactly what the function needs from the outside world. The AI reads the contract first instead of guessing which collaborators exist or which ones matter.&lt;/p&gt;
&lt;p&gt;It also makes testing simpler. Dependencies are visible. Interfaces stay small. You can hold a few of them in your head and let the AI handle the implementation within the module.&lt;/p&gt;
&lt;p&gt;This aligns with his point that what works for humans also works for AI.&lt;/p&gt;
&lt;p&gt;Making dependencies explicit is not clever. It is boring.&lt;/p&gt;
&lt;p&gt;But boring constraints are what let both humans and agents reason about the code.&lt;/p&gt;
</content:encoded></item><item><title>If You Only Enforce One Rule for AI Code, Make It fn(args, deps)</title><link>https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/one-rule-for-ai-code-fn-args-deps/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;AI coding agents produce code faster than you can review and understand it.&lt;/p&gt;
&lt;p&gt;One pattern works in both new and legacy codebases because you can adopt it incrementally, without breaking callers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;fn(args, deps) is all you need&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 888px) 888px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;888&quot; height=&quot;499&quot; src=&quot;https://arrangeactassert.com/_astro/one-rule-for-ai-code-fn-args-deps.9EhX_iaO_Zl7VGi.webp&quot; srcset=&quot;/_astro/one-rule-for-ai-code-fn-args-deps.9EhX_iaO_Z253gRJ.webp 640w, /_astro/one-rule-for-ai-code-fn-args-deps.9EhX_iaO_Z21BwGY.webp 750w, /_astro/one-rule-for-ai-code-fn-args-deps.9EhX_iaO_1evI6q.webp 828w, /_astro/one-rule-for-ai-code-fn-args-deps.9EhX_iaO_Zl7VGi.webp 888w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For business logic, treat every function as having two inputs: data (&lt;code&gt;args&lt;/code&gt;) and capabilities (&lt;code&gt;deps&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Without a clear constraint, generated code becomes harder to reason about: dependencies disappear, side effects spread, composition gets messy. This is why visible structure is essential.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;fn(args, deps) is that constraint&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For existing code, start with:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;functionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defaultDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dependencies are explicit, not hidden.&lt;/p&gt;
&lt;p&gt;There’s no framework and no package to install.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Linters and reviews catch problems after the fact; it’s better to get the shape right before the agent writes the code.&lt;/p&gt;
&lt;p&gt;This pattern is functional DI with explicit seams, good design regardless. It also happens to keep AI-generated code tractable.&lt;/p&gt;
&lt;p&gt;This means: no hidden infrastructure imports, no global singletons, and no constructors that quietly accumulate the whole world.&lt;/p&gt;
&lt;p&gt;The types explain intent. The agent has to colour within the lines.&lt;/p&gt;
&lt;p&gt;This approach is boring, but that’s precisely why it scales.&lt;/p&gt;
&lt;p&gt;The rule matters where business logic meets infrastructure. Pure functions don’t need deps; UI event handlers and glue code don’t need the ceremony. Request-scoped context (auth, tenant, transaction) follows the same rule: pass it in args or expose it as a dep (e.g. &lt;code&gt;getCurrentUser&lt;/code&gt;); no need for an extra parameter.&lt;/p&gt;
&lt;h2 id=&quot;the-core-idea-make-dependencies-visible-not-implicit&quot;&gt;The core idea: make dependencies visible, not implicit&lt;/h2&gt;
&lt;p&gt;Usually, the problem isn’t testability; it’s that the dependency surface is invisible. As a result, you jump between files to understand a method; an agent overmocks the whole constructor and produces tests that pass for the wrong reasons.&lt;/p&gt;
&lt;p&gt;Hidden dependencies (often via constructor injection) are the most common culprit:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UserService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Database&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; cache&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Cache&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; metrics&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Metrics&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Getting user &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getUser&lt;/code&gt; needs &lt;code&gt;db&lt;/code&gt; and &lt;code&gt;logger&lt;/code&gt;, but the constructor forces every caller (and every test) to satisfy five dependencies.&lt;/p&gt;
&lt;p&gt;An agent sees five dependencies and mocks all five. It doesn’t know which of &lt;code&gt;getUser&lt;/code&gt;’s methods are actually used.&lt;/p&gt;
&lt;p&gt;When someone later adds a side effect inside &lt;code&gt;getUser&lt;/code&gt;, the test still passes and verification drifts. The signature lies; the constructor hides the truth.&lt;/p&gt;
&lt;h2 id=&quot;fnargs-deps-makes-the-truth-the-default&quot;&gt;fn(args, deps) makes the truth the default&lt;/h2&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetUserArgs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetUserDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Database&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetUserArgs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetUserDeps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Getting user &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you ask, “What does this need?”, you see it in the signature. So does the agent. There’s no guessing or overmocking: the agent’s job becomes mechanical—read the types, mock those, call, and assert. You don’t thread deps through ten unrelated layers; you wire them once at a &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-this-is-a-testing-upgrade&quot;&gt;Why this is a testing upgrade&lt;/h2&gt;
&lt;p&gt;You mock exactly what the function uses. No module interception, no &lt;code&gt;vi.mock()&lt;/code&gt; hoisting, no constructor archaeology. Good tests stop describing object construction and start describing behaviour.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mock &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vitest-mock-extended&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GetUserDeps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./get-user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;returns the user when found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;GetUserDeps&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;findUser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockResolvedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the dependency surface changes, the Deps type changes, and tests fail at compile time rather than drift. For an agent, that’s a clear signal (“Property ‘logger’ is missing”); with classes, errors are noisier, and the agent often fixes one thing and breaks another.&lt;/p&gt;
&lt;h2 id=&quot;ports-and-adapters-without-the-ceremony&quot;&gt;Ports and adapters, without the ceremony&lt;/h2&gt;
&lt;p&gt;Deps are ports: capabilities the function needs (db, logger, sendEmail, current time). Adapters are what you wire at the boundary.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SendWelcomeEmailDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;sendEmail&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SendWelcomeEmailDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the boundary: &lt;code&gt;deps = { sendEmail: sendgridAdapter.sendEmail }&lt;/code&gt;. In tests: &lt;code&gt;deps = { sendEmail: vi.fn().mockResolvedValue(undefined) }&lt;/code&gt;. The agent only needs to satisfy the type; it doesn’t need to know SendGrid or SMTP. This is &lt;a href=&quot;https://arrangeactassert.com/posts/fn-args-deps-and-hexagonal-architecture/&quot;&gt;ports and adapters&lt;/a&gt; reduced to a function signature.&lt;/p&gt;
&lt;h2 id=&quot;adopting-the-pattern-in-an-existing-codebase&quot;&gt;Adopting the pattern in an existing codebase&lt;/h2&gt;
&lt;p&gt;You don’t need a big-bang rewrite. Add a seam (e.g. route through a factory), then migrate one function at a time; contract tests tell you if behaviour changes. The move that makes it backward-compatible: add &lt;code&gt;deps&lt;/code&gt; as the last argument with a default so existing callers keep working.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mailer &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; _mailer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Mailer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../infra/mailer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SendWelcomeEmailDeps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Mailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; defaultDeps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SendWelcomeEmailDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mailer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; _mailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  recipient&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sender&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; User&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SendWelcomeEmailDeps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; defaultDeps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mailer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mailer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    to&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; recipient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sender&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    template&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test seam on day one, no call-site churn. Later: migrate callers to pass deps from the composition root, then remove the default. Same pattern for any function that currently imports infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;wire-once-at-the-boundary&quot;&gt;Wire once at the boundary&lt;/h2&gt;
&lt;p&gt;You don’t pass deps at every call site. Wire once at a &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt; (service factory, router, app bootstrap). Domain functions receive deps and pass them down only when calling other domain functions; if you’re plumbing deps through five layers, your module boundaries are likely wrong.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUserService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Database&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; logger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createUserService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; userService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The agent follows one rule: domain functions are fn(args, deps); wiring lives in the factory.&lt;/p&gt;
&lt;h2 id=&quot;the-if-you-only-do-one-thing-rules&quot;&gt;The “if you only do one thing” rules&lt;/h2&gt;
&lt;p&gt;Keep the rule set short. Agents do best with a small, repeatable set of constraints.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Business logic is fn(args, deps).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain code does not import infrastructure at runtime&lt;/strong&gt; (no DB clients, HTTP clients, env reads).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inject what you want to mock&lt;/strong&gt; (network, disk, clock, collaborators). Don’t inject pure utilities—they don’t need test doubles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wire adapters at the boundary&lt;/strong&gt; (a &lt;a href=&quot;https://arrangeactassert.com/posts/composition-roots-and-fn-args-deps/&quot;&gt;composition root&lt;/a&gt; or service factory).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Defaults are allowed only for migration.&lt;/strong&gt; Temporary scaffolding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it. Not a framework, not a platform bet, just a dependency surface that stays visible. When the agent has that, it can reason about what, how, and why, and so can you. Once the seams are visible, testing, composition, and refactoring stop fighting the code.&lt;/p&gt;
&lt;p&gt;Start using this visible dependency surface today. Apply the fn(args, deps) rule in your next PR or refactor. By making seams visible, you make testing, composition, and refactoring smoother. The sooner you begin, the sooner you gain clarity for both you and the agent. Embrace the pattern; your codebase will thank you.&lt;/p&gt;
</content:encoded></item><item><title>Visualising Awaitly Workflows with awaitly-visualizer</title><link>https://arrangeactassert.com/posts/visualising-awaitly-workflows-with-awaitly-visualizer/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/visualising-awaitly-workflows-with-awaitly-visualizer/</guid><pubDate>Sat, 07 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;You have an &lt;a href=&quot;https://github.com/jagreehal/awaitly&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Awaitly&lt;/a&gt; workflow: a few steps, some dependencies, typed results. It works. When someone asks “what does this do?” or you need to debug a run, you’re left tracing through code.&lt;/p&gt;
&lt;p&gt;What if you could see the same workflow as a diagram? &lt;a href=&quot;https://github.com/jagreehal/awaitly/tree/main/packages/awaitly-visualizer&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;awaitly-visualizer&lt;/a&gt; plugs into your workflow’s events and turns them into that picture. For a checkout that runs fetchCart, validateCart, processPayment, then completeOrder, you get output like this:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌── checkout ────┐
│  ✓ fetchCart   │
│  ✓ validateCart│
│  ✓ processPayment
│  ✓ completeOrder
│  Completed     │
└────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same idea as Mermaid flowcharts: steps, order, success and failure. This post walks through adding it step by step. All of the code below lives in a test in the repo so you can run it yourself.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;part-1-a-minimal-checkout-workflow&quot;&gt;Part 1: A minimal checkout workflow&lt;/h2&gt;
&lt;p&gt;Start with a workflow that has no visualisation. We’ll use a simple checkout: fetch cart, validate, process payment, complete order. Each operation returns an &lt;code&gt;AsyncResult&lt;/code&gt;; the workflow composes them with &lt;code&gt;step()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly/core&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createWorkflow &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly/workflow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cart&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; itemCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; totalCents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fetchCart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cartId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Cart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CART_NOT_FOUND&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cartId &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CART_NOT_FOUND&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cartId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    itemCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalCents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validateCart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Cart
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;INVALID_CART&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;itemCount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;INVALID_CART&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; processPayment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Cart
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; transactionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PAYMENT_FAILED&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; transactionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;txn-123&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; completeOrder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  cartId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;COMPLETE_ERROR&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;order-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cartId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  fetchCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  validateCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  processPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  completeOrder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the workflow by creating it with a name and deps, then calling it with a function that uses &lt;code&gt;step()&lt;/code&gt; for each operation:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fetchCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; validateCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; processPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; completeOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fetchCart&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cart-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;validateCart&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validateCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;processPayment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;completeOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;completeOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing is visualised yet. The workflow just runs and returns a result. Next we wire in the visualiser so every step is reflected in a diagram.&lt;/p&gt;
&lt;h2 id=&quot;part-2-live-visualisation-with-createvisualizer&quot;&gt;Part 2: Live visualisation with createVisualizer&lt;/h2&gt;
&lt;p&gt;Create a visualiser with a workflow name (used as the diagram title). Pass its &lt;code&gt;handleEvent&lt;/code&gt; into the workflow’s &lt;code&gt;onEvent&lt;/code&gt; option. After the workflow completes, call &lt;code&gt;render()&lt;/code&gt; to get the default ASCII diagram, or &lt;code&gt;renderAs(&quot;mermaid&quot;)&lt;/code&gt; for Mermaid source.&lt;/p&gt;
&lt;p&gt;We’ll use the same workflow body everywhere below; only the wiring changes. Here it is in full once:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createVisualizer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly-visualizer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; viz &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createVisualizer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  workflowName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  detectParallel&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// this workflow is strictly sequential; with step.parallel() or step.race(), set true to show parallel/race scopes&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  onEvent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; viz&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Same four-step workflow as Part 1; we only add onEvent above&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fetchCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; validateCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; processPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; completeOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fetchCart&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cart-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;validateCart&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validateCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;processPayment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; order &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;completeOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;completeOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viz&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viz&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mermaid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example output from the blog-journey test (ASCII from &lt;code&gt;viz.render()&lt;/code&gt;, Mermaid from &lt;code&gt;viz.renderAs(&quot;mermaid&quot;)&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ASCII (terminal-style box):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌── checkout ──────────────────────────────────────────────────────────────────┐
│                                                                              │
│  ✓ fetchCart [0ms]                                                           │
│  ✓ validateCart [0ms]                                                        │
│  ✓ processPayment [0ms]                                                      │
│  ✓ completeOrder [0ms]                                                       │
│                                                                              │
│  Completed in 2ms                                                            │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Mermaid (flowchart source):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    start((&quot;▶ Start&quot;))
    step_fetchCart[&quot;✓ fetchCart 0ms&quot;]:::success
    start --&amp;gt; step_fetchCart
    step_validateCart[&quot;✓ validateCart 0ms&quot;]:::success
    step_fetchCart --&amp;gt; step_validateCart
    step_processPayment[&quot;✓ processPayment 0ms&quot;]:::success
    step_validateCart --&amp;gt; step_processPayment
    step_completeOrder[&quot;✓ completeOrder 0ms&quot;]:::success
    step_processPayment --&amp;gt; step_completeOrder
    finish((&quot;✓ Done&quot;)):::success
    step_completeOrder --&amp;gt; finish

    classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46
    %% other classDefs (pending, error, etc.) omitted for brevity
&lt;/pre&gt;
&lt;h3 id=&quot;when-a-step-fails&quot;&gt;When a step fails&lt;/h3&gt;
&lt;p&gt;Everything so far is the happy path. If a step returns an error (for example &lt;code&gt;fetchCart(&quot;missing&quot;)&lt;/code&gt; returns &lt;code&gt;CART_NOT_FOUND&lt;/code&gt;), the workflow short-circuits and the visualiser shows the failure. Same code; run with a cart id that triggers the error:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Same viz and workflow as above; only the input changes&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fetchCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; validateCart&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; processPayment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; completeOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fetchCart&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchCart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;missing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... rest unchanged&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.ok === false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ASCII (failed run):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌── checkout ──────────────────────────────────────────────────────────────────┐
│                                                                              │
│  ✗ fetchCart [0ms]                                                           │
│                                                                              │
│  Failed in 0ms                                                               │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Mermaid (failed run):&lt;/strong&gt; the flowchart shows the failing step with an error style and a “✗ Failed” end node instead of “✓ Done”. The diagram makes it obvious where the run stopped and that it did not reach later steps.&lt;/p&gt;
&lt;p&gt;The visualiser consumes workflow events (step start, step success, workflow success, and so on) and builds an internal representation. That representation is what gets rendered as ASCII or Mermaid. You can also use &lt;code&gt;renderAs(&quot;json&quot;)&lt;/code&gt; to inspect the structure, or &lt;code&gt;renderAs(&quot;logger&quot;)&lt;/code&gt; for a step-by-step log style. Event handling is synchronous and lightweight, so it’s fine for dev, test, and debugging; in production you might keep visualisation behind a feature flag or sample a fraction of runs if you want to limit overhead.&lt;/p&gt;
&lt;h2 id=&quot;part-3-collect-then-visualise-with-createeventcollector&quot;&gt;Part 3: Collect then visualise with createEventCollector&lt;/h2&gt;
&lt;p&gt;Sometimes you want to record events and visualise later, or send the same events to both a visualiser and your own logger or metrics. Use &lt;code&gt;createEventCollector&lt;/code&gt; and wire its handlers; same workflow as above, only the &lt;code&gt;onEvent&lt;/code&gt; and what you do after the run change:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createEventCollector &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly-visualizer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; collector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createEventCollector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  workflowName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  detectParallel&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  onEvent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; collector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same workflow function as Part 2 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visualize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;collector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visualizeAs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mermaid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The collector stores every workflow event it receives. When you call &lt;code&gt;visualize()&lt;/code&gt;, it replays those events through an internal visualiser and returns the same kind of output you get from &lt;code&gt;createVisualizer&lt;/code&gt;. You can also use &lt;code&gt;collector.getEvents()&lt;/code&gt; to get the raw events, or &lt;code&gt;visualizeEvents(events, options)&lt;/code&gt; if you’ve pushed events into your own array.&lt;/p&gt;
&lt;h2 id=&quot;part-4-combine-handlers&quot;&gt;Part 4: Combine handlers&lt;/h2&gt;
&lt;p&gt;If you want both a live visualiser and another consumer (logging, metrics, or a collector for later), use &lt;code&gt;combineEventHandlers&lt;/code&gt; so one run feeds all of them. Same workflow again; only the handler wiring changes:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; WorkflowEvent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly/workflow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createVisualizer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; combineEventHandlers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awaitly-visualizer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; viz &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createVisualizer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  workflowName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  detectParallel&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; collectedEvents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WorkflowEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; combined &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;combineEventHandlers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  viz&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WorkflowEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; collectedEvents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; onEvent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combined &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same workflow function as Part 2 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viz&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// collectedEvents now holds every event for this run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each event is passed to every handler you combined. You keep a single &lt;code&gt;onEvent&lt;/code&gt; and get multiple observers.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try it yourself&lt;/h2&gt;
&lt;p&gt;Install the packages:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; awaitly awaitly-visualizer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code in this post is covered by tests in the awaitly repo. Clone and run the blog journey tests:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/awaitly
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; awaitly
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--filter&lt;/span&gt; awaitly-visualizer &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; -- blog-journey&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll see the same checkout workflow exercised with &lt;code&gt;createVisualizer&lt;/code&gt;, &lt;code&gt;createEventCollector&lt;/code&gt;, and &lt;code&gt;combineEventHandlers&lt;/code&gt;. From there you can add visualisation to your own workflows by passing &lt;code&gt;onEvent&lt;/code&gt; and, if you like, collecting events for logs or Mermaid in docs. At that point, your workflows stop being invisible control flow and start being artifacts you can reason about.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/awaitly&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/awaitly&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>No, the sun does not shine out of Claude’s backside</title><link>https://arrangeactassert.com/posts/no-the-sun-does-not-shine-out-of-claudes-backside/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/no-the-sun-does-not-shine-out-of-claudes-backside/</guid><pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;As of today, Opus 4.5 is the best coding model I’ve used. That is not praise by vibes. That is, after building libraries and utilities that fixed problems I could not solve with the tools I was using before.&lt;/p&gt;
&lt;p&gt;The progress is impressive.&lt;/p&gt;
&lt;p&gt;However, it’s not all sunshine and rainbows, as people on social media and YouTube claim.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cartoon illustration of a pig driving and a chicken riding along, suggesting responsibility versus involvement.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_Z1hivNl.webp&quot; srcset=&quot;/_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_26WWWO.webp 640w, /_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_BOdgw.webp 750w, /_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_Z2vYXRQ.webp 828w, /_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_Z25DQ07.webp 1080w, /_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_Z6Kj9K.webp 1280w, /_astro/no-the-sun-does-not-shine-out-of-claudes-backside.CS-MQTEJ_Z1hivNl.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;To be fair, this is not just a Claude problem. It is just the model I use daily, so it is the one I am most familiar with.&lt;/p&gt;
&lt;p&gt;I keep seeing people brag about running Claude in a loop twenty-four seven, as if it were working shifts in a sweatshop.&lt;/p&gt;
&lt;p&gt;Are they producing apps? Yes.&lt;/p&gt;
&lt;p&gt;Are tasks being completed? Yes.&lt;/p&gt;
&lt;p&gt;Is the quality good? Maybe.&lt;/p&gt;
&lt;p&gt;When I built my version of the Ralph loop, I added an inspect-and-adapt step. Without that, what people are calling autonomy is just waterfall development with extra steps. But even with me stopping to inspect, it still wasn’t good enough.&lt;/p&gt;
&lt;p&gt;People like me started adding hooks, skills, validators, linting, compiler checks, and tests just to coax Claude into producing code that does not immediately fall over.&lt;/p&gt;
&lt;p&gt;But that doesn’t guarantee quality or a good product. None of it guarantees good design. It solves an immediate need. It patches a leak. It does not fix the abstraction. In fact, more often than not, it leaves you with a leaky one.&lt;/p&gt;
&lt;p&gt;Everyone has an opinion on how to avoid this, including me, and I will share my methods later. The reality is that nobody now or ever is betting their house on a process that guarantees success.&lt;/p&gt;
&lt;h2 id=&quot;the-boring-solution&quot;&gt;The boring solution&lt;/h2&gt;
&lt;p&gt;So the solution is boring. Pay attention. Stay involved.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Be the pig, not the chicken.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;also-use-another-ai&quot;&gt;Also, use another AI&lt;/h2&gt;
&lt;p&gt;Alongside Claude, I use another frontier model, Codex 5.2, purely as a reviewer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So far, Claude has not produced code that Codex considered correct on the first attempt. Often it takes many iterations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When Codex finds an issue, I ask it to create a failing test. I do this on purpose, and I do not automate it, even though I could.&lt;/p&gt;
&lt;p&gt;The friction matters.&lt;/p&gt;
&lt;p&gt;I read the issue, copy it, and hand it back to Claude to fix. How Codex identifies problems and how Claude explains its reasoning and resolution for a failing test are among the best lessons I’ve had.&lt;/p&gt;
&lt;p&gt;But by attentive, I mean that when Claude starts going off piste and over-engineering a solution, I stop it and give feedback.&lt;/p&gt;
&lt;p&gt;Yes, I am a backseat driver. That’s fine. AI isn’t going to kick me out of the car just yet.&lt;/p&gt;
</content:encoded></item><item><title>Stop Throwing Errors. Awaitly Makes Async Error Handling Actually Work</title><link>https://arrangeactassert.com/posts/stop-throwing-errors/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/stop-throwing-errors/</guid><pubDate>Thu, 22 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;img alt=&quot;Stop Throwing Errors&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1536&quot; src=&quot;https://arrangeactassert.com/_astro/stop-throwing-errors.CSMaM_f8_Z1OR3Fe.webp&quot; srcset=&quot;/_astro/stop-throwing-errors.CSMaM_f8_yXse8.webp 640w, /_astro/stop-throwing-errors.CSMaM_f8_1Izydg.webp 750w, /_astro/stop-throwing-errors.CSMaM_f8_1rx7wf.webp 828w, /_astro/stop-throwing-errors.CSMaM_f8_Z1OR3Fe.webp 1024w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’ve all written this code:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;lambdaHandler&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectToDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;errorHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Error&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;catch (error)&lt;/code&gt; swallows everything. Was it a “task not found”? A database connection failure? A permissions issue? Who knows.&lt;/p&gt;
&lt;p&gt;Throwing exceptions for expected failures is like using GOTO. You lose the thread.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/awaitly&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Awaitly&lt;/a&gt; fixes this by treating errors as data, not explosions. This guide teaches the patterns one concept at a time.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;part-1-foundation-no-library&quot;&gt;Part 1: Foundation (No Library)&lt;/h2&gt;
&lt;p&gt;Before we touch Awaitly, let’s fix some fundamental patterns using pure TypeScript. These are good practices regardless of what error handling library you use.&lt;/p&gt;
&lt;h3 id=&quot;step-0-the-starting-point&quot;&gt;Step 0: The Starting Point&lt;/h3&gt;
&lt;p&gt;Here’s a typical function that creates its own dependency:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This runs every time!&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectToDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Task not found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; task &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Error&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem: the db connection is created every time &lt;code&gt;getTask&lt;/code&gt; is called. We can’t test &lt;code&gt;getTask&lt;/code&gt; without a real database, and we can’t reuse the connection across multiple functions.&lt;/p&gt;
&lt;p&gt;Call &lt;code&gt;handler&lt;/code&gt; twice and you connect to the database twice. Wasteful.&lt;/p&gt;
&lt;h3 id=&quot;step-1-move-dependencies-to-the-boundary&quot;&gt;Step 1: Move Dependencies to the Boundary&lt;/h3&gt;
&lt;p&gt;Create dependencies at the “boundary” (your handler), then pass them down.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Db&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// db is passed IN as a parameter&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Task not found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Create db ONCE at the boundary&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectToDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; task &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Error&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Call handler twice with the SAME db instance&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// db connected only ONCE, reused across both calls&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;code&gt;db&lt;/code&gt; is created once per handler invocation (not per function call), &lt;code&gt;getTask&lt;/code&gt; can be tested by passing a mock db, and the connection is reusable across multiple function calls.&lt;/p&gt;
&lt;p&gt;Bonus: &lt;code&gt;getTask&lt;/code&gt; is now testable with a mock:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockDb&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mock&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Pending&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;any-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mockDb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-the-fnargs-deps-pattern&quot;&gt;Step 2: The fn(args, deps) Pattern&lt;/h3&gt;
&lt;p&gt;Let’s standardise on a consistent function signature:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// fn({ ...args }, { ...deps })&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    ^^^^^^^^^^   ^^^^^^^^^^&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//    what to do   how to do it&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Task not found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Call with named parameters&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives you a consistent shape across all business functions, clear separation of “what” vs “how”, self-documenting named parameters, and it’s easy to add new args or deps without changing call sites.&lt;/p&gt;
&lt;p&gt;Compare the readability:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Positional args: what&apos;s what?&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Named args: crystal clear&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; logger &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       ^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//       business args     infrastructure deps&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-return-null-for-expected-failures&quot;&gt;Step 3: Return null for Expected Failures&lt;/h3&gt;
&lt;p&gt;Throwing for “not found” is using exceptions for control flow. Return &lt;code&gt;null&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Expected failure, not an exception&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Found case&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; found &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;found&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Not found case: no try/catch needed!&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; notFound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-missing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;notFound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this approach:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-missing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result is null... but WHY?&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Was it not found? Permission error? DB down?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; tells us it failed, but not why. We’ll solve this in Part 2.&lt;/p&gt;
&lt;h2 id=&quot;part-2-typed-results&quot;&gt;Part 2: Typed Results&lt;/h2&gt;
&lt;p&gt;Now we introduce Awaitly’s &lt;code&gt;Result&lt;/code&gt; type, one piece at a time.&lt;/p&gt;
&lt;h3 id=&quot;step-4-introduce-ok-for-explicit-success&quot;&gt;Step 4: Introduce ok() for Explicit Success&lt;/h3&gt;
&lt;p&gt;Wrap successful returns in &lt;code&gt;ok(value)&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;never&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Wrapped in ok()&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.ok === true&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.value === Task&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success is now explicit, not implicit. It prepares for adding error cases (next step), and &lt;code&gt;result.ok&lt;/code&gt; tells you immediately if it succeeded.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;AsyncResult&amp;lt;Task, never&amp;gt;&lt;/code&gt; type means: “This returns a Task on success, and never returns an error.” We’ll change that &lt;code&gt;never&lt;/code&gt; to an actual error type next.&lt;/p&gt;
&lt;h3 id=&quot;step-5-introduce-err-for-named-failures&quot;&gt;Step 5: Introduce err() for Named Failures&lt;/h3&gt;
&lt;p&gt;Return &lt;code&gt;err(&apos;ERROR_CODE&apos;)&lt;/code&gt; instead of &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Named error!&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Success case&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; success &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// success.ok === true, success.value === Task&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Error case: we know WHAT went wrong&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; failure &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-missing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// failure.ok === false, failure.error === &apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now errors have a name, not just &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-6-asyncresult-type-annotation&quot;&gt;Step 6: AsyncResult Type Annotation&lt;/h3&gt;
&lt;p&gt;Add explicit return types so TypeScript enforces correctness:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//            ^^^^  ^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//            Success type    Error type&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// TypeScript now knows:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// - If result.ok === true, result.value is Task&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// - If result.ok === false, result.error is &apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AsyncResult&amp;lt;T, E&amp;gt;&lt;/code&gt; is just &lt;code&gt;Promise&amp;lt;Ok&amp;lt;T&amp;gt; | Err&amp;lt;E&amp;gt;&amp;gt;&lt;/code&gt;. The type annotation tells TypeScript exactly what success and failure look like.&lt;/p&gt;
&lt;h3 id=&quot;step-7-rich-error-objects&quot;&gt;Step 7: Rich Error Objects&lt;/h3&gt;
&lt;p&gt;Use error objects with &lt;code&gt;type&lt;/code&gt; plus context instead of plain strings:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Rich error type with context&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Include context!&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-missing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Now we have rich error info for logging/debugging&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: Task &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; not found&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Output: TASK_NOT_FOUND: Task t-missing not found&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Errors now carry useful debugging information. You can include taskId, timestamps, details, stack traces. Makes logging and error handling much richer.&lt;/p&gt;
&lt;h2 id=&quot;part-3-composing-results&quot;&gt;Part 3: Composing Results&lt;/h2&gt;
&lt;p&gt;Multiple functions that return Results: how do we compose them cleanly?&lt;/p&gt;
&lt;h3 id=&quot;step-8-the-boilerplate-problem&quot;&gt;Step 8: The Boilerplate Problem&lt;/h3&gt;
&lt;p&gt;Call multiple &lt;code&gt;AsyncResult&lt;/code&gt; functions and handle each manually:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UpdateFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UPDATE_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UpdateFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;updateTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Errored&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updated&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UPDATE_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Manual composition: lots of boilerplate!&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; UpdateFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Step 1: Get task&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; taskResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;taskResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; taskResult&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Boilerplate&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Step 2: Mark errored&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updateResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; taskResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;updateResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; updateResult&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// More boilerplate&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Imagine 5 more steps... that&apos;s 5 more if-checks!&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; updateResult&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every call needs &lt;code&gt;if (!result.ok) return result&lt;/code&gt;. The happy path gets buried in error-checking ceremony.&lt;/p&gt;
&lt;h3 id=&quot;step-9-run-for-linear-composition&quot;&gt;Step 9: run() for Linear Composition&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;run()&lt;/code&gt; to compose multiple &lt;code&gt;AsyncResult&lt;/code&gt; functions. &lt;code&gt;step()&lt;/code&gt; unwraps ok values; err values exit early.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; run&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Unexpected&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UNEXPECTED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; cause&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HandlerError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Unexpected&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  deps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HandlerError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HandlerError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// step(id, thunk): id for observability; thunk unwraps ok values. Err values exit the run() immediately.&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;getTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// task is Task, not Result&amp;lt;Task, ...&amp;gt;: already unwrapped!&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// If getTask returned err, we never reach this line&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; updated&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// catchUnexpected maps any unexpected throw to our error type&lt;/span&gt;
      &lt;span class=&quot;token class-name&quot;&gt;catchUnexpected&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cause&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UNEXPECTED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cause &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Happy path&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; success &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// success.ok === true, success.value.status === &apos;Errored&apos;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Error path: exits early, never calls markErrored&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; failure &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;t-missing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// failure.ok === false, failure.error.type === &apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The happy path now reads linearly (no if-checks), errors automatically short-circuit, and &lt;code&gt;step()&lt;/code&gt; unwraps the value so you can use it directly.&lt;/p&gt;
&lt;p&gt;Important API note: with &lt;code&gt;run()&lt;/code&gt;, you use &lt;code&gt;step(id, () =&amp;gt; fn())&lt;/code&gt; — an id (string) and a thunk. The thunk lets &lt;code&gt;run()&lt;/code&gt; catch synchronous throws.&lt;/p&gt;
&lt;h3 id=&quot;step-10-steptry-for-throwing-code&quot;&gt;Step 10: step.try() for Throwing Code&lt;/h3&gt;
&lt;p&gt;Third-party SDKs (Slack, Stripe, database drivers) throw exceptions. Use &lt;code&gt;step.try()&lt;/code&gt; to wrap them into typed errors:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConnectFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CONNECT_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Unexpected&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UNEXPECTED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; cause&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StepError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ConnectFailed &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Unexpected&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Simulate an SDK that throws&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; unstableDb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Connection refused&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleWithUnstableDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; StepError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; StepError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// step.try(id, thunk, opts) catches the throw and converts to typed error&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;connect&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; unstableDb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        onError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ConnectFailed &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CONNECT_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// This line never runs because connect() threw&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;success&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;no-task&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;catchUnexpected&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cause&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UNEXPECTED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cause &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleWithUnstableDb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.ok === false&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.error.type === &apos;CONNECT_FAILED&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// result.error.message === &apos;Connection refused&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;step.try()&lt;/code&gt; to wrap specific calls you know can throw (SDKs, I/O). Use &lt;code&gt;catchUnexpected&lt;/code&gt; as a safety net for bugs and unexpected throws.&lt;/p&gt;
&lt;p&gt;Prefer &lt;code&gt;step.try()&lt;/code&gt; for known throwers; rely on &lt;code&gt;catchUnexpected&lt;/code&gt; as a fallback for genuine surprises.&lt;/p&gt;
&lt;h2 id=&quot;part-4-workflows&quot;&gt;Part 4: Workflows&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;createWorkflow&lt;/code&gt; keeps the same mental model as &lt;code&gt;run()&lt;/code&gt; but adds automatic error inference.&lt;/p&gt;
&lt;h3 id=&quot;step-11-createworkflow-for-automatic-error-inference&quot;&gt;Step 11: createWorkflow for Automatic Error Inference&lt;/h3&gt;
&lt;p&gt;With &lt;code&gt;run()&lt;/code&gt;, you manually maintain the error union:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HandlerError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; DbFailed &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; SlackFailed &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Unexpected&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TaskWithError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HandlerError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;createWorkflow&lt;/code&gt;, the error union is computed from your deps:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createWorkflow &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly/workflow&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DbFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SlackFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SLACK_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; loadTask &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; markErrored &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DbFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... implementation&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; notifySlack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SlackFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... implementation&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// createWorkflow: declare deps, get automatic error inference&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errorHandler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadTask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; markErrored&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; notifySlack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// TypeScript INFERS the error type from deps:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Error = TaskNotFound | DbFailed | SlackFailed | UnexpectedError&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// No manual &quot;type HandlerError = ...&quot; needed!&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;errorHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;notifySlack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notifySlack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updated&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; updated&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No manual union maintenance (add a dep and the error type is auto-included), &lt;code&gt;UnexpectedError&lt;/code&gt; is included by default (no &lt;code&gt;catchUnexpected&lt;/code&gt; needed), and each step uses &lt;code&gt;step(id, () =&amp;gt; deps.fn())&lt;/code&gt; — an id plus a thunk so the workflow can cache and track steps.&lt;/p&gt;
&lt;p&gt;API note: both &lt;code&gt;run()&lt;/code&gt; and workflow use &lt;code&gt;step(id, () =&amp;gt; fn())&lt;/code&gt;. The id identifies the step for observability and caching; use &lt;code&gt;step(id, () =&amp;gt; deps.fn(), { key })&lt;/code&gt; when you need an explicit cache key.&lt;/p&gt;
&lt;h3 id=&quot;step-12-boundary-mapping-with-unexpectederror&quot;&gt;Step 12: Boundary Mapping with UnexpectedError&lt;/h3&gt;
&lt;p&gt;At your Lambda boundary, map the Result to HTTP responses:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createWorkflow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UNEXPECTED_ERROR&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly/workflow&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LambdaResponse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Task &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errorHandler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadTask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; markErrored &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lambdaHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;LambdaResponse&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;errorHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Error type is: TaskNotFound | DbFailed | UnexpectedError&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// TypeScript ensures we handle all cases (including UnexpectedError!)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Task not found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;DB error: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UNEXPECTED_ERROR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// UnexpectedError is included automatically by workflow&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Internal server error&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Key difference from run(): the workflow error type includes &lt;code&gt;UnexpectedError&lt;/code&gt; automatically. You must handle &lt;code&gt;UnexpectedError&lt;/code&gt; in your switch (TypeScript will remind you). Use the &lt;code&gt;UNEXPECTED_ERROR&lt;/code&gt; constant to ensure you can’t drift from the library.&lt;/p&gt;
&lt;h3 id=&quot;step-13-step-names-and-observability&quot;&gt;Step 13: Step Names and Observability&lt;/h3&gt;
&lt;p&gt;Add name/key options to steps for observability:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadTask &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;onEvent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; event &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;anonymous&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Step id shows up in events; key enables caching&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;t-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;task:t-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Same key = cached result&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Console output:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// step_start:loadTask&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// step_complete:loadTask&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step ids show up in logs/traces, keys enable caching (same key = cached result), and this is the foundation for durable execution (resume from last step).&lt;/p&gt;
&lt;h2 id=&quot;part-5-full-example&quot;&gt;Part 5: Full Example&lt;/h2&gt;
&lt;p&gt;The complete refactored handler using &lt;code&gt;createWorkflow&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tryAsync&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncResult&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createWorkflow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UNEXPECTED_ERROR&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly/workflow&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// TYPES&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Pending&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Errored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formattedLogs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DbFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SlackFailed&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SLACK_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LambdaResponse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Task &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// BUSINESS OPERATIONS (each returns AsyncResult)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; loadTask &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; getLogs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DbFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tryAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; logStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; markErrored &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  formattedLogs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DbFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Not found&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updated&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Errored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formattedLogs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updated&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; notifySlack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;slack&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SlackClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SlackFailed&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tryAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; slack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Task &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; errored&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SLACK_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Pure function: no deps needed&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;formatLogs&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; logs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;• &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;l&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// WORKFLOW (orchestrates operations)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Error type is INFERRED: TaskNotFound | DbFailed | SlackFailed | UnexpectedError&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errorHandler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadTask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; getLogs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; markErrored&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; notifySlack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// LAMBDA HANDLER (boundary)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ═══════════════════════════════════════════════════════════════════════════&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lambdaHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  slack&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SlackClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; production&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;LambdaResponse&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;errorHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;getLogs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getLogs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formattedLogs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;formatLogs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;logs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; formattedLogs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;production&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;notifySlack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notifySlack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;slack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; updated&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Error handled successfully&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Handle all error types (including UnexpectedError from workflow)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Task not found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SLACK_FAILED&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UNEXPECTED_ERROR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statusCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Internal server error&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare to original:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;try/catch everywhere&lt;/td&gt;
&lt;td&gt;Typed Results throughout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deps created inline&lt;/td&gt;
&lt;td&gt;deps injected at boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;errors as strings&lt;/td&gt;
&lt;td&gt;errors are data with context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;manual error union maintenance&lt;/td&gt;
&lt;td&gt;automatic inference with createWorkflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;happy path buried in if-checks&lt;/td&gt;
&lt;td&gt;linear happy path with step()&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;appendix-convenience-helpers&quot;&gt;Appendix: Convenience Helpers&lt;/h2&gt;
&lt;p&gt;These helpers reduce boilerplate but aren’t core to understanding Awaitly. Learn the core concepts first (&lt;code&gt;ok&lt;/code&gt;/&lt;code&gt;err&lt;/code&gt;/&lt;code&gt;run&lt;/code&gt;/&lt;code&gt;workflow&lt;/code&gt;), then use these for cleaner code.&lt;/p&gt;
&lt;h3 id=&quot;tryasync-wrap-throwing-code&quot;&gt;tryAsync: Wrap Throwing Code&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; tryAsync &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DbError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_ERROR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Manual try/catch&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateTaskManual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DbError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; unstableDb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_ERROR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Using tryAsync: much cleaner&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateTaskClean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DbError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tryAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; unstableDb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DB_ERROR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; e &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Unknown&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this when wrapping SDK calls (Slack, Stripe, database drivers) that throw exceptions.&lt;/p&gt;
&lt;h3 id=&quot;fromnullable-convert-null-to-typed-error&quot;&gt;fromNullable: Convert null to Typed Error&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fromNullable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFound&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Manual null check&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTaskManual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Using fromNullable: one line&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTaskClean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TaskNotFound&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; taskStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fromNullable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TASK_NOT_FOUND&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this for database queries that return null for “not found”, or optional properties that should be required.&lt;/p&gt;
&lt;h3 id=&quot;errors-and-errorof-extract-error-types&quot;&gt;Errors&amp;lt;&amp;gt; and ErrorOf&amp;lt;&amp;gt;: Extract Error Types&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Errors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorOf&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;awaitly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ErrorOf extracts the error type from a single function&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TaskNotFoundExtracted&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ErrorOf&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; loadTask&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Type: { type: &apos;TASK_NOT_FOUND&apos;; taskId: string }&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Errors extracts and unions error types from multiple functions&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HandlerErrorExtracted&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Errors&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; loadTask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; markErrored&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Type: TaskNotFound | DbFailed&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Instead of manually writing:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HandlerErrorManual&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; DbFailed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this when building error unions from multiple functions, or reducing boilerplate in error type definitions.&lt;/p&gt;
&lt;h2 id=&quot;appendix-run-vs-createworkflow&quot;&gt;Appendix: run() vs createWorkflow&lt;/h2&gt;
&lt;p&gt;When to prefer &lt;code&gt;run()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want explicit control over the error union&lt;/li&gt;
&lt;li&gt;You’re teaching or learning the fundamentals&lt;/li&gt;
&lt;li&gt;Simple cases with 1-2 steps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When to prefer &lt;code&gt;createWorkflow&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple steps with multiple error types&lt;/li&gt;
&lt;li&gt;You want automatic error inference&lt;/li&gt;
&lt;li&gt;You need observability (onEvent)&lt;/li&gt;
&lt;li&gt;You want built-in &lt;code&gt;UnexpectedError&lt;/code&gt; handling&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// run(): manual error union&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HandlerError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TaskNotFound &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; DbFailed &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Unexpected&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HandlerError&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; taskId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;catchUnexpected&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cause&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UNEXPECTED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cause &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// createWorkflow: automatic error union&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createWorkflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadTask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; markErrored &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;workflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loadTask&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;taskId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;markErrored&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;markErrored&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Error type is inferred: TaskNotFound | DbFailed | UnexpectedError&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;try-it&quot;&gt;Try It&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; awaitly&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start with &lt;code&gt;ok()&lt;/code&gt; and &lt;code&gt;err()&lt;/code&gt;. Move to &lt;code&gt;run()&lt;/code&gt; when you have multiple steps. Graduate to &lt;code&gt;createWorkflow&lt;/code&gt; when you want automatic error inference.&lt;/p&gt;
&lt;p&gt;Your future self (and your on-call colleagues) will thank you.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/awaitly&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/awaitly&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Instrumenting Message Queues? Autotel Handles the Ceremony</title><link>https://arrangeactassert.com/posts/oneuptime-message-queues/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/oneuptime-message-queues/</guid><pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The OneUptime team is spot on in their &lt;a href=&quot;https://oneuptime.com/blog/post/2026-01-07-opentelemetry-message-queue-tracing/view&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Instrument Message Queues with OpenTelemetry&lt;/a&gt; post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Inject trace context on the producer, extract on the consumer; use PRODUCER and CONSUMER span kinds; set semantic conventions (messaging.system, messaging.destination.name, messaging.operation, Kafka partition/offset/consumer group).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They show the raw OpenTelemetry code. It’s comprehensive. It’s also verbose. Every team ends up re-implementing the same patterns: inject, extract, span kinds, semantic attributes, error handling.&lt;/p&gt;
&lt;p&gt;We’ve all been there: copying “best practice” code from blog posts and adapting it for our broker.&lt;/p&gt;
&lt;p&gt;Their key insight:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For batch processing, use a batch span with links or child spans to contributing traces.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;I built Autotel to close that gap.&lt;/p&gt;
&lt;p&gt;While this demo uses Kafka, the same PRODUCER/CONSUMER span patterns apply to other brokers.&lt;/p&gt;
&lt;p&gt;Autotel makes message queue instrumentation the default. PRODUCER/CONSUMER span kinds automatic. Semantic attributes automatic. Error handling with &lt;code&gt;recordException()&lt;/code&gt; and &lt;code&gt;setStatus(ERROR)&lt;/code&gt; in the wrappers. Batch spans with links via &lt;code&gt;extractBatchLineage()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;The OneUptime article shows what correct instrumentation looks like:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: producer span with all the ceremony&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpanStatusCode &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@opentelemetry/api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tracer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTracer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;my-service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;publishMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; span &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;topic&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; publish&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PRODUCER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    attributes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.system&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;kafka&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.destination.name&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.operation&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;publish&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Inject trace context into headers&lt;/span&gt;
    propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;recordException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanStatusCode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: consumer span with semantic conventions&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;consumeMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KafkaMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Extract trace context from headers&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; span &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;topic&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; process&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CONSUMER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    attributes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.system&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;kafka&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.destination.name&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.operation&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;process&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.kafka.consumer.group&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; consumerGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.kafka.partition&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.kafka.offset&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; parentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; span&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;recordException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanStatusCode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: batch span with child spans&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processBatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KafkaMessage&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; batchSpan &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;batch process&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CONSUMER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    attributes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;messaging.batch.message_count&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; messages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; msg &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; messages&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; childSpan &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;message process&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CONSUMER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        links&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getSpanContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; batchSpan&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        childSpan&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    batchSpan&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but it’s a lot of ceremony for something we all want to be the default.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-thin-wrappers-correct-defaults&quot;&gt;The Solution: Thin Wrappers, Correct Defaults&lt;/h2&gt;
&lt;p&gt;With Autotel, the same instrumentation uses &lt;code&gt;withProducerSpan()&lt;/code&gt; and &lt;code&gt;withConsumerSpan()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Producer: automatic PRODUCER span kind, semantic attributes&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withProducerSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; injectTraceHeaders &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Envelope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withProducerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; messageKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Span includes: messaging.system=kafka, messaging.destination.name=orders,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// messaging.operation=publish, SpanKind=PRODUCER&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Error handling: recordException() + setStatus(ERROR) on throw&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Consumer: automatic CONSUMER span kind, semantic attributes&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withConsumerSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; normalizeHeaders &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; msg &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; messageMeta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withConsumerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;email-worker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    messageMeta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Span includes: messaging.system=kafka, messaging.destination.name=orders,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// messaging.operation=process, messaging.kafka.consumer.group=email-worker,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// messaging.kafka.partition, messaging.kafka.offset, SpanKind=CONSUMER&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Context extracted from headers automatically&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;batch-spans-with-links-no-child-span-creation&quot;&gt;Batch Spans with Links (No Child Span Creation)&lt;/h3&gt;
&lt;p&gt;For batch processing, &lt;code&gt;extractBatchLineage()&lt;/code&gt; creates links without manual child spans:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; extractBatchLineage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; withProcessingSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_HASH&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doFlush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; batch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  batch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Extract lineage: trace links + summary hash&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lineage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractBatchLineage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; maxLinks&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withProcessingSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.settlements.batched process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      contextMode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// New trace for batch&lt;/span&gt;
      links&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Links to contributing traces&lt;/span&gt;
      topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;settlements&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      consumerGroup&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;batcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;span&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Summary attributes for querying&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;linked_trace_id_count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_HASH&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;linked_trace_id_hash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processBatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The batch span carries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Links&lt;/strong&gt; to contributing traces (capped by &lt;code&gt;maxLinks&lt;/code&gt; to avoid payload explosion)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;linked_trace_id_count&lt;/strong&gt;: Number of traces that contributed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;linked_trace_id_hash&lt;/strong&gt;: Stable hash for “same set of inputs” queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No manual child span creation. No looping through messages to create links.&lt;/p&gt;
&lt;h2 id=&quot;manual-instrumentation-vs-autotel&quot;&gt;Manual Instrumentation vs Autotel&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual Instrumentation&lt;/th&gt;
&lt;th&gt;Autotel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tracer.startSpan()&lt;/code&gt; with &lt;code&gt;SpanKind.PRODUCER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;withProducerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tracer.startSpan()&lt;/code&gt; with &lt;code&gt;SpanKind.CONSUMER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;withConsumerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagation.inject()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;injectTraceHeaders()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagation.extract()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic in &lt;code&gt;withConsumerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;span.setAttribute()&lt;/code&gt; for each convention&lt;/td&gt;
&lt;td&gt;Semantic conventions automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Try/catch with &lt;code&gt;recordException()&lt;/code&gt; + &lt;code&gt;setStatus(ERROR)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Error handling in wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;span.end()&lt;/code&gt; in finally block&lt;/td&gt;
&lt;td&gt;Automatic on wrapper completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual child spans for batch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;extractBatchLineage()&lt;/code&gt; with links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different code per broker&lt;/td&gt;
&lt;td&gt;Same API (&lt;code&gt;withProducerSpan&lt;/code&gt; / &lt;code&gt;withConsumerSpan&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;what-the-wrappers-provide&quot;&gt;What the Wrappers Provide&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;withProducerSpan()&lt;/code&gt; and &lt;code&gt;withConsumerSpan()&lt;/code&gt; wrappers are thin layers over &lt;code&gt;autotel-plugins&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// packages/observability/src/kafka.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withProducerSpan &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; pluginWithProducerSpan &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;autotel-plugins/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;withProducerSpan&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProducerSpanOptions &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pluginWithProducerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;topic&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MESSAGING_OPERATION_PUBLISH&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      messageKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; options&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;messageKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The plugin handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SpanKind.PRODUCER&lt;/strong&gt; / &lt;strong&gt;SpanKind.CONSUMER&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic attributes&lt;/strong&gt;: &lt;code&gt;messaging.system&lt;/code&gt;, &lt;code&gt;messaging.destination.name&lt;/code&gt;, &lt;code&gt;messaging.operation&lt;/code&gt;, Kafka-specific (&lt;code&gt;partition&lt;/code&gt;, &lt;code&gt;offset&lt;/code&gt;, &lt;code&gt;consumer.group&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error handling&lt;/strong&gt;: &lt;code&gt;recordException(error)&lt;/code&gt; + &lt;code&gt;setStatus({ code: SpanStatusCode.ERROR })&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context propagation&lt;/strong&gt;: Inject on producer, extract on consumer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You write business logic. The wrapper handles observability ceremony. Forwarded retry or dead-letter messages preserve trace context and &lt;code&gt;correlation_id&lt;/code&gt; so failures remain observable across hops.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;p&gt;Clone the demo and see automatic instrumentation:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/event-driven-observability-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; event-driven-observability-demo
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; compose up &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Kafka, Jaeger&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trigger a checkout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sX&lt;/span&gt; POST http://localhost:3000/rpc/checkout/start &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content-type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;cartValue&quot;:149.99,&quot;itemCount&quot;:2,&quot;userId&quot;:&quot;usr_123&quot;,&quot;tenantId&quot;:&quot;acme&quot;}&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open Jaeger at &lt;code&gt;http://localhost:16686&lt;/code&gt;. Find the trace. You’ll see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PRODUCER spans&lt;/strong&gt; with &lt;code&gt;messaging.system=kafka&lt;/code&gt;, &lt;code&gt;messaging.destination.name&lt;/code&gt;, &lt;code&gt;messaging.operation=publish&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CONSUMER spans&lt;/strong&gt; with &lt;code&gt;messaging.kafka.consumer.group&lt;/code&gt;, &lt;code&gt;messaging.kafka.partition&lt;/code&gt;, &lt;code&gt;messaging.kafka.offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch spans&lt;/strong&gt; with &lt;code&gt;linked_trace_id_count&lt;/code&gt; and &lt;code&gt;linked_trace_id_hash&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All semantic conventions set. No manual attribute code in the application.&lt;/p&gt;
&lt;h3 id=&quot;evidence-from-a-live-demo-run&quot;&gt;Evidence from a live demo run&lt;/h3&gt;
&lt;p&gt;Here’s actual output from a demo run (2026-02-07):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jaeger trace&lt;/strong&gt; (queried via Jaeger API):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;traceID&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spanCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;services&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;worker-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spans&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout/start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;internal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events publish&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;producer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.system&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.destination.name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;publish&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.message.key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.system&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.destination.name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.consumer.group&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;demo-v1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.partition&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.offset&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same &lt;code&gt;traceID&lt;/code&gt; across &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;worker-email&lt;/code&gt;; PRODUCER and CONSUMER span kinds; all messaging semantic conventions set automatically by &lt;code&gt;withProducerSpan&lt;/code&gt; / &lt;code&gt;withConsumerSpan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/event-driven-observability-demo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/event-driven-observability-demo&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Message Isolation? Autotel Makes Tenant Context Flow</title><link>https://arrangeactassert.com/posts/signadot-message-isolation/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/signadot-message-isolation/</guid><pubDate>Sat, 17 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The Signadot team is spot on in their &lt;a href=&quot;https://dev.to/signadot/testing-event-driven-architectures-with-opentelemetry-4om7&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Testing Event-Driven Architectures with OpenTelemetry&lt;/a&gt; post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Message isolation using a shared queue: propagate tenant ID in Kafka message headers; consumers use tenant ID for selective message consumption.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They make the case that infrastructure duplication is expensive. Instead of separate Kafka clusters per environment, use tenant ID filtering on a shared queue. Instrument producers and consumers for context propagation.&lt;/p&gt;
&lt;p&gt;We’ve all been there: maintaining four “identical” Kafka setups that slowly drift apart.&lt;/p&gt;
&lt;p&gt;Their key insight:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Requires modifying consumers and using OpenTelemetry for context propagation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;I built Autotel to close that gap.&lt;/p&gt;
&lt;p&gt;Autotel does not invent a new isolation mechanism; it standardizes how existing OpenTelemetry context propagation is applied consistently across services.&lt;/p&gt;
&lt;p&gt;Autotel makes message isolation practical. One ID for selective consumption AND observability. No per-service boilerplate for context propagation.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;You want to test async workflows without duplicating infrastructure. The Signadot article describes the approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tag messages with tenant ID at the producer&lt;/li&gt;
&lt;li&gt;Propagate context through message headers&lt;/li&gt;
&lt;li&gt;Consumers filter by tenant ID (selective consumption)&lt;/li&gt;
&lt;li&gt;Only process messages for your tenant/environment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The manual implementation looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: producer adds tenant context&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tenantId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;x-tenant-id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tenantId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Must inject trace context manually&lt;/span&gt;
  propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Consumer: extract and filter&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;consume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KafkaMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tenantId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-tenant-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Filter: skip if not my tenant&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tenantId &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MY_TENANT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Extract trace context manually&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but it’s a lot of ceremony for something we all want to be the default.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-automatic-context-propagation&quot;&gt;The Solution: Automatic Context Propagation&lt;/h2&gt;
&lt;p&gt;With Autotel, context propagation is automatic:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Kafka consumer with context mode toggle&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withConsumerSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; normalizeHeaders&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HEADER_CORRELATION_ID&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; msg &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; messageMeta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Selective consumption: filter by correlation_id or tenant&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; correlationId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;HEADER_CORRELATION_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;correlationId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Skip, not my tenant/request&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DEMO_PROPAGATE_TRACE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Context mode: inherit trace from producer&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withConsumerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; consumerGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; messageMeta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;worker-email.handle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleOrderCreated&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Context mode: none (new trace per message)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;worker-email.handle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleOrderCreated&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;one-id-for-two-purposes&quot;&gt;One ID for Two Purposes&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;correlation_id&lt;/code&gt; serves dual purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Selective consumption&lt;/strong&gt;: “Should I process this message?”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability join key&lt;/strong&gt;: “Show me everything for this request”&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// At the API boundary&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; correlationId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getOrCreateCorrelationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// In the message&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.orders.created&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  correlation_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; correlationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; order_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-123&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// In the headers&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;HEADER_CORRELATION_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; correlationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;x-event-name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.orders.created&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now consumers can filter. Selective consumption should still acknowledge or forward skipped messages according to your retry/DLQ strategy.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shouldFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;correlationId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ISOLATION_TENANT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// correlation_id can encode tenant directly, or reference it indirectly&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;correlationId&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ISOLATION_TENANT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And observability tools can join:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- All traces for this request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; traces &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; tags&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;correlation_id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tenant-123-checkout-abc&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- All events for this request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; events &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; correlation_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tenant-123-checkout-abc&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- All logs for this request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; correlation_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tenant-123-checkout-abc&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;manual-message-isolation-vs-autotel&quot;&gt;Manual Message Isolation vs Autotel&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual Message Isolation&lt;/th&gt;
&lt;th&gt;Autotel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagation.inject()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;injectTraceHeaders()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagation.extract()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic in &lt;code&gt;withConsumerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Separate tenant ID and trace context&lt;/td&gt;
&lt;td&gt;&lt;code&gt;correlation_id&lt;/code&gt; serves both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-service boilerplate&lt;/td&gt;
&lt;td&gt;Thin wrappers over autotel-plugins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to forget context in one service&lt;/td&gt;
&lt;td&gt;Context flows automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;p&gt;Clone the demo and see message isolation in action:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/event-driven-observability-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; event-driven-observability-demo
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; compose up &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Kafka, Jaeger&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trigger a checkout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sX&lt;/span&gt; POST http://localhost:3000/rpc/checkout/start &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content-type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;cartValue&quot;:149.99,&quot;itemCount&quot;:2,&quot;userId&quot;:&quot;usr_123&quot;,&quot;tenantId&quot;:&quot;acme&quot;}&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Watch worker logs; you’ll see &lt;code&gt;correlation_id&lt;/code&gt; flowing through every service. Open Jaeger at &lt;code&gt;http://localhost:16686&lt;/code&gt; and search by that ID — all traces, all services, one query.&lt;/p&gt;
&lt;h3 id=&quot;evidence-from-a-live-demo-run&quot;&gt;Evidence from a live demo run&lt;/h3&gt;
&lt;p&gt;Here’s actual output from a demo run (2026-02-07):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API response:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;correlation_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;published&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.orders.created&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Jaeger trace&lt;/strong&gt; (one trace across API and worker):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;traceID&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;services&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;worker-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spans&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout/start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;internal&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events publish&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;producer&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;worker-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;consumer&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Event with correlation_id&lt;/strong&gt; (from analytics sink):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.checkouts.started&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;autotel&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;correlation_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;trace_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;trace_url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://localhost:16686/trace/429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same &lt;code&gt;correlation_id&lt;/code&gt; across API response, Kafka message key, and event payload. One ID for isolation and observability.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/event-driven-observability-demo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/event-driven-observability-demo&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Request-Level Isolation? Autotel Propagates Context Automatically</title><link>https://arrangeactassert.com/posts/cncf-async-testing/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/cncf-async-testing/</guid><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The CNCF team is spot on in their &lt;a href=&quot;https://www.cncf.io/blog/2025/10/09/testing-asynchronous-workflows-using-opentelemetry-and-istio/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Testing Asynchronous Workflows using OpenTelemetry and Istio&lt;/a&gt; post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Request-level isolation is the most cost-effective approach.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They make the case against duplicating infrastructure for testing. Instead of spinning up separate Kafka clusters per tenant, use OpenTelemetry Baggage to propagate tenant ID through async flows. Consumers filter by tenant ID. Istio handles routing.&lt;/p&gt;
&lt;p&gt;We’ve all been there: every team has their own “staging Kafka” and costs balloon.&lt;/p&gt;
&lt;p&gt;Their key insight:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use OpenTelemetry Baggage to propagate tenant ID through sync and async. When publishing to Kafka, producers inject trace context (including baggage) into message headers; consumers extract and make routing decisions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;I built Autotel to close that gap.&lt;/p&gt;
&lt;p&gt;Autotel makes context propagation the default. No manual inject/extract into message headers. No per-service boilerplate. No forgetting to include tenant ID in product events.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;You want request-level isolation for testing. The CNCF article describes the approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set tenant ID in OpenTelemetry Baggage at the edge&lt;/li&gt;
&lt;li&gt;Propagate baggage through HTTP (Istio handles it)&lt;/li&gt;
&lt;li&gt;Inject baggage into Kafka message headers on publish&lt;/li&gt;
&lt;li&gt;Extract baggage on consume, filter by tenant ID&lt;/li&gt;
&lt;li&gt;Enrich product events with tenant context&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The manual implementation:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: producer injects baggage into headers&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; baggage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@opentelemetry/api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;publishEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentBaggage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBaggage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tenantId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentBaggage&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tenant.id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Manual inject - easy to forget&lt;/span&gt;
  propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Must remember to include baggage keys explicitly&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tenantId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-tenant-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tenantId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Consumer extracts and filters&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;consume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; KafkaMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tenantId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-tenant-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Filter for selective consumption&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tenantId &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; expectedTenantId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Skip messages for other tenants&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// And every track() call needs tenant context&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;track&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;order.created&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  tenant_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tenantId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Easy to forget&lt;/span&gt;
  order_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but it’s a lot of ceremony for something we all want to be the default.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-context-flows-automatically&quot;&gt;The Solution: Context Flows Automatically&lt;/h2&gt;
&lt;p&gt;With Autotel, &lt;code&gt;injectTraceHeaders()&lt;/code&gt; propagates baggage automatically:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Producer: API sends to Kafka&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; injectTraceHeaders&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; withProducerSpan &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;buildHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;correlationId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eventName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;x-correlation-id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; correlationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;x-event-name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Returns: traceparent, tracestate, x-correlation-id, x-event-name&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Baggage entries are propagated via tracestate&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Envelope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withProducerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; messageKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Autotel still supports OpenTelemetry Baggage; &lt;code&gt;correlation_id&lt;/code&gt; is used as a stable, queryable join key that complements baggage rather than replacing it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;correlation_id&lt;/code&gt; serves as the tenant/request identifier. Use it for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Selective consumption&lt;/strong&gt;: “Only process messages where &lt;code&gt;correlation_id&lt;/code&gt; starts with &lt;code&gt;tenant-123&lt;/code&gt;”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability&lt;/strong&gt;: “Show me everything for this checkout”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prefix-based filtering is one example; &lt;code&gt;correlation_id&lt;/code&gt; can also reference tenant via lookup or structured encoding.&lt;/p&gt;
&lt;h3 id=&quot;enriching-product-events-from-baggage&quot;&gt;Enriching Product Events from Baggage&lt;/h3&gt;
&lt;p&gt;Configure &lt;code&gt;enrichFromBaggage&lt;/code&gt; once at init:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; track &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;autotel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  service&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    includeTraceContext&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;traceUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;http://localhost:16686/trace/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;traceId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    enrichFromBaggage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      allow&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;tenant.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;request.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      deny&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;user.email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user.ssn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Never include PII&lt;/span&gt;
      prefix&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ctx.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      transform&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;user.id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&quot;tenant.id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plain&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Now every track() call includes baggage context automatically&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;track&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;order.created&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; order_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; order&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Emitted event includes: ctx.tenant.id, ctx.user.id (hashed), ctx.request.id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No passing tenant ID into every &lt;code&gt;track()&lt;/code&gt; call. No forgetting to include context. The event schema stays clean, and observability context is always present.&lt;/p&gt;
&lt;h2 id=&quot;manual-baggage-propagation-vs-autotel&quot;&gt;Manual Baggage Propagation vs Autotel&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual Baggage Propagation&lt;/th&gt;
&lt;th&gt;Autotel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;propagation.inject()&lt;/code&gt; into headers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;injectTraceHeaders()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;propagation.extract()&lt;/code&gt; from headers&lt;/td&gt;
&lt;td&gt;Automatic in &lt;code&gt;withConsumerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manually include baggage keys in headers&lt;/td&gt;
&lt;td&gt;Baggage propagated via tracestate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass tenant ID to every &lt;code&gt;track()&lt;/code&gt; call&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enrichFromBaggage&lt;/code&gt; config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different code for HTTP vs Kafka&lt;/td&gt;
&lt;td&gt;Same pattern everywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to forget context in one service&lt;/td&gt;
&lt;td&gt;Context flows automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;one-id-for-isolation-and-observability&quot;&gt;One ID for Isolation and Observability&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;correlation_id&lt;/code&gt; is your stable join key:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// At the edge (API gateway or first service)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; correlationId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getOrCreateCorrelationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// From autotel&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// In message payload and headers&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.checkout.started&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  correlation_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; correlationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Same ID everywhere&lt;/span&gt;
  data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; order_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-123&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;x-correlation-id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; correlationId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Find all traces for a request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; traces &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; correlation_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;abc-123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Find all events for a request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; events &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; correlation_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;abc-123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Find all logs for a request&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; correlation_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;abc-123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And for testing with request-level isolation:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Consumer filters by correlation_id prefix or tenant ID&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tenantId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x-tenant-id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ISOLATION_MODE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; tenantId &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MY_TENANT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Skipped messages should still be acknowledged or forwarded&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// according to your retry/DLQ strategy to avoid backlogs&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withConsumerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; consumerGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; messageMeta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;p&gt;Clone the demo and see context propagation in action:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/event-driven-observability-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; event-driven-observability-demo
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; compose up &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Kafka, Jaeger&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trigger a checkout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sX&lt;/span&gt; POST http://localhost:3000/rpc/checkout/start &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content-type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;cartValue&quot;:149.99,&quot;itemCount&quot;:2,&quot;userId&quot;:&quot;usr_123&quot;,&quot;tenantId&quot;:&quot;acme&quot;}&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check the worker logs; you’ll see &lt;code&gt;correlation_id&lt;/code&gt; flowing through every service. Open Jaeger at &lt;code&gt;http://localhost:16686&lt;/code&gt; and search by &lt;code&gt;correlation_id&lt;/code&gt;. All traces, all services, one query.&lt;/p&gt;
&lt;h3 id=&quot;evidence-from-a-live-demo-run&quot;&gt;Evidence from a live demo run&lt;/h3&gt;
&lt;p&gt;Here’s actual output from a demo run (2026-02-07):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API response&lt;/strong&gt; (stable correlation_id returned immediately):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;ok&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;correlation_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;published&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.orders.created&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Event with autotel enrichment&lt;/strong&gt; (from analytics sink at &lt;code&gt;/events&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.checkouts.started&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;autotel&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;correlation_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;trace_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;span_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;557a33e70d8d3589&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;trace_flags&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;01&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;trace_url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://localhost:16686/trace/429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same &lt;code&gt;correlation_id&lt;/code&gt; in the API response and in every event; &lt;code&gt;trace_url&lt;/code&gt; links directly to the Jaeger trace. One ID joins traces, events, and logs.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/event-driven-observability-demo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/event-driven-observability-demo&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>End-to-End Tracing? Autotel Makes It Automatic</title><link>https://arrangeactassert.com/posts/oso-end-to-end-tracing/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/oso-end-to-end-tracing/</guid><pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The OSO team is spot on in their &lt;a href=&quot;https://oso.sh/blog/end-to-end-tracing-in-event-driven-architectures/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;End-to-End Tracing in Event Driven Architectures&lt;/a&gt; post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Traces break at queues unless you extract context from message headers and put it in the appropriate context.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They walk through the real pain: stateful processing loses trace context in caches, Kafka Connect can only do batch-level tracing, and every team ends up writing custom interceptors and state store wrappers.&lt;/p&gt;
&lt;p&gt;We’ve all been there.&lt;/p&gt;
&lt;p&gt;Their key insight:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Kafka Streams and Kafka Connect this often means manual work: interceptors, state stores, batch spans, or extending tracing logic to extract from headers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;I built Autotel to close that gap.&lt;/p&gt;
&lt;p&gt;Autotel does not change Kafka semantics or tracing theory; it standardizes how OpenTelemetry context propagation is applied across services.&lt;/p&gt;
&lt;p&gt;Autotel makes end-to-end tracing the default. No custom interceptors. No state store wrappers. No per-service boilerplate for inject/extract.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;A checkout request flows through your event-driven system:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;API → Kafka → payment-worker → Kafka → email-worker → Kafka → batcher&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without proper context propagation, you get:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Trace A (API)
Trace B (payment-worker)  ← new trace, no link to A
Trace C (email-worker)    ← new trace, no link to A or B
Trace D (batcher)         ← batch span, no idea which requests contributed&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You cannot see the full path in Jaeger. You cannot query “everything for this checkout.” When the batcher fails, you have no idea which upstream requests were affected.&lt;/p&gt;
&lt;p&gt;The manual fix? Every team writes:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: custom interceptor&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TracingProducerInterceptor&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProducerInterceptor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;onSend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;record&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProducerRecord&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProducerRecord &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; span &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;kafka.send&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PRODUCER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    propagator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;messaging.system&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;kafka&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;messaging.destination.name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Then a consumer interceptor...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TracingConsumerInterceptor&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConsumerInterceptor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;onConsume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;record&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ConsumerRecord&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ConsumerRecord &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; propagator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;carrier&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; carrier&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parentContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; span &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;kafka.process&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; kind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SpanKind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CONSUMER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;messaging.system&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;kafka&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;messaging.kafka.partition&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;messaging.kafka.offset&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ... more attributes&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// And for batches, custom state stores, batch spans with links...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works, but it’s a lot of ceremony for something we all want to be the default.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-zero-per-service-wiring&quot;&gt;The Solution: Zero Per-Service Wiring&lt;/h2&gt;
&lt;p&gt;With Autotel, the same flow uses &lt;code&gt;withProducerSpan()&lt;/code&gt; and &lt;code&gt;withConsumerSpan()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Producer: API sends to Kafka&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withProducerSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; injectTraceHeaders &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Envelope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withProducerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; messageKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;injectTraceHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        messages&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;correlation_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// traceparent, tracestate, x-correlation-id&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Consumer: Worker processes from Kafka&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withConsumerSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; normalizeHeaders &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; msg &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeHeaders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; messageMeta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; partition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withConsumerSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;email-worker&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    headers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    messageMeta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Your business logic here&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Context is already extracted - you&apos;re in the same trace&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleOrderCreated&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No custom interceptors. No &lt;code&gt;propagator.inject()&lt;/code&gt; / &lt;code&gt;propagator.extract()&lt;/code&gt;. No manual span attribute setting.&lt;/p&gt;
&lt;h3 id=&quot;batch-lineage-for-fan-in&quot;&gt;Batch Lineage for Fan-In&lt;/h3&gt;
&lt;p&gt;When multiple messages feed into one batch, Autotel’s &lt;code&gt;extractBatchLineage()&lt;/code&gt; creates a batch span with links:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; extractBatchLineage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; withProcessingSpan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_HASH&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@demo/observability/kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doFlush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; items &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; batch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  batch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Extract lineage from all contributing messages&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lineage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractBatchLineage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; maxLinks&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withProcessingSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;v1.settlements.batched process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      contextMode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      links&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Links to contributing traces&lt;/span&gt;
      topic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;settlements&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      consumerGroup&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;batcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;span&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;linked_trace_id_count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SEMATTRS_LINKED_TRACE_ID_HASH&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lineage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;linked_trace_id_hash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processBatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The batch span carries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;linked_trace_id_count&lt;/code&gt;: How many traces contributed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;linked_trace_id_hash&lt;/code&gt;: Stable hash for querying “same set of inputs”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;links&lt;/code&gt;: Actual trace links to contributing spans (capped to avoid payload explosion)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;manual-interceptors-vs-autotel&quot;&gt;Manual Interceptors vs Autotel&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual Interceptors&lt;/th&gt;
&lt;th&gt;Autotel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Custom ProducerInterceptor class&lt;/td&gt;
&lt;td&gt;&lt;code&gt;withProducerSpan()&lt;/code&gt; wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom ConsumerInterceptor class&lt;/td&gt;
&lt;td&gt;&lt;code&gt;withConsumerSpan()&lt;/code&gt; wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagator.inject()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;injectTraceHeaders()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual &lt;code&gt;propagator.extract()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatic in &lt;code&gt;withConsumerSpan()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-attribute &lt;code&gt;span.setAttribute()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Semantic conventions automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom state store wrappers for stateful processing&lt;/td&gt;
&lt;td&gt;Same pattern, context flows through stateful processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual batch spans with child spans&lt;/td&gt;
&lt;td&gt;&lt;code&gt;extractBatchLineage()&lt;/code&gt; with links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different code per broker&lt;/td&gt;
&lt;td&gt;Same API (&lt;code&gt;withProducerSpan&lt;/code&gt; / &lt;code&gt;withConsumerSpan&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;one-trace-api-to-batcher&quot;&gt;One Trace, API to Batcher&lt;/h2&gt;
&lt;p&gt;With Autotel, the same checkout request shows as one trace in Jaeger:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Trace: 4bf92f3577b34da6a3ce929d0e0e4736
├─ api: POST /checkout (INTERNAL)
│  └─ orders publish (PRODUCER)
├─ orders process (CONSUMER) - payment-worker
│  └─ payments publish (PRODUCER)
├─ payments process (CONSUMER) - email-worker
│  └─ notifications publish (PRODUCER)
└─ v1.settlements.batched process (CONSUMER) - batcher
   └─ linked_trace_id_count: 5
   └─ linked_trace_id_hash: a3f2c1...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Query &lt;code&gt;correlation_id&lt;/code&gt; to find all related logs, events, and traces. Query &lt;code&gt;linked_trace_id_hash&lt;/code&gt; to find all batches with the same contributing requests. Retries and dead-letter forwarding preserve &lt;code&gt;correlation_id&lt;/code&gt; and trace context so failures remain observable across hops.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;p&gt;Clone the demo and see end-to-end traces in Jaeger:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/event-driven-observability-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; event-driven-observability-demo
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; compose up &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Kafka, Jaeger&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trigger a checkout:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-sX&lt;/span&gt; POST http://localhost:3000/rpc/checkout/start &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content-type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;cartValue&quot;:149.99,&quot;itemCount&quot;:2,&quot;userId&quot;:&quot;usr_123&quot;,&quot;tenantId&quot;:&quot;acme&quot;}&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; jq&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open Jaeger at &lt;code&gt;http://localhost:16686&lt;/code&gt;. Search for the trace. You’ll see one connected trace from API through workers, including batch spans with lineage.&lt;/p&gt;
&lt;h3 id=&quot;evidence-from-a-live-demo-run&quot;&gt;Evidence from a live demo run&lt;/h3&gt;
&lt;p&gt;Here’s actual output from a demo run (2026-02-07):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jaeger trace&lt;/strong&gt; (queried via Jaeger API):&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;traceID&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f259348df534db2fc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spanCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;services&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;worker-email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spans&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout/start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;internal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;api&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events publish&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;producer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.system&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.destination.name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;publish&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.message.key&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;429a7e3408f6408f&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events process&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.system&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kafka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.destination.name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;domain-events&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.consumer.group&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;demo-v1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.partition&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;messaging.kafka.offset&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One trace (&lt;code&gt;429a7e3408f6408f...&lt;/code&gt;) spans &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;worker-email&lt;/code&gt;. The CONSUMER span’s parent is the PRODUCER span — no custom interceptors, no state store wrappers, just &lt;code&gt;withProducerSpan&lt;/code&gt; and &lt;code&gt;withConsumerSpan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/event-driven-observability-demo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/event-driven-observability-demo&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Logging Sucks. Autotel Makes Wide Events the Default</title><link>https://arrangeactassert.com/posts/logging-sucks/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/logging-sucks/</guid><pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Boris is spot on in his &lt;a href=&quot;https://loggingsucks.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Logging Sucks&lt;/a&gt; post&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;logs are optimised for writing, not querying&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He explains why debugging in production feels like archaeology.&lt;/p&gt;
&lt;p&gt;You grep for &lt;code&gt;user-123&lt;/code&gt;, find it logged 47 different ways, then spend an hour correlating timestamps across services.&lt;/p&gt;
&lt;p&gt;We’ve all been there.&lt;/p&gt;
&lt;p&gt;His wide event example nails it:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user_456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;subscription&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;premium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;lifetime_value_cents&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;284700&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;cart&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;item_count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;total_cents&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;coupon_applied&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SAVE20&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;payment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;provider&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stripe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;latency_ms&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1089&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PaymentError&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card_declined&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;stripe_decline_code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;insufficient_funds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One event. High-cardinality keys (&lt;code&gt;user.id&lt;/code&gt;, &lt;code&gt;traceId&lt;/code&gt;). High dimensionality. Queryable.&lt;/p&gt;
&lt;p&gt;But there’s still a gap…&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;I built Autotel to close that gap.&lt;/p&gt;
&lt;p&gt;Autotel makes wide events the default output of traces, producing one canonical structured log per request, chosen via tail sampling.&lt;/p&gt;
&lt;p&gt;By default, Autotel emits a canonical log line for the root/server span (and optionally for spans that match custom filters such as &lt;code&gt;status=ERROR&lt;/code&gt; or &lt;code&gt;duration_ms &amp;gt; 2000&lt;/code&gt;), with tail sampling applied automatically.&lt;/p&gt;
&lt;p&gt;The middleware-based approach still requires wiring, manual context accumulation, and custom sampling logic.&lt;/p&gt;
&lt;p&gt;It works, but it’s a lot of ceremony for something we all want to be the default.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-youre-solving&quot;&gt;The Problem You’re Solving&lt;/h2&gt;
&lt;p&gt;A single checkout produces scattered logs:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;2024-12-20T10:23:45.100Z INFO  Checkout started userId=user-123
2024-12-20T10:23:45.150Z DEBUG Cart loaded cartId=cart-1 itemCount=2
2024-12-20T10:23:45.300Z INFO  Payment processing method=card provider=stripe
2024-12-20T10:23:45.450Z DEBUG Validating payment details
2024-12-20T10:23:45.612Z ERROR Payment failed error=card_declined userId=user-123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To debug, you grep for &lt;code&gt;userId&lt;/code&gt;, then &lt;code&gt;cartId&lt;/code&gt;, then correlate timestamps across services.&lt;/p&gt;
&lt;h2 id=&quot;one-wide-event-zero-per-endpoint-wiring&quot;&gt;One Wide Event. Zero Per-Endpoint Wiring&lt;/h2&gt;
&lt;p&gt;With Autotel, the same checkout produces a single canonical log line (a wide event). No per-endpoint middleware wiring, no finally blocks, no string logs:&lt;/p&gt;
&lt;pre class=&quot;language-jsonc&quot; data-language=&quot;jsonc&quot;&gt;&lt;code class=&quot;language-jsonc&quot;&gt;{
  &quot;level&quot;: 50, // Pino numeric level (50=error, 30=info)
  &quot;name&quot;: &quot;checkout-api&quot;,
  &quot;msg&quot;: &quot;[HTTP POST /api/checkout] Request completed&quot;,
  &quot;http.request.method&quot;: &quot;POST&quot;,
  &quot;http.route&quot;: &quot;/api/checkout&quot;,
  &quot;http.response.status_code&quot;: 500,
  &quot;user.id&quot;: &quot;user-123&quot;,
  &quot;user.subscription&quot;: &quot;premium&quot;,
  &quot;user.account_age_days&quot;: 847,
  &quot;user.lifetime_value_cents&quot;: 284700,
  &quot;request.id&quot;: &quot;req_123&quot;,
  &quot;cart.id&quot;: &quot;cart-1&quot;,
  &quot;cart.item_count&quot;: 2,
  &quot;cart.total_cents&quot;: 7998,
  &quot;cart.coupon_applied&quot;: &quot;SAVE20&quot;,
  &quot;payment.method&quot;: &quot;card&quot;,
  &quot;payment.provider&quot;: &quot;stripe&quot;,
  &quot;payment.latency_ms&quot;: 150,
  &quot;payment.attempt&quot;: 1,
  &quot;error.type&quot;: &quot;PaymentError&quot;,
  &quot;error.code&quot;: &quot;card_declined&quot;,
  &quot;error.message&quot;: &quot;Card declined by issuer&quot;,
  &quot;error.stripe_decline_code&quot;: &quot;insufficient_funds&quot;,
  &quot;service.name&quot;: &quot;checkout-api&quot;,
  &quot;service.version&quot;: &quot;1.0.0&quot;,
  &quot;deployment.environment&quot;: &quot;development&quot;,
  &quot;traceId&quot;: &quot;4bf92f3577b34da6a3ce929d0e0e4736&quot;,
  &quot;spanId&quot;: &quot;00f067aa0ba902b7&quot;,
  &quot;correlationId&quot;: &quot;4bf92f3577b34da6&quot;,
  &quot;duration_ms&quot;: 512.3,
  &quot;status_code&quot;: 2, // OpenTelemetry StatusCode (1=OK, 2=ERROR)
  &quot;status_message&quot;: &quot;Payment failed: card_declined&quot;,
  &quot;timestamp&quot;: &quot;2024-12-20T10:23:45.612Z&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Examples are JSONC for readability. The &lt;code&gt;status_code&lt;/code&gt; field uses OpenTelemetry’s StatusCode enum (OK=1, ERROR=2); for errors, &lt;code&gt;status_message&lt;/code&gt; provides a human-readable description.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;attributeRedactor&lt;/code&gt; in production to redact PII.&lt;/p&gt;
&lt;p&gt;One event with 25+ fields, emitted automatically when the root span completes.&lt;/p&gt;
&lt;p&gt;All attributes use dot-notation (e.g., &lt;code&gt;user.id&lt;/code&gt;) rather than nested objects. Most log stores flatten nested objects into dotted keys anyway.&lt;/p&gt;
&lt;p&gt;Autotel emits that shape directly.&lt;/p&gt;
&lt;h3 id=&quot;which-spans-become-wide-events&quot;&gt;Which spans become wide events?&lt;/h3&gt;
&lt;p&gt;By default, Autotel emits canonical logs for root/server spans (typically your HTTP request handlers).&lt;/p&gt;
&lt;p&gt;You can configure additional spans via filters (e.g., by span.kind, minimum duration, or status).&lt;/p&gt;
&lt;p&gt;This avoids a log volume explosion from every nested span.&lt;/p&gt;
&lt;h3 id=&quot;limits--safety-rails&quot;&gt;Limits &amp;amp; safety rails&lt;/h3&gt;
&lt;p&gt;OpenTelemetry SDKs enforce attribute limits (defaults vary by SDK and are configurable). Autotel respects SDK limits and truncates when exceeded. For large payloads, store IDs and pointers rather than full objects. Use attributeRedactor to redact PII before emission.&lt;/p&gt;
&lt;p&gt;Be intentional about which high-cardinality fields you index vs store: index a small set, store the rest.&lt;/p&gt;
&lt;h2 id=&quot;manual-wide-event-assembly-vs-autotel&quot;&gt;Manual Wide-Event Assembly vs Autotel&lt;/h2&gt;
&lt;p&gt;Manual middleware-based approach builds the event manually:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Manual approach: middleware + manual accumulation&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wideEventMiddleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;request.id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;requestId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;wideEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;duration_ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Then in every handler:&lt;/span&gt;
app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/checkout&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;wideEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Manual approach often ends up with nested blobs that get flattened inconsistently&lt;/span&gt;
  event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subscription&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subscription &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item_count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...more manual accumulation&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Autotel, context accumulates naturally:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trace&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; httpServer &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; processCheckout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CheckoutRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// Standard user attributes via setUser&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// email: user.email, // Redact PII in production&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Custom user attributes via setAttributes&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;user.subscription&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subscription&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;user.account_age_days&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accountAgeDays&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;user.lifetime_value_cents&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lifetimeValueCents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;httpServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;POST&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; route&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/checkout&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; total &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; sum &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;price&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;cart.id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cartId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;cart.item_count&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;cart.total_cents&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;cart.coupon_applied&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coupon&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; payment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;payment.method&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;payment.provider&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;provider&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;payment.latency_ms&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;latencyMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;error.type&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;PaymentError&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;error.code&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;error.can_retry&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canRetry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; payment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// On span end, Autotel emits one structured log line via the configured exporter&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No per-endpoint middleware. No ctx.get(‘wideEvent’). No finally block. (You still need init() setup and exporter configuration, but that’s one-time, not per-endpoint.)&lt;/p&gt;
&lt;p&gt;By default, this can go to stdout (JSON) or to an OTLP/HTTP exporter, depending on your setup.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Manual Wide-Event Assembly&lt;/th&gt;
&lt;th&gt;Autotel Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Build a separate event object&lt;/td&gt;
&lt;td&gt;Use the span as the event source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Middleware to create/attach context&lt;/td&gt;
&lt;td&gt;trace() creates context per function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mutate ctx.get(‘wideEvent’)&lt;/td&gt;
&lt;td&gt;ctx.setAttributes() on the span&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emit in finally block&lt;/td&gt;
&lt;td&gt;Emit on span completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom shouldSample() function&lt;/td&gt;
&lt;td&gt;Built-in tail sampler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;on-otel-wont-save-you&quot;&gt;On “OTel Won’t Save You”&lt;/h2&gt;
&lt;p&gt;He’s right.&lt;/p&gt;
&lt;p&gt;Most OTel setups capture span name, duration, and maybe recordException(error). That’s baseline instrumentation: useful, but it won’t give you queryable context.&lt;/p&gt;
&lt;p&gt;Autotel’s trace() wrapper makes rich instrumentation the path of least resistance.&lt;/p&gt;
&lt;p&gt;You’re already inside the traced function, so adding ctx.setAttributes() is natural. Context accumulates as you process, not in a separate middleware layer.&lt;/p&gt;
&lt;h2 id=&quot;tail-sampling-without-the-logic&quot;&gt;Tail Sampling Without the Logic&lt;/h2&gt;
&lt;p&gt;His sampling function:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shouldSample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status_code &lt;span class=&quot;token operator&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;duration_ms &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;subscription &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;enterprise&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Autotel:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; AdaptiveSampler &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autotel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  service&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;checkout-api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sampler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AdaptiveSampler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    baselineSampleRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    alwaysSampleErrors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    alwaysSampleSlow&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    slowThresholdMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same logic, zero custom code. The sampler evaluates after the span completes (tail sampling), so it sees duration, status, and all attributes before deciding.&lt;/p&gt;
&lt;p&gt;Autotel’s sampler decides whether to emit the canonical log line for each root span; it’s not trying to guarantee whole-trace retention.&lt;/p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;/h2&gt;
&lt;p&gt;If you want to see the shape firsthand, here’s a 60-second demo.&lt;/p&gt;
&lt;p&gt;Quickstart: clone the repo and run the demo:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/jagreehal/autotel
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; autotel/apps/example-canonical-logs
&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; start:server
&lt;span class=&quot;token comment&quot;&gt;# In another terminal: ./demo.sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The demo accepts request_id in the request body, then records it on the span as request.id so the emitted logs stay dot-notated.&lt;/p&gt;
&lt;p&gt;Request IDs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inputs&lt;/strong&gt;: &lt;code&gt;request_id&lt;/code&gt; (ergonomic)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output&lt;/strong&gt;: &lt;code&gt;request.id&lt;/code&gt; (normalised)&lt;/li&gt;
&lt;li&gt;If header exists: also store &lt;code&gt;http.request.header.x-request-id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-queries-you-want&quot;&gt;The Queries You Want&lt;/h2&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subscription &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;premium&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; feature_flags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;new_checkout_flow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Failed payments by decline code:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; count
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;PaymentError&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Slow checkouts for high-value customers:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; data-language=&quot;sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; logs
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; duration_ms &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lifetime_value_cents &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each curl call adds context to the span. Watch the server console on the final step, one canonical log line with everything:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout-api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;http.request.method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;http.route&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/api/checkout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;http.response.status_code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;user.id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user_456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;user.subscription&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;premium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;user.account_age_days&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;847&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;user.lifetime_value_cents&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;284700&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;request.id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;req_test123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;cart.id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cart_xyz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;cart.item_count&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;cart.total_cents&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15999&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;cart.coupon_applied&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SAVE20&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;payment.method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;payment.provider&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stripe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;payment.latency_ms&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;241&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;payment.attempt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;service.name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;checkout-api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;service.version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;deployment.environment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;development&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;traceId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;24e8e520137c5cdcdd59ffd5f653d870&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;spanId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ed53a2d659907201&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;correlationId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;24e8e520137c5cdc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;duration_ms&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.04&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status_code&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2026-01-08T00:26:08.836Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[HTTP POST /api/checkout] Request completed&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The demo supports manual curl commands too:&lt;/p&gt;
&lt;h3 id=&quot;step-1-initialize-request&quot;&gt;Step 1: Initialize request&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST http://localhost:3000/checkout/start &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;request_id&quot;: &quot;req_123&quot;}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-add-user-context&quot;&gt;Step 2: Add user context&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST http://localhost:3000/checkout/auth &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;request_id&quot;: &quot;req_123&quot;, &quot;user_id&quot;: &quot;user_456&quot;}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-add-cart-context&quot;&gt;Step 3: Add cart context&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST http://localhost:3000/checkout/cart &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;request_id&quot;: &quot;req_123&quot;, &quot;cart_id&quot;: &quot;cart_xyz&quot;}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-process-payment&quot;&gt;Step 4: Process payment&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST http://localhost:3000/checkout/payment &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;request_id&quot;: &quot;req_123&quot;}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-5-6-complete--emit-canonical-log&quot;&gt;Step 5-6: Complete + emit canonical log&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST http://localhost:3000/checkout/complete &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;request_id&quot;: &quot;req_123&quot;}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repo: &lt;a href=&quot;https://github.com/jagreehal/autotel&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github.com/jagreehal/autotel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Related: &lt;a href=&quot;https://arrangeactassert.com/posts/otel-is-not-the-three-pillars/&quot;&gt;OpenTelemetry Is Not the Three Pillars&lt;/a&gt; (draft) — siloed stores versus one wide event, with a runnable A/B in &lt;a href=&quot;https://github.com/jagreehal/autotel/tree/main/apps/example-pillars-vs-unified&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;apps/example-pillars-vs-unified&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Reranking: Improving Search Relevance with the AI SDK</title><link>https://arrangeactassert.com/posts/reranking-ai-sdk/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/reranking-ai-sdk/</guid><pubDate>Tue, 23 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Reranking improves search relevance by reordering documents based on their relevance to a query. Unlike embedding-based similarity search, reranking models are specifically trained to understand the relationship between queries and documents, often producing more accurate relevance scores.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reranking&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 512px) 512px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;512&quot; height=&quot;768&quot; src=&quot;https://arrangeactassert.com/_astro/reranking-ai-sdk.isOg22lo_Z1tNRqD.webp&quot; srcset=&quot;/_astro/reranking-ai-sdk.isOg22lo_Z1tNRqD.webp 512w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-problem-vector-search-vs-query-relevance&quot;&gt;The Problem: Vector Search vs Query Relevance&lt;/h2&gt;
&lt;p&gt;Vector search finds semantically similar documents but may miss the most relevant one when the query uses different vocabulary. For example, a query like “How do I get a refund?” might match documents containing “billing” or “payment” (similar financial vocabulary) rather than the document that actually answers the question.&lt;/p&gt;
&lt;h2 id=&quot;two-stage-retrieval-pipeline&quot;&gt;Two-Stage Retrieval Pipeline&lt;/h2&gt;
&lt;p&gt;The recommended approach combines fast vector search with precise reranking:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌───────────────────────────────────────────────────────────────┐
│                    All Documents (1000s)                      │
└──────────────────────────┬────────────────────────────────────┘
                           │
                           ▼
              ┌───────────────────────┐
              │   Vector Search       │
              │   (Fast, Broad)       │
              └──────────┬────────────┘
                         │
                         ▼
              ┌─────────────────────────┐
              │   Top 20-100 Candidates │
              └──────────┬──────────────┘
                         │
                         ▼
              ┌────────────────────────┐
              │   Reranking            │
              │   (Precise, Slower)    │
              └──────────┬─────────────┘
                         │
                         ▼
              ┌─────────────────────────┐
              │   Top 3-10 Results      │
              └─────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Broad retrieval&lt;/strong&gt;: Vector search returns top 20-100 candidates quickly (tune for latency/recall)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Precise reranking&lt;/strong&gt;: Re-score candidates for query relevance using the &lt;a href=&quot;https://ai-sdk.dev/docs/reference/ai-sdk-core/rerank&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;rerank&lt;/code&gt;&lt;/a&gt; function&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;example-customer-support-knowledge-base&quot;&gt;Example: Customer Support Knowledge Base&lt;/h2&gt;
&lt;p&gt;Using a knowledge base with 6 articles, we compare vector search with reranking.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For clarity, examples below rerank small document sets directly. In production, rerank only the top candidates from vector search (see &lt;a href=&quot;#two-stage-retrieval-pipeline&quot;&gt;Two-Stage Retrieval Pipeline&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;vector-search-results&quot;&gt;Vector Search Results&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; embed&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cosineSimilarity &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;How do I get a refund?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queryEmbedding &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;embed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;textEmbeddingModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;nomic-embed-text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; query&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Compare with pre-embedded articles&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; scores &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; articles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;article&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  article&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  score&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cosineSimilarity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queryEmbedding&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;embedding&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; articleEmbeddings&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;embedding&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; topResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scores&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Billing and Payment Methods&lt;/td&gt;
&lt;td&gt;0.6073&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Account Plan Changes&lt;/td&gt;
&lt;td&gt;0.5862&lt;/td&gt;
&lt;td&gt;✓ correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Exporting Your Data&lt;/td&gt;
&lt;td&gt;0.5797&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Vector search ranks “Billing and Payment Methods” #1 because it shares financial vocabulary, but it doesn’t answer the refund question.&lt;/p&gt;
&lt;h3 id=&quot;after-reranking&quot;&gt;After Reranking&lt;/h3&gt;
&lt;p&gt;Using the &lt;a href=&quot;https://ai-sdk.dev/docs/reference/ai-sdk-core/rerank&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;rerank&lt;/code&gt;&lt;/a&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rerankedDocuments &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embeddingReranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embeddinggemma&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; supportArticles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;How do I get a refund?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Original Index&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Account Plan Changes (KB003)&lt;/td&gt;
&lt;td&gt;0.5376&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;How to Reset Your Password (KB001)&lt;/td&gt;
&lt;td&gt;0.2920&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Billing and Payment Methods (KB002)&lt;/td&gt;
&lt;td&gt;0.2815&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Reranking correctly identifies KB003 (which contains “Refunds are available within 14 days”) as the most relevant result.&lt;/p&gt;
&lt;h2 id=&quot;comparison-vector-search-vs-reranking&quot;&gt;Comparison: Vector Search vs Reranking&lt;/h2&gt;
&lt;p&gt;Testing 7 queries designed to expose vocabulary mismatch issues:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query&lt;/th&gt;
&lt;th&gt;Vector Search #1&lt;/th&gt;
&lt;th&gt;After Rerank #1&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;“How do I get a refund?”&lt;/td&gt;
&lt;td&gt;Billing and Payment Methods&lt;/td&gt;
&lt;td&gt;Account Plan Changes ✓&lt;/td&gt;
&lt;td&gt;IMPROVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“money back”&lt;/td&gt;
&lt;td&gt;Billing and Payment Methods&lt;/td&gt;
&lt;td&gt;Account Plan Changes ✓&lt;/td&gt;
&lt;td&gt;IMPROVED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“account protection options”&lt;/td&gt;
&lt;td&gt;Two-Factor Authentication Setup ✓&lt;/td&gt;
&lt;td&gt;Two-Factor Authentication Setup ✓&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“stop my account”&lt;/td&gt;
&lt;td&gt;Account Plan Changes ✓&lt;/td&gt;
&lt;td&gt;Account Plan Changes ✓&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“download all my info”&lt;/td&gt;
&lt;td&gt;Exporting Your Data ✓&lt;/td&gt;
&lt;td&gt;Exporting Your Data ✓&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“forgot my login”&lt;/td&gt;
&lt;td&gt;How to Reset Your Password ✓&lt;/td&gt;
&lt;td&gt;How to Reset Your Password ✓&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“how much can I call the API”&lt;/td&gt;
&lt;td&gt;API Rate Limits ✓&lt;/td&gt;
&lt;td&gt;API Rate Limits ✓&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vector Search accuracy: 5/7 (71%)&lt;/li&gt;
&lt;li&gt;After Reranking: 7/7 (100%)&lt;/li&gt;
&lt;li&gt;Queries improved: 2 (both vocabulary mismatch cases)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;working-with-object-documents&quot;&gt;Working with Object Documents&lt;/h2&gt;
&lt;p&gt;Reranking supports structured documents (JSON objects), making it ideal for searching through databases, emails, or other structured content:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; emails &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-billing@amazon.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Your AWS Invoice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-15&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;team@linear.app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Weekly Project Update&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-14&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noreply@github.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Security alert: new sign-in&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-14&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sales@datadog.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Your Datadog Quote - Enterprise Plan&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-13&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;no-reply@vercel.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Deployment failed: main branch&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-13&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; from&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;hr@company.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Holiday Schedule Reminder&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2024-12-12&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rerankedDocuments &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embeddingReranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embeddinggemma&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; emails&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Find the pricing quote from Datadog&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;From&lt;/th&gt;
&lt;th&gt;Subject&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;mailto:sales@datadog.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;sales@datadog.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Your Datadog Quote - Enterprise Plan&lt;/td&gt;
&lt;td&gt;0.6830&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;mailto:aws-billing@amazon.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;aws-billing@amazon.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Your AWS Invoice&lt;/td&gt;
&lt;td&gt;0.3238&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;mailto:hr@company.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;hr@company.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Holiday Schedule Reminder&lt;/td&gt;
&lt;td&gt;0.1946&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;use-case-rag-context-selection&quot;&gt;Use Case: RAG Context Selection&lt;/h2&gt;
&lt;p&gt;For RAG applications, reranking selects the most relevant documents to include in the LLM context:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; docs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;The createClient() function initializes a new API client...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Authentication uses Bearer tokens...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Rate limiting returns HTTP 429 when exceeded...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Webhooks are sent via POST to your configured endpoint...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Error responses follow RFC 7807 Problem Details format...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Pagination uses cursor-based navigation...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerankedDocuments&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embeddingReranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embeddinggemma&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; docs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;How do I handle API errors?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Use rerankedDocuments for LLM context&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rerankedDocuments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\n\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Error responses follow RFC 7807 Problem Details format…&lt;/td&gt;
&lt;td&gt;0.4662&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Rate limiting returns HTTP 429 when exceeded…&lt;/td&gt;
&lt;td&gt;0.4447&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These top documents would be passed to the LLM for answer generation.&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-results&quot;&gt;Understanding the Results&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;rerank&lt;/code&gt; function returns a comprehensive result object:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rerankedDocuments&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; originalDocuments &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embeddingReranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embeddinggemma&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; supportArticles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;How do I get a refund?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Return value properties:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ranking&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sorted array of &lt;code&gt;{ originalIndex, score, document }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rerankedDocuments&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Documents sorted by relevance (convenience property)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;originalDocuments&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Original documents array (unchanged)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each item in the &lt;code&gt;ranking&lt;/code&gt; array contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;originalIndex&lt;/code&gt;: Position in the original documents array&lt;/li&gt;
&lt;li&gt;&lt;code&gt;score&lt;/code&gt;: Relevance score (higher is more relevant)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;document&lt;/code&gt;: The original document&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Scores are not comparable across models or providers; only relative ordering within a single &lt;code&gt;rerank&lt;/code&gt; call matters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;filtering-by-score-threshold&quot;&gt;Filtering by Score Threshold&lt;/h3&gt;
&lt;p&gt;In production, you may want to discard results with low relevance scores. Filter the &lt;code&gt;ranking&lt;/code&gt; array to only include results above a threshold:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cohere&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;rerank-v3.5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Filter to only include results with score &amp;gt; 0.4&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; relevantResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ranking&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Returns only documents with relevance score above threshold&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reranking-providers--models&quot;&gt;Reranking Providers &amp;amp; Models&lt;/h2&gt;
&lt;p&gt;The AI SDK supports multiple reranking providers. You can use reranking models from:&lt;/p&gt;
&lt;h3 id=&quot;cohere&quot;&gt;Cohere&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cohere &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/cohere&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cohere&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;rerank-v3.5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;amazon-bedrock&quot;&gt;Amazon Bedrock&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; bedrock &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/amazon-bedrock&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bedrock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cohere.rerank-v3-5:0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;ollama-local&quot;&gt;Ollama (Local)&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ollama &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai-sdk-ollama&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embeddingReranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embeddinggemma&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Some reranking models (e.g., Cohere rerankers) are cross-encoders that jointly score query–document pairs, while others (e.g., embedding-based rerankers) trade some accuracy for speed and locality. Cross-encoders typically provide higher accuracy but require API calls, while embedding-based rerankers can run locally with lower latency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;settings&quot;&gt;Settings&lt;/h2&gt;
&lt;h3 id=&quot;top-n-results&quot;&gt;Top-N Results&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;topN&lt;/code&gt; to limit the number of results returned. This is useful for retrieving only the most relevant documents:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cohere &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/cohere&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cohere&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;rerank-v3.5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;doc1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;doc2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;doc3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;doc4&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;doc5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;relevant information&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  topN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Return only top 3 most relevant documents&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;provider-options&quot;&gt;Provider Options&lt;/h3&gt;
&lt;p&gt;Reranking model settings can be configured using &lt;code&gt;providerOptions&lt;/code&gt; for provider-specific parameters. This is particularly useful for handling long documents that might otherwise be truncated:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rerank &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cohere &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/cohere&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ranking &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rerank&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cohere&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reranking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;rerank-v3.5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  documents&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;long document 1...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;long document 2...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;relevant information&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  providerOptions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cohere&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      maxTokensPerDoc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Limit tokens per document&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Examples (provider-specific; check provider docs for available options):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cohere&lt;/strong&gt;: &lt;code&gt;maxTokensPerDoc&lt;/code&gt; - Maximum tokens per document (default varies by model)&lt;/li&gt;
&lt;li&gt;Other providers may expose additional options via &lt;code&gt;providerOptions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;best-practices&quot;&gt;Best Practices&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use vector search for broad retrieval first&lt;/strong&gt;: Retrieve top 20-100 candidates before reranking (tune for latency/recall trade-offs). In practice, reranking typically adds tens of milliseconds for 20–50 documents, depending on model and provider.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tune topN based on use case&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RAG: &lt;code&gt;topN: 3&lt;/code&gt; (small context window)&lt;/li&gt;
&lt;li&gt;Search results: &lt;code&gt;topN: 10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Auto-reply selection: &lt;code&gt;topN: 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitor performance&lt;/strong&gt;: Track click-through rates, RAG answer accuracy, and queries requiring refinement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Vector Search&lt;/th&gt;
&lt;th&gt;With Reranking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Accuracy (top-1)&lt;/td&gt;
&lt;td&gt;71% (5/7)&lt;/td&gt;
&lt;td&gt;100% (7/7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vocabulary mismatch handling&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;+tens of milliseconds for 20–50 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Broad retrieval&lt;/td&gt;
&lt;td&gt;Final ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Reranking improves search relevance by reordering documents based on query-document relationships rather than just semantic similarity. For search systems where precision matters customer support, RAG, email, documentation, reranking improves result quality with minimal code changes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See the &lt;a href=&quot;https://github.com/jagreehal/ai-sdk-reranking-example&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ai-sdk-reranking-example&lt;/a&gt; repository for runnable code.&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>AI Code Needs Rules, Not Rituals (The Proof)</title><link>https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals-the-proof/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals-the-proof/</guid><pubDate>Thu, 18 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I wrote previously about why &lt;a href=&quot;https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals/&quot;&gt;AI-generated code needs rules, not rituals&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AI coding agents aren’t going anywhere. They’re excellent at exploring ideas, generating boilerplate, and moving fast. But speed without reliability just ships bugs faster. And without constraints, AI-generated code is unreliable by default.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prompting is a ritual. Linting is a rule.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is the proof.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Agent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 508px) 508px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;508&quot; height=&quot;491&quot; src=&quot;https://arrangeactassert.com/_astro/ai-code-needs-rules-not-rituals-the-proof.BQgdl3gw_ZwTPeC.webp&quot; srcset=&quot;/_astro/ai-code-needs-rules-not-rituals-the-proof.BQgdl3gw_ZwTPeC.webp 508w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-prompts-dont-cut-it&quot;&gt;Why Prompts Don’t Cut It&lt;/h2&gt;
&lt;p&gt;Most teams try to control AI output with instructions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CLAUDE.md&lt;/li&gt;
&lt;li&gt;AGENTS.md&lt;/li&gt;
&lt;li&gt;Cursor rules&lt;/li&gt;
&lt;li&gt;Commands / Sub-agents / Skills&lt;/li&gt;
&lt;li&gt;Long prompt templates&lt;/li&gt;
&lt;li&gt;Carefully curated examples&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this helps. None of it guarantees anything.&lt;/p&gt;
&lt;p&gt;Prompting is probabilistic. You’re hoping the model remembers your preferences and applies them consistently across contexts. Sometimes it does. Sometimes it doesn’t. Often it lands in the worst possible place: almost correct.&lt;/p&gt;
&lt;p&gt;Almost correct is how bugs slip through review.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;a-real-example&quot;&gt;A Real Example&lt;/h2&gt;
&lt;p&gt;My preference in JavaScript is that functions should take a single object parameter rather than positional arguments.&lt;/p&gt;
&lt;p&gt;I’ve explained this preference to AI tools. I’ve shown examples. I’ve reinforced it repeatedly.&lt;/p&gt;
&lt;p&gt;And I still get this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌ Generated anyway&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateDiscount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;price&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; taxRate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; couponValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes the model listens. Sometimes it doesn’t. That inconsistency alone disqualifies prompting as enforcement.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-rules-actually-do&quot;&gt;What Rules Actually Do&lt;/h2&gt;
&lt;p&gt;Encode the preference as a lint rule. I built &lt;a href=&quot;https://github.com/jagreehal/eslint-plugin-prefer-object-params&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eslint-plugin-prefer-object-params&lt;/a&gt; for exactly this. Now the bad version can’t survive:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;error  Prefer object params over positional arguments  prefer-object-params&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No retries. No “please remember next time.”
The rule fires, the code fails, and the agent fixes it.&lt;/p&gt;
&lt;p&gt;That’s enforcement.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;but-what-if-no-rule-exists&quot;&gt;“But What If No Rule Exists?”&lt;/h2&gt;
&lt;p&gt;Write one. Or have the agent write one.&lt;/p&gt;
&lt;p&gt;That’s exactly what I did with the plugin above.&lt;/p&gt;
&lt;p&gt;Now, AI-generated code hits the same walls as human-written code. Every generation has to pass. The output becomes deterministic, reviewable, and aligned with how I actually want the code to look.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-this-catches&quot;&gt;What This Catches&lt;/h2&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌ Easy to miss in review&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sendEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;to&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; subject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bcc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;✖ prefer-object-params: Use a single options object instead of positional arguments&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI slop hits a brick wall.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;beyond-style&quot;&gt;Beyond Style&lt;/h2&gt;
&lt;p&gt;These examples are structural because they’re easy to show: parameters, signatures, conventions. But the principle scales.&lt;/p&gt;
&lt;p&gt;Some rules live in linters.
Some live in type systems.
Some live in tests and runtime validation.&lt;/p&gt;
&lt;p&gt;Complex business logic still needs tests. Security rules still need audits.&lt;/p&gt;
&lt;p&gt;The point isn’t that lint rules replace everything. The point is that anything you can make deterministic, you should.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-reality&quot;&gt;The Reality&lt;/h2&gt;
&lt;p&gt;Prompting is great for exploration. Production code needs rules.&lt;/p&gt;
&lt;p&gt;If AI is writing code in your repo, constrain it with the same systems you already trust: linters, types, tests, and CI checks. That’s how you get the speed AI promises without sacrificing reliability.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rituals hope. Rules enforce.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>AI Code Needs Rules, Not Rituals</title><link>https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-code-needs-rules-not-rituals/</guid><pubDate>Mon, 20 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Coding agents are here to stay, and I know I’m absolutely right about that. While we’re all getting used to workflows using AI-powered coding agents, we now live in the world of dark arts and rituals.&lt;/p&gt;
&lt;p&gt;We spend hours tweaking prompts, creating elaborate &lt;code&gt;Claude.md&lt;/code&gt;, &lt;code&gt;Agents.md&lt;/code&gt; and other files formatted in a particular way, stored in a particular way essentially performing black magic to &lt;em&gt;hope&lt;/em&gt; our LLM agent adheres to our team’s best practices and coding patterns.&lt;/p&gt;
&lt;p&gt;On a good day, it works. On others, the behaviour is random.&lt;/p&gt;
&lt;p&gt;Here’s the problem: &lt;strong&gt;Random is not good enough for production.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We’re trying to force a non-deterministic, generative tool to be a deterministic rule-follower. This is the wrong approach.&lt;/p&gt;
&lt;p&gt;Instead, we should let AI do what it does best: be creative and generative, helping us achieve and realise our desired outcomes while following instructions and examples for how, what, and where it should generate.&lt;/p&gt;
&lt;p&gt;My advice? Stop relying on hope-driven prompting. Start using linters to &lt;em&gt;guarantee&lt;/em&gt; your standards.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Agent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;768&quot; src=&quot;https://arrangeactassert.com/_astro/ai-code-needs-rules-not-rituals.c79RN2jm_Z1BsTox.webp&quot; srcset=&quot;/_astro/ai-code-needs-rules-not-rituals.c79RN2jm_1wcW6L.webp 640w, /_astro/ai-code-needs-rules-not-rituals.c79RN2jm_qG2V2.webp 750w, /_astro/ai-code-needs-rules-not-rituals.c79RN2jm_1YjLm8.webp 828w, /_astro/ai-code-needs-rules-not-rituals.c79RN2jm_Z1JMu4b.webp 1080w, /_astro/ai-code-needs-rules-not-rituals.c79RN2jm_Z18qyTw.webp 1280w, /_astro/ai-code-needs-rules-not-rituals.c79RN2jm_Z1BsTox.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-problem-with-hope-driven-development&quot;&gt;The Problem with Hope-Driven Development&lt;/h2&gt;
&lt;p&gt;After months of working with AI coding agents across different projects, I’ve noticed a pattern that’s become impossible to ignore. We’ve all been there: spending hours crafting the perfect prompt, organising our project files just so, and crossing our fingers that this time, the AI will follow our coding standards.&lt;/p&gt;
&lt;p&gt;But here’s what I’ve learned: &lt;strong&gt;hope is not a strategy for production code.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this article, I’ll show you why relying on prompts alone is fundamentally flawed, and how to build a deterministic system that guarantees your AI-generated code meets your standards. You’ll discover practical examples of linting rules that solve real problems, learn how to create a self-correcting AI workflow, and understand why this approach future-proofs your development process.&lt;/p&gt;
&lt;p&gt;By the end, you’ll have a concrete plan to stop hoping for quality and start engineering it.&lt;/p&gt;
&lt;h2 id=&quot;a-lesson-from-the-trenches&quot;&gt;A Lesson from the Trenches&lt;/h2&gt;
&lt;p&gt;Last month, I spent three hours debugging why our AI-generated React components were causing bundle size warnings. The issue? Inconsistent import patterns across 47 files. Some used &lt;code&gt;import { z } from &apos;zod&apos;&lt;/code&gt;, others used &lt;code&gt;import * as z from &apos;zod&apos;&lt;/code&gt;. Our AI agent had been trained on mixed examples and couldn’t maintain consistency.&lt;/p&gt;
&lt;p&gt;That’s when I realised: we were asking the wrong question. Instead of “How can we make our AI more consistent?”, we should have been asking “How can we guarantee consistency regardless of AI behaviour?”&lt;/p&gt;
&lt;p&gt;The solution wasn’t better prompting—it was better tooling.&lt;/p&gt;
&lt;h2 id=&quot;example-1-the-subtle-art-of-imports&quot;&gt;Example 1: The Subtle Art of Imports&lt;/h2&gt;
&lt;p&gt;It’s not just about correctness; consistency and performance matter too.&lt;/p&gt;
&lt;p&gt;Consider this common Zod import:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌ This *can* pull in unnecessary bytes depending on your bundler&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Some bundlers may not tree-shake this effectively&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many teams, aiming for optimal bundle sizes, prefer this pattern:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ✅ This is often more efficient and easier for tree-shaking&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Bundlers can more reliably eliminate unused exports&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; z &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Will your AI agent know this? Maybe. Will it remember 100% of the time? Absolutely not.&lt;/p&gt;
&lt;p&gt;Instead of adding this trivia to a prompt file you hope the AI reads, just add a dedicated lint rule. The community has already solved this with &lt;a href=&quot;https://github.com/samchungy/eslint-plugin-import-zod&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eslint-plugin-import-zod&lt;/a&gt;. Using this lint rule ensures that both AI and we will use the most optimal way for importing Zod.&lt;/p&gt;
&lt;h2 id=&quot;example-2-the-react-hooks-minefield&quot;&gt;Example 2: The React Hooks Minefield&lt;/h2&gt;
&lt;p&gt;Let’s talk about React. The Rules of Hooks are notoriously tricky. There’s advice, for the advice, for which there is more guidance, and then a clarification on that makes it confusing for us, and who knows what patterns and docs AI has trained on.&lt;/p&gt;
&lt;p&gt;With so many edge cases, models often make hook mistakes.&lt;/p&gt;
&lt;p&gt;Thankfully, the React team provides a deterministic solution for this: &lt;a href=&quot;https://react.dev/reference/eslint-plugin-react-hooks&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eslint-plugin-react-hooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is where the “prompting” strategy truly falls apart. That ESLint plugin was recently updated to support the new React Compiler and the &lt;code&gt;useEffectEvent&lt;/code&gt; API.&lt;/p&gt;
&lt;p&gt;Now, ask yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does your AI agent, trained on a massive (but older) corpus of code, know about these cutting-edge rules?&lt;/li&gt;
&lt;li&gt;Can you guarantee it will apply them correctly, every time?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the &lt;strong&gt;“LLM Lag”&lt;/strong&gt; in action. Remember: LLMs are trained on older codebases. They often won’t know the latest patterns or subtle rule changes. While MCP servers such as context7 can help, it’s still up to your coding tool to first use the tools available and then act on the information retrieved.&lt;/p&gt;
&lt;p&gt;In contrast, ESLint and other linting tools provide the deterministic check you need, ensuring that even AI-generated code adheres to the most modern React practices.&lt;/p&gt;
&lt;h2 id=&quot;why-eslint-because-determinism-is-your-reassurance&quot;&gt;Why ESLint? Because Determinism is Your Reassurance&lt;/h2&gt;
&lt;p&gt;In a world of AI randomness, ESLint delivers determinism.&lt;/p&gt;
&lt;p&gt;Why risk your code quality and standards on chance?&lt;/p&gt;
&lt;p&gt;Integrating ESLint into your workflow provides a reliable safety net and ensures code meets production quality standards.&lt;/p&gt;
&lt;h2 id=&quot;the-self-correcting-ai-workflow&quot;&gt;The “Self-Correcting” AI Workflow&lt;/h2&gt;
&lt;p&gt;This is where it gets truly powerful. You don’t just run the linter at the end. You build a feedback loop.&lt;/p&gt;
&lt;p&gt;Imagine this workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The AI coding agent generates a new component or feature.&lt;/li&gt;
&lt;li&gt;A hook (e.g., a file-save hook in your IDE, or post-tool use hook ) that runs &lt;code&gt;eslint --fix&lt;/code&gt; on the generated files.&lt;/li&gt;
&lt;li&gt;The agent sees the linting errors or the resulting code changes.&lt;/li&gt;
&lt;li&gt;In its next turn, the AI can self-correct based on the deterministic feedback from the linter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The AI remains fast, but lint feedback keeps code on track with your quality standards.&lt;/p&gt;
&lt;p&gt;Here’s how this self-correcting workflow looks in practice:&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;graph TD
    A[AI Agent Generates Code] --&amp;gt; B[File Save Hook Triggers]
    B --&amp;gt; C[ESLint Runs Automatically]
    C --&amp;gt; D{Linting Errors?}
    D --&amp;gt;|Yes| E[ESLint Auto-Fixes Issues]
    D --&amp;gt;|No| F[Code Meets Standards]
    E --&amp;gt; G[AI Sees Fixed Code]
    G --&amp;gt; H[AI Learns from Corrections]
    H --&amp;gt; I[Next Generation Improved]
    F --&amp;gt; I
    I --&amp;gt; A
    
    style A fill:#e1f5fe
    style C fill:#f3e5f5
    style E fill:#e8f5e8
    style F fill:#e8f5e8
    style H fill:#fff3e0
&lt;/pre&gt;
&lt;p&gt;This creates a continuous improvement loop where the AI learns from deterministic feedback, becoming more aligned with your standards over time.&lt;/p&gt;
&lt;h2 id=&quot;prevent-vendor-lock-in&quot;&gt;Prevent Vendor Lock-in&lt;/h2&gt;
&lt;p&gt;While we hope for standardisation, the AI market is a fast-moving, innovative space. Today’s way of doing things becomes the old way. I’ve seen this with Cursor, and now we have skills with Claude. I use a variety of AI tools as they all have their strengths and weaknesses, and so linting rules offer the consistency I can rely on.&lt;/p&gt;
&lt;h2 id=&quot;the-added-bonus-future-proofing-your-codebase&quot;&gt;The Added Bonus: Future-Proofing Your Codebase&lt;/h2&gt;
&lt;p&gt;This workflow brings huge long-term benefits.&lt;/p&gt;
&lt;p&gt;Next month, when a new React pattern emerges or your team discovers a new performance optimisation, you don’t need to retrain or re-prompt your AI.&lt;/p&gt;
&lt;p&gt;You just add the new ESLint rule.&lt;/p&gt;
&lt;p&gt;From that moment on, you can be assured that any AI-generated code will follow this new best practice.&lt;/p&gt;
&lt;p&gt;Even better, you can now ask the AI to help you refactor your existing codebase, and the linter will act as its guide, ensuring the improvements are applied consistently.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop hoping for quality. Engineer it.&lt;/strong&gt; Replace hope-driven prompting with deterministic linting rules that guarantee your standards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build a self-correcting feedback loop.&lt;/strong&gt; Integrate ESLint into your AI workflow so the agent learns from deterministic corrections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future-proof your approach.&lt;/strong&gt; When new best practices emerge, add a lint rule rather than updating prompts across multiple files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintain consistency across tools.&lt;/strong&gt; Linting rules work regardless of which AI tool you’re using, preventing vendor lock-in.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;your-next-steps&quot;&gt;Your Next Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Audit your current prompts.&lt;/strong&gt; Identify which “rules” in your prompt files could be enforced with linting instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start with one rule.&lt;/strong&gt; Pick the most common inconsistency in your AI-generated code and create an ESLint rule for it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up the feedback loop.&lt;/strong&gt; Configure your IDE or build process to run &lt;code&gt;eslint --fix&lt;/code&gt; automatically on AI-generated files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gradually expand.&lt;/strong&gt; Add more rules as you discover patterns, building a comprehensive quality system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;a-balanced-approach&quot;&gt;A Balanced Approach&lt;/h2&gt;
&lt;p&gt;This isn’t about abandoning prompts entirely. High-level guidance, team conventions, and architectural decisions still benefit from well-crafted prompts. Those still leak out of a long context. Before the agent writes a line, somebody has to hold the floodplain and the wind, which is the &lt;a href=&quot;https://arrangeactassert.com/posts/the-dollar-house-still-needs-a-site-survey/&quot;&gt;site survey&lt;/a&gt;. But for the nitty-gritty details, import patterns, hook usage, naming conventions, let your linters do the heavy lifting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stop hoping for quality. Engineer it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let your AI be the generative engine, and let your linters be the deterministic, ever-updatable guardrails that future-proof your codebase.&lt;/p&gt;
&lt;p&gt;When a new best practice emerges, you won’t need to re-prompt your markdown files; you’ll just add a rule.&lt;/p&gt;
</content:encoded></item><item><title>Agent: The Sugar Syntax of streamText</title><link>https://arrangeactassert.com/posts/agent-sugar-syntax-streamtext/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/agent-sugar-syntax-streamtext/</guid><pubDate>Fri, 19 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;For most of us, AI still feels like a black box. We send it a prompt and we get back a blob of text. Maybe we write some code to call a tool; maybe we juggle a few callbacks. We tell ourselves that this is just how things work: a model can only generate tokens, and tools can only run in our code.&lt;/p&gt;
&lt;p&gt;But what if this mental model is the problem?&lt;/p&gt;
&lt;p&gt;In this post I want to argue that the Agent pattern in the AI SDK is as revolutionary for AI development as &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; were for React. Just like React’s client/server directives annotate where code runs across the network, the Agent API annotates where logic runs across the AI/model boundary.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Agent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 500px) 500px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;500&quot; height=&quot;666&quot; src=&quot;https://arrangeactassert.com/_astro/agent-stream-text.QviLcBSG_ZijOS3.webp&quot; srcset=&quot;/_astro/agent-stream-text.QviLcBSG_ZijOS3.webp 500w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Even if you never use it, understanding why it exists will change how you think about building AI applications.&lt;/p&gt;
&lt;h2 id=&quot;two-worlds-stitched-together&quot;&gt;Two worlds stitched together&lt;/h2&gt;
&lt;p&gt;Let’s start with the basics. The &lt;a href=&quot;https://ai-sdk.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AI SDK&lt;/a&gt; exposes two ways to talk to language models:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text#generatetext&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;generateText&lt;/a&gt; / &lt;a href=&quot;https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text#streamtext&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;streamText&lt;/a&gt;, which directly stream tokens back from an LLM.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ai-sdk.dev/docs/reference/ai-sdk-core/agent#agent&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Agent&lt;/a&gt;, an object-oriented facade built on top of those functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The raw &lt;code&gt;streamText&lt;/code&gt; function does a lot. It starts streaming immediately, supports callbacks for chunks and errors, and exposes helper functions for sending responses. The result object contains rich information: the generated content, reasoning, tool calls and results, usage data and more. In other words, &lt;code&gt;streamText&lt;/code&gt; already knows how to handle multi-step conversations, execute tools, and recover from errors. It is the low-level primitive.&lt;/p&gt;
&lt;p&gt;The Agent class, by contrast, is almost boring.&lt;/p&gt;
&lt;p&gt;The official docs describe it as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“a structured way to encapsulate LLM configuration, tools, and behavior into reusable components”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It accepts the same settings you would pass to &lt;code&gt;generateText&lt;/code&gt; or &lt;code&gt;streamText&lt;/code&gt;. Under the hood, its &lt;code&gt;generate&lt;/code&gt; and &lt;code&gt;stream&lt;/code&gt; methods literally forward those options to the corresponding functions.&lt;/p&gt;
&lt;p&gt;So why bother?&lt;/p&gt;
&lt;h2 id=&quot;the-old-way&quot;&gt;The old way&lt;/h2&gt;
&lt;p&gt;To appreciate the difference, imagine you are building a simple weather bot with raw &lt;code&gt;streamText&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Your code might look like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; streamText &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; openai &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/openai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;streamText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;openai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;You are a helpful assistant.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;What is the weather in NYC?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;getWeather&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Get the current weather&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;inputSchema&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; location &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// call your weather API&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;temperature&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sunny&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;onError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;onFinish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; toolCalls &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Stream finished; tools with execute already ran.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// For manual handling, omit execute and process toolCalls.&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// consume the async iterator&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; chunk &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textStream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chunk&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works fine, but notice how much boilerplate you are dealing with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have to pass the same model, system prompt and tools every time.&lt;/li&gt;
&lt;li&gt;You manually consume the &lt;code&gt;textStream&lt;/code&gt; and handle &lt;code&gt;onError&lt;/code&gt; / &lt;code&gt;onFinish&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You decide when to stop streaming, when to call tools and when to finish.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You are writing orchestration logic rather than focusing on your problem. Every detail about streaming, tool calls and state management lives in your code.&lt;/p&gt;
&lt;h2 id=&quot;the-agent-way&quot;&gt;The Agent way&lt;/h2&gt;
&lt;p&gt;Now look at the same logic expressed with an Agent:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Agent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; openai &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@ai-sdk/openai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; assistant &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Agent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;openai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;You are a helpful assistant.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;getWeather&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Get the current weather&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;inputSchema&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; location &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;temperature&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sunny&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; assistant&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;What is the weather in NYC?&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. There are no callbacks to hook, no loop to write. When the model decides to call a tool, the SDK calls it for you. When the model finishes generating text, the stream ends. The same configuration is reused for every call to the agent.&lt;/p&gt;
&lt;p&gt;Under the hood, nothing magical is happening. The Agent’s &lt;code&gt;stream&lt;/code&gt; method merges your prompt with the agent’s configuration and forwards it to &lt;code&gt;streamText&lt;/code&gt;. Agent methods return the same result objects as &lt;code&gt;generateText&lt;/code&gt;/&lt;code&gt;streamText&lt;/code&gt; and reuse most of the same settings. Yet this tiny abstraction has outsized effects on how you structure your code.&lt;/p&gt;
&lt;h2 id=&quot;why-does-this-matter&quot;&gt;Why does this matter?&lt;/h2&gt;
&lt;h3 id=&quot;from-configuration-to-behavior&quot;&gt;From configuration to behavior&lt;/h3&gt;
&lt;p&gt;When you call &lt;code&gt;streamText&lt;/code&gt; directly, you think procedurally:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Call the model.&lt;/strong&gt; Set up the model, system prompt and tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle the stream.&lt;/strong&gt; Consume tokens, watch for tool calls, call tools, feed results back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage state.&lt;/strong&gt; Keep track of previous messages, step counts and stop conditions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle errors.&lt;/strong&gt; Log and recover from exceptions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With an Agent you think declaratively:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Define an agent.&lt;/strong&gt; Specify the model, system prompt, tools and stopping rules once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Give it tasks.&lt;/strong&gt; Pass a prompt to &lt;code&gt;generate()&lt;/code&gt; or &lt;code&gt;stream()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Let it orchestrate.&lt;/strong&gt; The SDK manages streaming, tool calls and state.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In other words, the Agent doesn’t add new features; it removes cognitive overhead. You stop thinking about configuration and start thinking about behavior. The agent becomes a reusable AI entity in your codebase rather than a loose configuration object.&lt;/p&gt;
&lt;h3 id=&quot;reusability-and-encapsulation&quot;&gt;Reusability and encapsulation&lt;/h3&gt;
&lt;p&gt;Because an agent is a class, you can instantiate as many as you need with different roles. Here’s a more advanced example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codeReviewer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Agent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;openai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a senior software engineer conducting code reviews.
You can read files, analyze code quality and suggest improvements.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; readFileTool&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;analyzeComplexity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; complexityTool&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;suggestRefactoring&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; refactorTool&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;checkTests&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; testingTool
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;stopWhen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stepCountIs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// maximum five steps&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; review &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; codeReviewer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Please review the file src/utils/data-processor.js&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’re not manually iterating over tool calls anymore. You define the &lt;strong&gt;capabilities&lt;/strong&gt; of an assistant and let it figure out how to achieve its goal. Each call to &lt;code&gt;stream()&lt;/code&gt; reuses the same tools, system prompt and stopping conditions; the only thing that changes is the prompt. As the docs note, the Agent encapsulates configuration so you can reuse it across your application.&lt;/p&gt;
&lt;h2 id=&quot;a-bigger-mental-model-ai-as-a-single-program&quot;&gt;A bigger mental model: AI as a single program&lt;/h2&gt;
&lt;p&gt;This abstraction hints at a deeper mental model. In the old world, your application and the model live in separate universes. The model only knows how to generate text; your code only knows how to run tools. There is no way to express that a piece of code wants to orchestrate both. You glue them together with &lt;code&gt;fetch()&lt;/code&gt; or manual loops.&lt;/p&gt;
&lt;p&gt;Agents invite you to see your application and the AI model as &lt;strong&gt;one program split across two execution contexts&lt;/strong&gt;. You describe an assistant’s behavior (its model, prompt and tools) and then call it like any other method. The AI decides when to call your tools; your tools feed their results back into the model. Each generation step is either a piece of text or a tool invocation, and the loop continues until a stopping condition is met. You no longer need to manage the loop yourself; you think at a higher level.&lt;/p&gt;
&lt;p&gt;Here’s a visual way to think about it:&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;graph TD
  subgraph &quot;Your Code&quot;
    A[Define Agent] --&amp;gt; B[&quot;Call agent.stream()&quot;]
  end

  subgraph &quot;AI SDK&quot;
    B --&amp;gt; C{streamText}
    C --&amp;gt; D[LLM]
    C --&amp;gt; E[Tool Executor]
    E --&amp;gt; D
  end

  subgraph &quot;Agent Configuration&quot;
    F[Model]
    G[System Prompt]
    H[Tools]
    I[Stop Conditions]
  end

  F -.-&amp;gt; B
  G -.-&amp;gt; B
  H -.-&amp;gt; B
  I -.-&amp;gt; B
&lt;/pre&gt;
&lt;p&gt;The dashed lines represent configuration that the agent holds on to. Whenever you call &lt;code&gt;agent.stream()&lt;/code&gt;, that configuration is merged with your prompt and passed to &lt;code&gt;streamText&lt;/code&gt;. The loop of model → tool call → model continues until the model generates text or hits a stop condition.&lt;/p&gt;
&lt;h2 id=&quot;cognitive-load-and-api-design&quot;&gt;Cognitive load and API design&lt;/h2&gt;
&lt;p&gt;So what is the big deal out of what is essentially a convenience wrapper?&lt;/p&gt;
&lt;p&gt;Because &lt;strong&gt;good API design is as much about psychology as it is about features&lt;/strong&gt;. When all we had was &lt;code&gt;streamText&lt;/code&gt;, we had to think about the network protocol, callbacks and error handling. We were coding at the wrong level of abstraction.&lt;/p&gt;
&lt;p&gt;By introducing a small facade, the AI SDK changes our default mental model. It makes the boundary between your code and the model explicit but frictionless. You can still drop down to &lt;code&gt;streamText&lt;/code&gt; for fine-grained control, for example, when you need to handle each chunk yourself or implement custom loop logic. But for most use cases, an Agent lets you focus on what your AI should do, not how it should do it.&lt;/p&gt;
&lt;p&gt;This reminds me of the leap from writing XHR calls to using &lt;code&gt;fetch()&lt;/code&gt; / async functions; or from manual DOM updates to using React components. Each leap didn’t add something we couldn’t technically do before; it removed something we no longer had to think about. That’s why I think the Agent pattern will outlive the current library. It’s not just sugar, it’s a mental model.&lt;/p&gt;
&lt;h2 id=&quot;beyond-the-basics-building-ai-entities&quot;&gt;Beyond the basics: building AI entities&lt;/h2&gt;
&lt;p&gt;Once you start seeing agents as reusable AI entities, you begin to imagine more ambitious scenarios. For example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codebaseAgent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Agent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;openai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;gpt-4o&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;You understand this entire codebase.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    readFile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    searchCode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    runTests&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    deployCode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    analyzePerformance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    reviewPRs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    updateDocs
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;stopWhen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stepCountIs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Same agent helps with multiple tasks&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; codebaseAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Refactor the authentication system&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; codebaseAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Write API documentation for the billing module&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; codebaseAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Investigate why the build is failing&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the agent isn’t just a function call; it’s a &lt;strong&gt;team member&lt;/strong&gt; with a persistent identity. You might add memory so it remembers previous files it has read, or share context so it builds up a knowledge base. At this point, you’re not building AI features anymore. You’re building AI entities with their own capabilities, constraints and state.&lt;/p&gt;
&lt;h2 id=&quot;the-meta-lesson&quot;&gt;The meta-lesson&lt;/h2&gt;
&lt;p&gt;The relationship between Agents and &lt;code&gt;streamText&lt;/code&gt; illustrates an important principle: sometimes the most significant innovation is not a new capability, but a new way of thinking about existing capabilities.&lt;/p&gt;
&lt;p&gt;The Agent class doesn’t change what &lt;code&gt;streamText&lt;/code&gt; can do; it changes how you think about orchestrating AI and tools. It allows you to see your application and the model as a single program and to express your intent declaratively.&lt;/p&gt;
&lt;p&gt;When you design APIs, ask yourself: What mental model am I promoting? Are you forcing your users to juggle configuration and boilerplate, or are you giving them the right abstractions so they can focus on behavior?&lt;/p&gt;
&lt;p&gt;The Agent pattern shows that a tiny bit of sugar can make a complex system feel intuitive and human. And that might be the most important feature of all.&lt;/p&gt;
</content:encoded></item><item><title>Build Safer, Faster, and More Reliable AI Apps with AI SDK Middleware</title><link>https://arrangeactassert.com/posts/ai-sdk-middleware-tutorial/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-sdk-middleware-tutorial/</guid><pubDate>Wed, 27 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Having recently built an AI Guardrails library for the &lt;a href=&quot;https://ai-sdk.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AI SDK&lt;/a&gt;, I wanted to share what I learned along the way. This post will walk you through how you can write your own middleware, and why it’s such a game-changer for building robust AI applications.&lt;/p&gt;
&lt;p&gt;Design AI features that are safer, faster, and easier to evolve by layering language model middleware. This guide explains how to use AI SDK middleware to transform inputs, post-process outputs, enforce safety rules, cache results, observe performance, and handle streaming using a clean, composable approach aligned with &lt;a href=&quot;https://ai-sdk.dev/docs/recipes/middleware&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;official guidance&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-middleware&quot;&gt;Why middleware&lt;/h2&gt;
&lt;p&gt;Middleware enables you to intercept and modify calls to a language model without altering business logic. Add features incrementally, reuse them across apps, and standardize behavior across providers.&lt;/p&gt;
&lt;h2 id=&quot;when-to-use-middleware&quot;&gt;When to use middleware&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You need consistent guardrails or validation across multiple models/providers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You want caching, rate limiting, or cost controls without changing app logic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You need to enrich prompts or normalize outputs at a single integration point&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You want structured, uniform observability and error handling&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;quickstart&quot;&gt;Quickstart&lt;/h2&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; wrapLanguageModel &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; enhancedModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapLanguageModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; yourModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  middleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; yourMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-middleware-interface&quot;&gt;The middleware interface&lt;/h3&gt;
&lt;p&gt;Implement one or more of these hooks:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; yourMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;transformParams&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; params &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// modify request options for both generate and stream&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// post-process non-streaming results&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;wrapStream&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doStream &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// transform streaming results&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;recommended-middleware-order&quot;&gt;Recommended middleware order&lt;/h2&gt;
&lt;p&gt;Apply middleware in this order for predictable behavior and performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Safety and validation first (block/clean unsafe input early)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Caching early (short-circuit on cache hit)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transformations next (input/output shaping)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitoring and logging last (observe the final shape and timing)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapLanguageModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; yourModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  middleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    safetyMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1) block/validate&lt;/span&gt;

    cachingMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 2) short-circuit identical calls&lt;/span&gt;

    inputEnhancerMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 3) transform inputs&lt;/span&gt;

    outputProcessorMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 4) transform outputs&lt;/span&gt;

    monitoringMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 5) observe last&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;
flowchart LR



  A[User request] --&amp;gt; B[Safety &amp;amp; Validation]

  B --&amp;gt; C{Blocked?}

  C --&amp;gt;|Yes| X[Return safe fallback]

  C --&amp;gt;|No| D[Caching]

  D --&amp;gt; E{Cache hit?}

  E --&amp;gt;|Yes| Y[Return cached result]

  E --&amp;gt;|No| F[Input Transformation]

  F --&amp;gt; G[Model Inference]

  G --&amp;gt; H[Output Processing]

  H --&amp;gt; I[Monitoring / Logging]

  I --&amp;gt; J[Response]

&lt;/pre&gt;
&lt;h2 id=&quot;core-patterns&quot;&gt;Core patterns&lt;/h2&gt;
&lt;h3 id=&quot;1-input-transformation&quot;&gt;1) Input transformation&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inputEnhancerMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;transformParams&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; params &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; enhancedPrompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;system&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;You are a helpful assistant.&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; enhancedPrompt &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-output-processing&quot;&gt;2) Output processing&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; outputProcessorMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\s+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-safety-and-request-blocking&quot;&gt;3) Safety and request blocking&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; safetyMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; params &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;toText&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; p &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        p &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; p &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;object&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;content&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; promptText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\b(hack|exploit|bypass|malicious)\b&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;promptText&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;I cannot process this request.&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        finishReason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;other&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        warnings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-streaming-transformation&quot;&gt;4) Streaming transformation&lt;/h3&gt;
&lt;p&gt;Handle multiple stream part types for fine-grained control.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; streamingMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapStream&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doStream &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transformStream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransformStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chunk&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; controller&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chunk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text-delta&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; filtered &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; chunk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;delta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\b(harmful|bad)\b&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;***&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            controller&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;chunk&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delta&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; filtered &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tool-call&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tool-result&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;response-metadata&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            controller&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enqueue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chunk&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stream&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipeThrough&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transformStream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;rest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;
flowchart TD



  S[Model Stream] --&amp;gt; T[TransformStream]

  T --&amp;gt;|text_delta| D[Filter delta - redact words]

  D --&amp;gt; U[Emit filtered text_delta]

  T --&amp;gt;|tool_call| C[Pass-through tool_call]

  T --&amp;gt;|tool_result| R[Pass-through tool_result]

  T --&amp;gt;|response_metadata| M[Pass-through metadata]

  T --&amp;gt;|error| E[Pass-through error]

  U --&amp;gt; K[Client]

  C --&amp;gt; K

  R --&amp;gt; K

  M --&amp;gt; K

  E --&amp;gt; K

&lt;/pre&gt;
&lt;h3 id=&quot;5-monitoring-and-logging&quot;&gt;5) Monitoring and logging&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; monitoringMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; params &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; durationMs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AI call completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        durationMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        temperature&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        inputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;inputTokens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        outputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;outputTokens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; durationMs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AI call failed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        durationMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;6-caching&quot;&gt;6) Caching&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cachingMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; params &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cacheKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cacheKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;7-retry-logic&quot;&gt;7) Retry logic&lt;/h3&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; retryMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxRetries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Error &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; maxRetries&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; attempt&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        lastError &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; error &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempt &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; maxRetries&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; lastError&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attempt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;error-handling&quot;&gt;Error handling&lt;/h2&gt;
&lt;p&gt;Start with a safe fallback, and optionally branch on SDK error types (e.g., &lt;code&gt;NoSuchToolError&lt;/code&gt;) to produce targeted responses:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NoSuchToolError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LanguageModelMiddleware&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; robustMiddleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LanguageModelMiddleware &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;wrapGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NoSuchToolError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ToolWarning&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tool&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Requested tool is not available.&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

          finishReason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

          usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

          warnings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tool&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

              message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Missing tool in execution.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ToolWarning&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Sorry, something went wrong.&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        finishReason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; inputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; totalTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        warnings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;
flowchart TD



  A[doGenerate] --&amp;gt; B{throws}

  B --&amp;gt;|No| Z[Success]

  B --&amp;gt;|Yes| C{NoSuchToolError}

  C --&amp;gt;|Yes| D[Tool fallback]

  C --&amp;gt;|No| E[Generic fallback]

&lt;/pre&gt;
&lt;h2 id=&quot;composition-that-scales&quot;&gt;Composition that scales&lt;/h2&gt;
&lt;p&gt;Compose multiple middlewares to form a clear pipeline.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; wrapLanguageModel &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; modelWithStack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapLanguageModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; yourModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  middleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    safetyMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    cachingMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    inputEnhancerMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    outputProcessorMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    monitoringMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;performance-considerations&quot;&gt;Performance considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Keep heavy computation out of hot paths; precompute or cache&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid excessive serialization in &lt;code&gt;transformParams&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stream: transform deltas incrementally, don’t buffer entire outputs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log only what you need; prefer structured logs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vi &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;safetyMiddleware&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;blocks harmful content&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockModel&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; doGenerate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wrapped &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapLanguageModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; mockModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      middleware&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; safetyMiddleware&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; params&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;how to hack wifi?&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; wrapped&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doGenerate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;cannot process&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;doGenerate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Middleware standardizes safety, caching, transformations, and observability&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Order matters: safety → cache → transform → monitor&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Handle streaming by part type for fine-grained control&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Prefer explicit error branches for known SDK errors&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep it lightweight and testable&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Language Model Middleware (docs): &lt;a href=&quot;https://ai-sdk.dev/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ai-sdk.dev/docs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Middleware guide and examples: &lt;a href=&quot;https://sdk.vercel.ai/docs/ai-sdk-core/middleware&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;sdk.vercel.ai/docs/ai-sdk-core/middleware&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cookbook (caching, streaming, tools): &lt;a href=&quot;https://sdk.vercel.ai/examples&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;sdk.vercel.ai/examples&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Building Reliable AI Agents Series: Factor 2 – Own Your Prompts</title><link>https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-02-own-your-prompts/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-02-own-your-prompts/</guid><pubDate>Mon, 28 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;This is the second post in a series of posts about &lt;a href=&quot;https://arrangeactassert.com/posts/building-reliable-ai-agents-12-factor-methodology/&quot;&gt;building reliable AI agents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When building AI agents, where do your prompts live? If they’re hidden inside frameworks or scattered across configuration files, you’re missing a fundamental principle of maintainable AI systems: treating prompts as first-class code citizens.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;factor-2-own-your-prompts&quot;&gt;Factor 2: Own Your Prompts&lt;/h2&gt;
&lt;p&gt;When building AI agents, where do your prompts live? If they’re hidden inside frameworks or scattered across configuration files, you’re missing a fundamental principle of maintainable AI systems: treating prompts as first-class code citizens.&lt;/p&gt;
&lt;h2 id=&quot;the-hidden-prompt-problem&quot;&gt;The Hidden Prompt Problem&lt;/h2&gt;
&lt;p&gt;Most AI frameworks abstract away prompts, promising simplicity. But this convenience comes at a cost. When your agent misbehaves, how do you debug it? When you need to improve responses, where do you look? Without visibility into prompts, you’re essentially flying blind.&lt;/p&gt;
&lt;p&gt;Factor 2 of the 12-Factor Agent methodology solves this by establishing a simple principle: prompts should be explicit, version-controlled code artefacts. No hidden abstractions, no mysterious instructions - just clear, manageable code.&lt;/p&gt;
&lt;h2 id=&quot;why-explicit-prompts-matter&quot;&gt;Why Explicit Prompts Matter&lt;/h2&gt;
&lt;p&gt;Consider this scenario: your customer service agent suddenly starts giving incorrect information. With hidden prompts, you’re left guessing. With explicit prompts, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the exact instructions your AI received&lt;/li&gt;
&lt;li&gt;Review recent prompt changes in version control&lt;/li&gt;
&lt;li&gt;Roll back to a previous working version&lt;/li&gt;
&lt;li&gt;Test different prompt variations systematically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The formula is simple: Same Question + Different Prompts = Different Behaviour (Predictably).&lt;/p&gt;
&lt;h2 id=&quot;implementing-factor-2&quot;&gt;Implementing Factor 2&lt;/h2&gt;
&lt;p&gt;Here’s what explicit prompt management looks like in practice:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PROMPTS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  basicV1&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a helpful assistant.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  basicV2&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a helpful and friendly assistant.
Always be polite, clear, and provide helpful explanations.
When asked about calculations, use the available math tools.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  calculator&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a mathematical assistant with access to calculator tools.
When asked to perform calculations:
1. Use the appropriate math tool
2. Show the calculation step by step
3. Explain the result clearly&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how each prompt version is clearly defined, labelled, and ready for version control. No magic, no hidden configuration - just code.&lt;/p&gt;
&lt;h2 id=&quot;the-benefits-in-production&quot;&gt;The Benefits in Production&lt;/h2&gt;
&lt;p&gt;When you own your prompts, several things become possible:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Systematic A/B Testing&lt;/strong&gt;: Compare prompt performance with real metrics. Which version leads to better customer satisfaction? Which reduces support tickets?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Team Collaboration&lt;/strong&gt;: Prompts become reviewable artefacts. Team members can suggest improvements through standard pull requests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compliance and Auditing&lt;/strong&gt;: Track exactly what instructions your AI received at any point in time. Essential for regulated industries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debugging&lt;/strong&gt;: When issues arise, you can immediately see the exact prompt that caused the problem.&lt;/p&gt;
&lt;h2 id=&quot;moving-beyond-guesswork&quot;&gt;Moving Beyond Guesswork&lt;/h2&gt;
&lt;p&gt;Traditional prompt engineering often feels like alchemy - mysterious incantations that sometimes work. Factor 2 transforms it into engineering - systematic, testable, and reproducible.&lt;/p&gt;
&lt;p&gt;By treating prompts as code, you gain the same benefits that version control brought to software development: collaboration, history, rollbacks, and systematic improvement.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Implementing Factor 2 doesn’t require complex frameworks. Start simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extract all prompts from configuration into explicit constants&lt;/li&gt;
&lt;li&gt;Version these prompts alongside your code&lt;/li&gt;
&lt;li&gt;Create a simple system for switching between prompt versions&lt;/li&gt;
&lt;li&gt;Track which prompts are used in production&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key is visibility. When every team member can see, understand, and improve your prompts, your AI systems become truly maintainable.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hidden prompts are technical debt. They make debugging harder, improvement slower, and collaboration impossible. By owning your prompts - making them explicit, versioned, and testable - you transform AI development from guesswork into engineering.&lt;/p&gt;
&lt;p&gt;The next time you’re building an AI agent, ask yourself: can I see exactly what instructions it’s receiving? If not, it’s time to take ownership of your prompts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/mastra-12-factor-examples/blob/main/src/factor-02-own-your-prompts/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Want to see Factor 2 in action? Check out the complete working example&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Hannah Hampton. A proper comeback story.</title><link>https://arrangeactassert.com/posts/hannah-hampton/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/hannah-hampton/</guid><pubDate>Sun, 27 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;figure&gt;
    &lt;img src=&quot;https://arrangeactassert.com//upload.wikimedia.org/wikipedia/commons/d/d4/20250510-Hannah_Hampton.jpg&quot; alt=&quot;Hannah Hampton&quot;&gt;
    &lt;figcaption class=&quot;text-xs text-gray-500 text-left&quot;&gt;
        Photo by &lt;a href=&quot;https://commons.wikimedia.org/wiki/User:KTC&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Katie Chan (KTC)&lt;/a&gt;, licensed under &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CC BY-SA 4.0&lt;/a&gt;.
    &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;⚽️ Dropped by then and current manager Sarina Wiegman from the England squad in 2022 amid concerns over her attitude and conduct, she remained outside the national setup for almost two years.&lt;/p&gt;
&lt;p&gt;⚽️ Born with strabismus and challenged by depth‑perception issues, she was told by doctors she should not play football.&lt;/p&gt;
&lt;p&gt;⚽️ Rebuilt her career at Chelsea, playing an integral role in winning the treble last season.&lt;/p&gt;
&lt;p&gt;⚽️ Chosen as England’s first-choice goalkeeper ahead of the great and brilliant Mary Earps.&lt;/p&gt;
&lt;p&gt;⚽️ Delivered under pressure in the quarter‑final versus Sweden, even with a bloody nose. Named Player of the Match.&lt;/p&gt;
&lt;p&gt;Tonight, she starts in a European final for England.&lt;/p&gt;
&lt;p&gt;Even when things don’t go your way, never give up.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
</content:encoded></item><item><title>Building Reliable AI Agents Series: A 12-Factor Methodology</title><link>https://arrangeactassert.com/posts/building-reliable-ai-agents-12-factor-methodology/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/building-reliable-ai-agents-12-factor-methodology/</guid><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;After building production AI systems over the past few years, thanks to &lt;a href=&quot;https://github.com/humanlayer/12-factor-agent&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;HumanLayer&lt;/a&gt;, I’ve learned that most agent failures aren’t about the LLM, they’re about architecture.&lt;/p&gt;
&lt;p&gt;That’s why I’m creating a series of posts sharing the 12-Factor Agents methodology using &lt;a href=&quot;https://github.com/humanlayer/12-factor-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Mastra&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In each part, I’ll break down one principle that transforms fragile prototypes into robust, production-ready AI agents.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-01-natural-language-to-tool-calls/&quot;&gt;Factor 1: Natural Language → Tool Calls&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-02-own-your-prompts/&quot;&gt;Factor 2: Own Your Prompts&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Building Reliable AI Agents Series: Factor 1 – Natural Language → Tool Calls</title><link>https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-01-natural-language-to-tool-calls/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/building-reliable-ai-agents-factor-01-natural-language-to-tool-calls/</guid><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;This is the first post in a series of posts about &lt;a href=&quot;https://arrangeactassert.com/posts/building-reliable-ai-agents-12-factor-methodology/&quot;&gt;building reliable AI agents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unlock reliable, testable AI agents by treating your LLM as a parser, not an executor. Learn how converting natural language into structured tool calls leads to predictable, scalable systems.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;factor-1-natural-language--tool-calls&quot;&gt;Factor 1: Natural Language → Tool Calls&lt;/h2&gt;
&lt;p&gt;Modern AI agents are most robust when their LLMs parse instructions, rather than execute them directly. This approach transforms the LLM into a sophisticated parser that converts natural language into structured function calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Natural Language → LLM Processing → Structured Tool Call → Deterministic Execution&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;why-this-matters&quot;&gt;Why this matters&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Predictable results&lt;/strong&gt; – Same input, same output every time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debuggable workflows&lt;/strong&gt; – You can trace exactly what happened&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testable components&lt;/strong&gt; – Tools can be unit-tested independently&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalable architecture&lt;/strong&gt; – Add new capabilities without touching LLM logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/mastra-12-factor-examples/blob/main/src/factor-01-natural-language-to-tool-calls/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;See Factor 1 in action here&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Demystifying MCP: Coaching Colleagues Through the New AI Protocol</title><link>https://arrangeactassert.com/posts/mcp-workshop/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/mcp-workshop/</guid><pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Last month, I had the fantastic opportunity to run a hands-on Model Context Protocol (MCP) workshop. It was a chance to mentor and coach colleagues, from engineers and testers to product owners, as we explored what MCP is, how it works, and why it is generating so much momentum across AI and developer communities.&lt;/p&gt;
&lt;p&gt;My goal was not just to share knowledge. It was to guide the learning journey and build a shared, foundational understanding of this powerful emerging standard.&lt;/p&gt;
&lt;h2 id=&quot;workshop-highlights&quot;&gt;Workshop Highlights&lt;/h2&gt;
&lt;p&gt;We covered everything from core protocol basics and prompt crafting to real world patterns such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple MCP client and servers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompts&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication flows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session context handling&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composing multiple MCP servers&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;outcome&quot;&gt;Outcome&lt;/h2&gt;
&lt;p&gt;By the end of the session, everyone had a clear understanding of MCP, its potential, and how it could fundamentally change how we build AI toolchains. This clarity, made possible through practical examples and direct support, was a truly rewarding outcome.&lt;/p&gt;
&lt;h2 id=&quot;explore-the-workshop-repository&quot;&gt;Explore the Workshop Repository&lt;/h2&gt;
&lt;p&gt;You can explore the same TypeScript repository I used for the workshop here:
👉 &lt;a href=&quot;https://github.com/jagreehal/typescript-mcp-workshop&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/jagreehal/typescript-mcp-workshop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each example includes step-by-step guidance. So, whether you want to spin up your first MCP server or dive deep into tool composition and integration flows, this will show you how.&lt;/p&gt;
&lt;p&gt;MCP is evolving rapidly, and I will keep the repository up to date as best practices emerge. If you have feedback or ideas for what I should cover next, please let me know.&lt;/p&gt;
</content:encoded></item><item><title>Understanding Commands &amp; Events with Orchestration &amp; Choreography</title><link>https://arrangeactassert.com/posts/understanding-commands-events-orchestration-choreography/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/understanding-commands-events-orchestration-choreography/</guid><pubDate>Wed, 18 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Designing distributed systems has never been more challenging. As teams embrace microservices and event‑driven architectures, a persistent myth has arisen: &lt;strong&gt;commands equal orchestration&lt;/strong&gt;, and &lt;strong&gt;events equal choreography&lt;/strong&gt;. This tidy equivalence often becomes a mental shortcut but conceals the deeper truth of control‑flow patterns versus messaging semantics. As many practitioners have observed, collapsing these separate dimensions can restrict your system’s flexibility and resilience.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Person thinking about the difference between commands and events.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1536px) 1536px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_RmiH8.webp&quot; srcset=&quot;/_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_Z1aNKwj.webp 640w, /_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_ZJOvBy.webp 750w, /_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_1OVvLy.webp 828w, /_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_1xxEy3.webp 1080w, /_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_CmyoH.webp 1280w, /_astro/understanding-commands-events-orchestration-choreography.DDUUa9cQ_RmiH8.webp 1536w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this article, we’ll demystify these concepts and show how to apply them independently. You’ll discover how separating &lt;strong&gt;semantics&lt;/strong&gt; (commands vs. events) from &lt;strong&gt;control flow&lt;/strong&gt; (orchestration vs. choreography) grants you greater architectural freedom and clearer, more maintainable workflows.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Let’s examine three core scenarios, highlighting error handling, delivery guarantees and state‑management nuances.&lt;/p&gt;
&lt;h3 id=&quot;1-orchestration-with-events-centralised-resumable-workflows&quot;&gt;1. Orchestration with Events: Centralised, Resumable Workflows&lt;/h3&gt;
&lt;p&gt;An orchestrator maintains end‑to‑end visibility by subscribing to domain events, tracking each workflow’s state, and emitting further actions. Although illustrated with events, the same pattern applies to commands.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// orchestrator.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderPlaced&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentConfirmed&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// EventBus and StateStore interfaces for DI&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EventBus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StateStore&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OrderOrchestrator&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; eventBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; EventBus&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected event bus&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; state&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; StateStore &lt;span class=&quot;token comment&quot;&gt;// Injected state store&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OrderPlaced&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment_pending&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Order &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; placed. Starting payment.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ProcessPayment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onPaymentConfirmed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentConfirmed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fulfilled&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Payment confirmed for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. Fulfilling order.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;FulfilOrder&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: The orchestrator can centrally retry failed steps or invoke compensating actions. If a step fails, the workflow pauses and retries based on configured policies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Delivery Guarantees&lt;/strong&gt;: Events often default to at‑most‑once delivery on basic buses, though modern platforms (Kafka, Pulsar) provide at‑least‑once semantics with idempotent consumers to avoid data loss. The orchestrator persists all incoming events and uses idempotent handlers to ensure each workflow step runs exactly once or is safely retried.&lt;/p&gt;
&lt;h3 id=&quot;2-choreography-with-commands-decentralised-implicit-flows&quot;&gt;2. Choreography with Commands: Decentralised, Implicit Flows&lt;/h3&gt;
&lt;p&gt;In a choreographed system, each service reacts locally and issues the next command. There is no central coordinator—each participant knows only its own scope.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// inventory.service.ts&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// CommandBus interface for DI&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandBus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InventoryService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; commandBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CommandBus&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected command bus&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reserveStock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sku&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Inventory: Reserving &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sku&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; for order &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commandBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ScheduleShipment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sku &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// shipping.service.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShippingService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; commandBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CommandBus&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected command bus&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scheduleShipment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sku&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Shipping: Scheduling shipment for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sku&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... further logic ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Each service can route unprocessable messages to a dead‑letter queue for later inspection, preventing a single failure from halting the entire choreography.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Delivery Guarantees&lt;/strong&gt;: Commands generally require at‑least‑once delivery (e.g. via durable queues), so idempotent handlers are essential. Events in choreographies may default to at‑most‑once delivery, but real‑world event streaming often guarantees at‑least‑once with idempotent consumers.&lt;/p&gt;
&lt;h3 id=&quot;3-mixed-messaging-orthogonal-dimensions-in-practice&quot;&gt;3. Mixed Messaging: Orthogonal Dimensions in Practice&lt;/h3&gt;
&lt;p&gt;By decoupling semantics from control flow, you can mix commands and events as appropriate.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// payment-orchestrator.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentOrchestrator&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; commandBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CommandBus&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected command bus&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmd&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ProcessPayment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Processing payment for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;needsCharge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commandBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AttemptCharge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;needsCharge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... check if charge is needed ...&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// shipping-subscriber.ts&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// EventBus and CommandBus interfaces reused&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;subscribeEvent&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  eventType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... subscribe logic ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ShippingSubscriber&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; commandBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CommandBus&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected command bus&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; eventBus&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; EventBus &lt;span class=&quot;token comment&quot;&gt;// Injected event bus&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onOrderPlaced&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OrderPlaced&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Shipping (choreography): Received OrderPlaced for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commandBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;InitiatePackaging&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventBus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ShipmentScheduled&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orderId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;statemanagement-nuance&quot;&gt;State‑Management Nuance&lt;/h3&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Example: rebuilding state via event sourcing in a choreographed service&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// EventLog interface for DI&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EventLog&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;getEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InventoryService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; reserved&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; eventLog&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; EventLog&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Injected event log&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rebuildState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; events &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;StockReserved&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; orderId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sku &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; events&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reserved&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;orderId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sku&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;State rebuilt from event log:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Choreographed services can manage their local state via event sourcing—replaying an event log to rebuild state on restart, enabling rich audit trails without central orchestration.&lt;/p&gt;
&lt;h3 id=&quot;visualising-the-patterns&quot;&gt;Visualising the Patterns&lt;/h3&gt;
&lt;p&gt;Below is a diagram illustrating the difference between orchestration (centralised control) and choreography (decentralised flow). Orchestration is like a conductor leading an orchestra—one central figure directs each part. Choreography is more like a jazz band, where each musician listens and responds, creating harmony without a single leader.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;%% Figure 1: Orchestration and Choreography Control Flows
%% Alt text: Diagram showing orchestration as a central orchestrator directing workflow steps, and choreography as services passing commands and events in a decentralised manner.
flowchart LR
  subgraph Orchestration
    A[OrderPlaced Event] --&amp;gt; B[Orchestrator Determines Next Step]
    B --&amp;gt; C[Emit ProcessPayment]
    C --&amp;gt; D[PaymentConfirmed Event]
    D --&amp;gt; E[Emit FulfilOrder]
  end

  subgraph Choreography
    F[Inventory Service] -- &quot;Command: ReserveStock&quot; --&amp;gt; G[Billing Service]
    G -- &quot;Event: StockReserved&quot; --&amp;gt; H[Shipping Service]
    H -- &quot;Command: ScheduleShipment&quot; --&amp;gt; I[Notification Service]
    I -- &quot;Event: ShipmentScheduled&quot; --&amp;gt; J[Analytics Service]
  end
&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Separating messaging semantics (commands vs. events) from control-flow patterns (orchestration vs. choreography) gives you the flexibility to design robust, adaptable distributed systems. Choose the right tool for each job, and don’t conflate the two dimensions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By disentangling messaging semantics from control‑flow patterns, you gain architectural agility, robust orchestrators, and flexible choreographies. This separation allows you to adapt your system as requirements evolve, without being locked into a single pattern.&lt;/p&gt;
</content:encoded></item><item><title>From Gatekeeper to Enabler: Rethinking Engineering in the Age of the Citizen Developer</title><link>https://arrangeactassert.com/posts/engineering-gatekeeper-to-enabler-citizen-developer/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/engineering-gatekeeper-to-enabler-citizen-developer/</guid><pubDate>Mon, 09 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Last month, our company hackathon became a vivid illustration of a broader shift in how software gets built. Across teams, from sales to support, product to engineering, domain experts huddled around laptops, experimenting with AI powered platforms such as V0, Lovable and Bolt. Within hours, they’d fashioned interactive prototypes complete with navigation flows and validation rules, all without writing a single line of traditional code.&lt;/p&gt;
&lt;p&gt;Although these early demos relied on mock data, the fact that non-engineers could conjure usable software unaided was striking.&lt;/p&gt;
&lt;p&gt;As a full-stack engineer accustomed to crafting CRUD apps from the ground up, I found myself asking a new question: &lt;strong&gt;How might we empower these citizen developers to build more often, more securely, and with live data?&lt;/strong&gt; Their deep problem domain knowledge meant they moved swiftly, iterated boldly and learned faster than any handoff-laden process could permit.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;../images/engineering-gatekeeper-to-enabler-citizen-developer.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img alt=&quot;An isometric illustration of a futuristic highway under construction, where software engineers in hard hats are laying down glowing code-shaped road segments.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/engineering-gatekeeper-to-enabler-citizen-developer.BZTDIlmK_Z1sXajs.webp&quot; srcset=&quot;/_astro/engineering-gatekeeper-to-enabler-citizen-developer.BZTDIlmK_ZjcYcc.webp 640w, /_astro/engineering-gatekeeper-to-enabler-citizen-developer.BZTDIlmK_qXyNt.webp 750w, /_astro/engineering-gatekeeper-to-enabler-citizen-developer.BZTDIlmK_BJtiU.webp 828w, /_astro/engineering-gatekeeper-to-enabler-citizen-developer.BZTDIlmK_Z1sXajs.webp 1024w&quot;&gt;&lt;/a&gt;
&lt;em&gt;An isometric illustration of a futuristic highway under construction, where software engineers in hard hats are laying down glowing code-shaped road segments.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Over my two decades in software, I’ve discovered my highest leverage isn’t in writing every screen or endpoint myself, but in architecting robust APIs, infrastructure and tooling so that others can deliver user value. In this two-part series, I’ll share how engineers can transition from gatekeeping code to enabling creation at scale. In this first instalment, we’ll explore the mindset shifts and guiding principles. Part 2 will dive into concrete patterns and architectural strategies for secure, sustainable enablement.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-democratisation-of-software-development&quot;&gt;The Democratisation of Software Development&lt;/h2&gt;
&lt;p&gt;Traditionally, software lived in the hands of specialists schooled in algorithms, architecture and abstraction. That expertise guaranteed rigour, but often created bottlenecks. Those closest to the problem had to wait for engineers. Today, low-code and no-code platforms are rewriting that story. By abstracting away boilerplate—through drag-and-drop interfaces, natural-language prompts or schema-driven generators—these tools empower domain experts to design, test and ship apps without deep coding knowledge. The advent of the &lt;a href=&quot;https://www.gartner.com/en/information-technology/glossary/citizen-developer&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;citizen developer&lt;/a&gt; blurs the boundary between “user” and “builder.” As engineers, our role must evolve: we are no longer the sole authors of software, but the architects of the roads on which others will drive.&lt;/p&gt;
&lt;h2 id=&quot;the-rise-of-the-citizen-developer&quot;&gt;The Rise of the Citizen Developer&lt;/h2&gt;
&lt;p&gt;Citizen developers are not seeking to dismantle engineering teams—they simply need to solve context-specific problems fast. Whether it’s an operations lead automating routine workflows, an analyst assembling a live dashboard or a product manager sketching an onboarding flow, these experts bring intimate understanding of user needs. Platforms like &lt;a href=&quot;https://v0.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;V0.dev&lt;/a&gt;, &lt;a href=&quot;https://lovable.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Lovable.dev&lt;/a&gt; and &lt;a href=&quot;https://www.bolt.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bolt&lt;/a&gt; combine intuitive interfaces with smart defaults and rich integrations. Some even scaffold complete applications from database schemas or plain-English descriptions. What once took weeks now happens in hours. Sure, these MVPs may carry imperfections, but their true value lies in rapid validation and immediate feedback. This is not a distant horizon; it’s our present.&lt;/p&gt;
&lt;h2 id=&quot;engineers-as-enablers&quot;&gt;Engineers as Enablers&lt;/h2&gt;
&lt;p&gt;To capitalise on this momentum, engineers must adopt a new mindset: from building every feature to creating the ecosystem where features emerge. That means crafting reusable components and well-documented APIs, defining safe defaults and guardrails, and fostering experimentation within controlled boundaries. In practice this looks like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stewardship over ownership:&lt;/strong&gt; Rather than micromanaging every app, we curate the environments, libraries and conventions that reflect our standards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Constraints over approvals:&lt;/strong&gt; Guardrails and templates scale more gracefully than manual reviews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enablement over velocity:&lt;/strong&gt; Our success is measured by how quickly non-engineers can deliver without compromising security or stability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A well-paved road isn’t an easy excuse; it’s the fastest, safest path forward.&lt;/p&gt;
&lt;h2 id=&quot;schema-driven-ui-generation&quot;&gt;Schema-Driven UI Generation&lt;/h2&gt;
&lt;p&gt;One powerful pattern is schema-driven UI. Instead of hand-coding forms and validations, citizen developers define a schema—perhaps in &lt;a href=&quot;https://json-schema.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;JSON Schema&lt;/a&gt; or via &lt;a href=&quot;https://graphql.org/learn/introspection/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GraphQL introspection&lt;/a&gt;—and the platform auto-generates the interface. Rename a field or tweak a validation rule in the schema, and the UI updates instantly. Benefits include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speed:&lt;/strong&gt; Interfaces materialise in moments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; Uniform look, feel and behaviour across apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability:&lt;/strong&gt; Built-in validation reduces runtime errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintainability:&lt;/strong&gt; Schema changes propagate automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By keeping business logic declarative, engineers can focus on data models and APIs, while platforms handle presentation. Both developer and domain expert stay in their zone of expertise.&lt;/p&gt;
&lt;h2 id=&quot;security-and-governance&quot;&gt;Security and Governance&lt;/h2&gt;
&lt;p&gt;Enabling a multitude of builders needn’t mean relinquishing control. Thoughtfully designed platforms bake governance into every layer, making policies transparent, auditable and automated. Core patterns include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Centralised identity providers for authentication&lt;/li&gt;
&lt;li&gt;Curated and versioned APIs for data access&lt;/li&gt;
&lt;li&gt;Rate-limiting and comprehensive logging for observability&lt;/li&gt;
&lt;li&gt;Usage analytics to understand how templates and tools are adopted&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many organisations encapsulate these capabilities in an &lt;a href=&quot;https://internaldeveloperplatform.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Internal Developer Platform (IDP)&lt;/a&gt;, which serves as the single source of truth for permissions, policies and pipelines. In this model, security isn’t an afterthought—it’s inherent to the platform.&lt;/p&gt;
&lt;h2 id=&quot;trade-offs-and-tensions&quot;&gt;Trade-offs and Tensions&lt;/h2&gt;
&lt;p&gt;Citizen development offers clear upsides—accelerated prototyping, reduced IT backlogs and closer alignment between solutions and needs—but it also introduces challenges: potential sprawl of shadow IT, uneven code quality and emerging compliance gaps. These concerns aren’t reasons to halt progress, but signals to evolve our platforms and processes: tighten templates, codify best practices and foster ongoing collaboration between engineers and domain experts.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Engineers as enablers:&lt;/strong&gt; Our highest value is in building the platforms, APIs and guardrails that empower others to create.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Citizen developers are here:&lt;/strong&gt; With the right tools, domain experts can deliver real solutions—fast.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Governance is essential:&lt;/strong&gt; Security, observability and policy must be built into the platform, not bolted on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collaboration is the future:&lt;/strong&gt; The best outcomes arise when engineers and domain experts work together, not in silos.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;visualising-the-new-collaboration-model&quot;&gt;Visualising the New Collaboration Model&lt;/h2&gt;
&lt;p&gt;This diagram shows how engineers, citizen developers, and the platform interact. Engineers create the platform and guardrails, enabling citizen developers to build solutions safely. Governance and feedback ensure continuous improvement.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
  A[&quot;Engineers&quot;] --&amp;gt;|&quot;Build&quot;| B[&quot;Platform &amp;amp; Guardrails&quot;]
  B --&amp;gt;|&quot;Enable&quot;| C[&quot;Citizen Developers&quot;]
  C --&amp;gt;|&quot;Build&quot;| D[&quot;Apps &amp;amp; Solutions&quot;]
  D --&amp;gt;|&quot;Feedback&quot;| B
  B --&amp;gt;|&quot;Governance&quot;| E[&quot;Security &amp;amp; Compliance&quot;]
&lt;/pre&gt;
&lt;h2 id=&quot;conclusion-a-new-kind-of-collaboration&quot;&gt;Conclusion: A New Kind of Collaboration&lt;/h2&gt;
&lt;p&gt;The rise of the citizen developer marks a structural transformation in how organisations solve problems. For engineers, this shift isn’t a diminution of our role but a reorientation from building every screen to designing the highways of innovation. By embracing stewardship, defining clear guardrails and architecting platforms that blend security with flexibility, we empower entire teams to deliver value safely and swiftly. The most effective engineering groups will be those that not only ship code, but also cultivate the ecosystem in which others can ship it too.&lt;/p&gt;
&lt;p&gt;In Part 2, we’ll explore concrete architectural patterns and API-exposure strategies that make secure citizen development not just possible, but effortless.&lt;/p&gt;
</content:encoded></item><item><title>Dual-Layer Locking: Redis for Speed, PostgreSQL for Reliability</title><link>https://arrangeactassert.com/posts/dual-layer-locking/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/dual-layer-locking/</guid><pubDate>Mon, 02 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Two users withdraw money from the same account at exactly the same moment. Your system processes both requests, your database balance goes negative, and you wake up to an incident report. Sound familiar?&lt;/p&gt;
&lt;p&gt;What if you could combine &lt;a href=&quot;https://redis.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Redis&lt;/a&gt;’s millisecond response times with &lt;a href=&quot;https://www.postgresql.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PostgreSQL&lt;/a&gt;’s bulletproof consistency? This dual-layer locking pattern does exactly that, giving you both speed and safety.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Redis and PostgreSQL logos side by side.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/dual-layer-locking.C2e6q2B7_Z1pDQxx.webp&quot; srcset=&quot;/_astro/dual-layer-locking.C2e6q2B7_ZENGlH.webp 640w, /_astro/dual-layer-locking.C2e6q2B7_Z12w73u.webp 750w, /_astro/dual-layer-locking.C2e6q2B7_Z1gk2gE.webp 828w, /_astro/dual-layer-locking.C2e6q2B7_Z1pDQxx.webp 1024w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this post, we’ll explore a pattern that combines Redis’s speed with PostgreSQL’s reliability to prevent race conditions at scale.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-problem-race-conditions-at-scale&quot;&gt;The Problem: Race Conditions at Scale&lt;/h2&gt;
&lt;p&gt;Consider this scenario: 100 concurrent requests to update the same user account. Without proper locking:&lt;/p&gt;
&lt;figure&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;---
alt: &quot;Flowchart showing three requests reading and writing the same balance, resulting in an incorrect final value.&quot;
---
graph TD
    A[Request 1: Update Balance] --&amp;gt;|Reads £100| DB[(Database)]
    B[Request 2: Update Balance] --&amp;gt;|Reads £100| DB
    C[Request 3: Update Balance] --&amp;gt;|Reads £100| DB
    A --&amp;gt;|Writes £80| DB
    B --&amp;gt;|Writes £50| DB
    C --&amp;gt;|Writes £120| DB
    D[Final Balance: £120] --&amp;gt;|Should be £50| DB
    style D fill:#f96,stroke:#333,stroke-width:2px,color:#fff,font-weight:bold
&lt;/pre&gt;
&lt;figcaption&gt;Figure 1: Race condition scenario with concurrent balance updates.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The last write wins, and you’ve lost £70. In production, the ‘thundering herd’ problem where many processes try to acquire a lock at once can make things even worse by overwhelming your system.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-dual-layer-defense&quot;&gt;The Solution: Dual-Layer Defense&lt;/h2&gt;
&lt;p&gt;Think of it like securing a bank vault, you need both the outer perimeter (Redis) and the inner vault door (PostgreSQL):&lt;/p&gt;
&lt;figure&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;---
alt: &quot;Flowchart showing a request passing through Redis lock, PostgreSQL transaction, and safe update steps.&quot;
---
graph LR
    A[Incoming Request] --&amp;gt;|Step 1| B[Redis Lock&amp;lt;br/&amp;gt;Fast Distribution]
    B --&amp;gt;|Step 2| C[PostgreSQL Transaction&amp;lt;br/&amp;gt;Data Integrity]
    C --&amp;gt;|Step 3| D[Safe Update]

    classDef redis fill:#ffe6e6,stroke:#cc0000,stroke-width:2px
    classDef postgres fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    classDef success fill:#e6ffe6,stroke:#00cc00,stroke-width:2px

    class B redis
    class C postgres
    class D success
&lt;/pre&gt;
&lt;figcaption&gt;Figure 2: Dual-layer defence—Redis for fast distribution, PostgreSQL for data integrity.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;layer-1-redis-distributed-lock&quot;&gt;Layer 1: Redis Distributed Lock&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Coordinates across services in &amp;lt;1ms (&lt;a href=&quot;https://redis.io/docs/reference/patterns/distributed-locks/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;learn more&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Prevents stampeding herd problems (many processes trying to acquire the same lock)&lt;/li&gt;
&lt;li&gt;Auto-expires to prevent deadlocks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;layer-2-postgresql-row-lock&quot;&gt;Layer 2: PostgreSQL Row Lock&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Guarantees ACID compliance&lt;/li&gt;
&lt;li&gt;Prevents partial updates&lt;/li&gt;
&lt;li&gt;Handles complex transactions safely&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-is-optimistic-locking&quot;&gt;What is Optimistic Locking?&lt;/h3&gt;
&lt;p&gt;Optimistic locking is a technique that allows multiple transactions to proceed without locking resources up front. Instead, each transaction checks whether the data has changed before committing. If another transaction has modified the data, the update fails, and the process can retry. This helps catch rare edge cases where data changes between read and write.&lt;/p&gt;
&lt;h3 id=&quot;production-ready-implementation&quot;&gt;Production-Ready Implementation&lt;/h3&gt;
&lt;figure&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;---
alt: &quot;Flowchart showing the dual-layer locking process, including Redis lock acquisition, DB transaction, version check, and success/error paths.&quot;
---
flowchart TD
    A[Request] --&amp;gt; B{Redis Lock?}
    B --&amp;gt;|Acquired| C[DB Transaction]
    B --&amp;gt;|Failed| D[Exponential Backoff]
    D --&amp;gt; E{Retry?}
    E --&amp;gt;|Yes| B
    E --&amp;gt;|No| F[Return Error]
    C --&amp;gt; G[SELECT FOR UPDATE]
    G --&amp;gt; H[Version Check]
    H --&amp;gt; I{Valid?}
    I --&amp;gt;|Yes| J[Update &amp;amp; Commit]
    I --&amp;gt;|No| K[Rollback &amp;amp; Retry]
    J --&amp;gt; L[Release Lock]
    K --&amp;gt; D
    L --&amp;gt; M[Success]

    classDef redis fill:#ffe6e6,stroke:#cc0000,stroke-width:2px
    classDef postgres fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
    classDef success fill:#e6ffe6,stroke:#00cc00,stroke-width:2px
    classDef error fill:#ffe6cc,stroke:#ff6600,stroke-width:2px

    class B,D,L redis
    class C,G,H,I,J,K postgres
    class M success
    class E,F error
&lt;/pre&gt;
&lt;figcaption&gt;Figure 4: Dual-layer locking process from request to success or error.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Which can be implemented in code like this:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// TransferRequest defines the structure for a money transfer operation&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransferRequest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  fromAccountId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  toAccountId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AccountService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;transferMoney&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fromAccountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toAccountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TransferRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// CRITICAL: Always acquire locks in consistent order to prevent deadlocks&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;firstId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; secondId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;fromAccountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toAccountId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lockKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;transfer:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;firstId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;secondId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Acquire a distributed lock in Redis&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;acquireRedisLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lockKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;BEGIN&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Lock rows in same order as Redis locks&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; accounts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        SELECT id, balance, version 
        FROM accounts 
        WHERE id IN ($1, $2) 
        ORDER BY id
        FOR UPDATE
      &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;firstId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; secondId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fromAccount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; accounts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; fromAccountId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; toAccount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; accounts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; toAccountId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fromAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;balance &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InsufficientFundsError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Balance: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;fromAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;balance&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, Required: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;amount&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Atomic updates with optimistic locking&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          UPDATE accounts 
          SET balance = balance - $1, version = version + 1, updated_at = NOW()
          WHERE id = $2 AND version = $3
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fromAccountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fromAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          UPDATE accounts 
          SET balance = balance + $1, version = version + 1, updated_at = NOW()
          WHERE id = $2 AND version = $3  
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toAccountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;version&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Verify both updates succeeded (optimistic lock check)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rowCount &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcurrentModificationError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;Account was modified by another transaction&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;COMMIT&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ROLLBACK&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Always release the Redis lock&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;releaseRedisLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Acquire a distributed lock in Redis with retries and exponential backoff&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;acquireRedisLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    timeoutMs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30000&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Lock&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateUUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxRetries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; maxRetries&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; acquired &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;redis&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;PX&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeoutMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NX&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acquired&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeoutMs &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Exponential backoff: 50ms, 100ms, 200ms&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attempt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      attempt&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LockAcquisitionError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Failed to acquire lock after &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;maxRetries&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; attempts&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Release the Redis lock using an atomic Lua script&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;releaseRedisLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; token &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Lua script ensures atomic check-and-delete&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      if redis.call(&quot;GET&quot;, KEYS[1]) == ARGV[1] then
        return redis.call(&quot;DEL&quot;, KEYS[1])
      else
        return 0
      end
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;redis&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;critical-design-patterns&quot;&gt;Critical Design Patterns&lt;/h2&gt;
&lt;h3 id=&quot;1-lock-ordering-prevents-deadlocks&quot;&gt;1. Lock Ordering Prevents Deadlocks&lt;/h3&gt;
&lt;figure&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;---
alt: &quot;Sequence diagram showing two transfers acquiring locks in the same order to prevent deadlocks.&quot;
---
sequenceDiagram
    participant T1 as Transfer A→B
    participant T2 as Transfer B→A
    participant Redis as Redis
    participant DB as PostgreSQL

    Note over T1,T2: Both sort account IDs: A, B
    T1-&amp;gt;&amp;gt;Redis: Lock &quot;transfer:A:B&quot;
    T2-&amp;gt;&amp;gt;Redis: Lock &quot;transfer:A:B&quot;
    Note over T2: Waits for T1
    T1-&amp;gt;&amp;gt;DB: Lock accounts A, B (sorted order)
    T1-&amp;gt;&amp;gt;DB: Complete transfer
    T1-&amp;gt;&amp;gt;Redis: Release lock
    T2-&amp;gt;&amp;gt;Redis: Acquire lock &quot;transfer:A:B&quot;
    T2-&amp;gt;&amp;gt;DB: Lock accounts A, B
    T2-&amp;gt;&amp;gt;DB: Complete transfer
&lt;/pre&gt;
&lt;figcaption&gt;Figure 3: Consistent lock ordering prevents deadlocks.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Without consistent ordering, Transfer A→B and Transfer B→A can deadlock each other.&lt;/p&gt;
&lt;h3 id=&quot;2-exponential-backoff-handles-contention&quot;&gt;2. Exponential Backoff Handles Contention&lt;/h3&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Bad: Hammers Redis with retries (thundering herd problem)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tryLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Retry immediately - creates thundering herd&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Good: Exponential backoff with jitter&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  baseDelay &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attempt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  maxDelay
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-optimistic-locking-catches-edge-cases&quot;&gt;3. Optimistic Locking Catches Edge Cases&lt;/h3&gt;
&lt;p&gt;Even with locks in place, version checks help catch rare edge cases where another transaction modifies the row between reads and writes:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This will fail if another transaction modified the row&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;UPDATE&lt;/span&gt; accounts
&lt;span class=&quot;token constant&quot;&gt;SET&lt;/span&gt; balance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; balance &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; $1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; version &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; version &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;WHERE&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $2 &lt;span class=&quot;token constant&quot;&gt;AND&lt;/span&gt; version &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $3  &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; This condition fails &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; row was modified&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;error-handling-that-actually-works&quot;&gt;Error Handling That Actually Works&lt;/h2&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TransferService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;transferWithRetry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TransferRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;TransferResult&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxRetries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; maxRetries&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; attempt&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transferMoney&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        lastError &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Don&apos;t retry business logic errors&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InsufficientFundsError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
          error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InvalidAccountError&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Retry on infrastructure failures&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LockAcquisitionError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
          error &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcurrentModificationError&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempt &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; maxRetries&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;calculateBackoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delay&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Unknown error - don&apos;t retry&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MaxRetriesExceededError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Failed after &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;maxRetries&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; attempts&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      lastError
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateBackoff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Exponential backoff with jitter: 100ms, 200ms, 400ms&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; base &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attempt &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jitter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; jitter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Cap at 5 seconds&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;when-not-to-use-this-pattern&quot;&gt;When NOT to Use This Pattern&lt;/h2&gt;
&lt;p&gt;This pattern adds complexity. Don’t use it when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Low contention scenarios&lt;/strong&gt;: If conflicts happen &amp;lt;1% of the time, simpler optimistic locking may suffice&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single-service operations&lt;/strong&gt;: If you’re not distributed, PostgreSQL locks alone are often enough&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-heavy workloads&lt;/strong&gt;: This pattern optimises writes; reads don’t need dual locking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch operations&lt;/strong&gt;: For bulk updates, consider queue-based processing instead&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Alternative approaches:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Event sourcing&lt;/strong&gt;: For audit-heavy domains&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CQRS&lt;/strong&gt;: When read/write patterns differ significantly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database partitioning&lt;/strong&gt;: When you can shard by tenant/region&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;monitoring-and-observability&quot;&gt;Monitoring and Observability&lt;/h2&gt;
&lt;p&gt;Track these metrics to catch problems early:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Key metrics to monitor&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LockingMetrics&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  lockAcquisitionTime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Histogram&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Should be &amp;lt;10ms p99&lt;/span&gt;
  lockHoldTime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Histogram&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Should be &amp;lt;100ms p99&lt;/span&gt;
  lockContentionRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Failures due to contention&lt;/span&gt;
  deadlockCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Should be zero&lt;/span&gt;
  optimisticLockFailures&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Version conflicts&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Alert on these conditions&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lockAcquisitionTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;p99 &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;High Redis lock contention&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deadlockCount &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Deadlock detected - check lock ordering&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Dual-layer locking isn’t just about preventing race conditions—it’s about building systems that stay fast under load while maintaining strict consistency guarantees.&lt;/p&gt;
&lt;p&gt;This pattern powers financial transactions, inventory management, and any system where correctness and performance both matter. The complexity pays for itself when you’re processing millions of pounds and can’t afford to be wrong.&lt;/p&gt;
</content:encoded></item><item><title>Impact Through Empowerment: Contributing Without Direct Participation</title><link>https://arrangeactassert.com/posts/impact-through-empowerment/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/impact-through-empowerment/</guid><pubDate>Mon, 24 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In my career, I have realised that the best companies celebrate each success in a genuine, informal way. They avoid contrived rituals that can feel like an artificial façade.&lt;/p&gt;
&lt;p&gt;In these organisations, individuals willingly help colleagues reach shared goals.&lt;/p&gt;
&lt;p&gt;Take Janet from my local Parkrun, for example.&lt;/p&gt;
&lt;p&gt;&lt;img
 src=&quot;https://arrangeactassert.com/static/images/janet-parkrun.jpg&quot;
 alt=&quot;Janet at my local Parkrun encouraging each participant to achieve their goals&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;Although she does not compete, she choose to find the time to cheer on each participant to achieve their goals… even on cold Saturday mornings.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Celebrating success without ceremony creates an environment where everyone feels genuinely valued.&lt;/p&gt;
&lt;p&gt;This approach is far more natural than forcing people to attend mandatory meetings or follow rigid procedures.&lt;/p&gt;
&lt;p&gt;From my experience, an open approach, such as using a Slack channel for professional and personal achievements which is open to everyone, works better than overly formal recognition schemes in which it can be harder to contribute and share.&lt;/p&gt;
&lt;p&gt;Once people embrace this method, openness becomes a habit. Employees feel inspired to share their accomplishments on their terms, promoting a positive organisational culture.&lt;/p&gt;
</content:encoded></item><item><title>From Static to Stateful: Revolutionising AI Communication with the MCP Protocol</title><link>https://arrangeactassert.com/posts/ai-communication-mcp/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-communication-mcp/</guid><pubDate>Mon, 10 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;MCP standardises how AI applications communicate with external systems using JSON‑RPC 2.0 over stateful, bidirectional connections. Unlike standard JSON‑RPC, which treats every request independently, MCP augments the protocol by embedding session tokens and context IDs into each message.&lt;/p&gt;
&lt;p&gt;This enhancement provides state, enabling advanced, multi‑step interactions and dynamic module loading at runtime. Such a stateful design is essential for modern, agile AI systems.&lt;/p&gt;
&lt;p&gt;Imagine an AI‑powered payments system that dynamically integrates a new fraud detection module during operation. MCP allows the system to load this module on the fly without a full redeployment, provided the server supports dynamic module loading.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explore the MCP protocol, its core components, and how it compares to traditional REST and GraphQL APIs.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;core-components&quot;&gt;Core Components&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flexibility &amp;amp; Modularity:&lt;/strong&gt; The clear separation into client, server, and protocol components enables dynamic integration and iterative enhancements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Capabilities:&lt;/strong&gt; The stateful design supports multi‑step operations and real‑time context tracking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Disadvantages:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Increased Complexity:&lt;/strong&gt; The extra architectural layers and stateful interactions require careful design and a steeper learning curve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation Overhead:&lt;/strong&gt; The need for sophisticated session management introduces additional development overhead, though it unlocks features that static APIs cannot provide.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
    subgraph &quot;MCP Core Components&quot;
        direction LR
        A[&quot;Client&amp;lt;br/&amp;gt;(Requests &amp;amp; Callbacks)&quot;] --- C
        C --- B[&quot;Server&amp;lt;br/&amp;gt;(Tools &amp;amp; Resources)&quot;]
        C[&quot;Protocol Layer&amp;lt;br/&amp;gt;(JSON-RPC 2.0+)&quot;]

        C -.-&amp;gt; D[(&quot;Session&amp;lt;br/&amp;gt;Tokens&quot;)]
        C -.-&amp;gt; E[(&quot;Context&amp;lt;br/&amp;gt;IDs&quot;)]
    end

    A &amp;lt;===&amp;gt; |&quot;Stateful&amp;lt;br/&amp;gt;Bidirectional&amp;lt;br/&amp;gt;Communication&quot;| B

    classDef component fill:#4285f4,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef token fill:#fbbc05,stroke:#333,stroke-width:1px,color:#333,rounded:true

    class A,B,C component
    class D,E token

    style A font-weight:bold
    style B font-weight:bold
    style C font-weight:bold
&lt;/pre&gt;
&lt;h2 id=&quot;technical-deep-dive&quot;&gt;Technical Deep Dive&lt;/h2&gt;
&lt;h3 id=&quot;state-management&quot;&gt;State Management&lt;/h3&gt;
&lt;p&gt;MCP’s implementation of statefulness builds on the foundation of JSON‑RPC. While standard JSON‑RPC treats each request as stateless, MCP embeds unique session tokens and context IDs into every message. This approach allows the server to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Establish a session:&lt;/strong&gt; The server issues a session token and context ID on connection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintain context:&lt;/strong&gt; Subsequent requests carry these identifiers, allowing the server to track multi‑step interactions and adjust responses based on accumulated context.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;state-management-interaction-diagram&quot;&gt;State Management Interaction Diagram&lt;/h4&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;sequenceDiagram
    autonumber
    participant Client
    participant Server

    rect rgb(240, 248, 255)
    Note over Client,Server: Session Initialization
    Client-&amp;gt;&amp;gt;Server: Initiate Connection (JSON‑RPC Request)
    Server--&amp;gt;&amp;gt;Client: Respond with Session Token &amp;amp; Context ID
    end

    rect rgb(245, 245, 245)
    Note over Client,Server: Stateful Interaction
    Client-&amp;gt;&amp;gt;Server: Request with Session Token &amp;amp; Context ID
    alt Context Valid
        Server--&amp;gt;&amp;gt;Client: Response with Updated Context
        Client-&amp;gt;&amp;gt;Server: Follow-up Request (with updated context)
        Server--&amp;gt;&amp;gt;Client: Final Result (context-aware)
    else Context Invalid
        Server--&amp;gt;&amp;gt;Client: Error: Invalid Context
    end
    end
&lt;/pre&gt;
&lt;h3 id=&quot;security&quot;&gt;Security&lt;/h3&gt;
&lt;p&gt;MCP’s security is built on a layered approach, incorporating additional steps to safeguard dynamic interactions and state management.&lt;/p&gt;
&lt;h4 id=&quot;security-layers-diagram&quot;&gt;Security Layers Diagram&lt;/h4&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    A[Client Request] --&amp;gt; B[JSON‑RPC Message]
    B --&amp;gt; |&quot;Embedded Security&quot;| C{&quot;Session Token,&amp;lt;br/&amp;gt;Context ID &amp;amp;&amp;lt;br/&amp;gt;Auth Token&quot;}
    C --&amp;gt; D[TLS Encryption]
    D --&amp;gt; E[Authentication&amp;lt;br/&amp;gt;&amp;amp; Authorization]
    E --&amp;gt; F[Token Validation]
    F --&amp;gt; G[Access Control]
    G --&amp;gt; H[Secure Processing]

    classDef process fill:#4285f4,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef security fill:#0f9d58,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef tokens fill:#fbbc05,stroke:#333,stroke-width:1px,color:#333,rounded:true

    class A,B,H process
    class D,E,F,G security
    class C tokens
&lt;/pre&gt;
&lt;h3 id=&quot;error-handling&quot;&gt;Error Handling&lt;/h3&gt;
&lt;p&gt;MCP integrates robust error handling mechanisms to ensure reliable interactions even in complex, stateful sessions.&lt;/p&gt;
&lt;h4 id=&quot;error-handling-sequence-diagram&quot;&gt;Error Handling Sequence Diagram&lt;/h4&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;sequenceDiagram
    autonumber
    participant Client
    participant Server

    Client-&amp;gt;&amp;gt;Server: Function call request (with session token)
    alt Error Scenario
        Server--x Client: Error Response
        Note over Client,Server: Error Code, Message &amp;amp; Recovery Hints
        Client-&amp;gt;&amp;gt;Server: Retry with Error Handling Strategy
        alt Recovery Successful
            Server--&amp;gt;&amp;gt;Client: Success Response
        else Persistent Error
            Server--x Client: Escalated Error With Diagnostics
        end
    else Success Scenario
        Server--&amp;gt;&amp;gt;Client: Success Response with Updated State
    end
&lt;/pre&gt;
&lt;h3 id=&quot;tools-prompts-and-resources&quot;&gt;Tools, Prompts, and Resources&lt;/h3&gt;
&lt;p&gt;MCP differentiates among three types of operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tools:&lt;/strong&gt; RPC methods that produce side effects (e.g., creating or updating resources) and require explicit confirmation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompts:&lt;/strong&gt; Predefined message templates that guide AI actions without causing side effects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resources:&lt;/strong&gt; Read‑only endpoints that provide data access.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    A[MCP Server] --&amp;gt; B
    A --&amp;gt; C
    A --&amp;gt; D

    subgraph Operations
        B[&quot;⚙️ Tool Operations&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Side Effects&amp;lt;/i&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;create, update, delete&amp;lt;/small&amp;gt;&quot;]
        C[&quot;⚙️ Prompts&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;No Side Effects&amp;lt;/i&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;templates, guidance&amp;lt;/small&amp;gt;&quot;]
        D[&quot;⚙️ Resources&amp;lt;br/&amp;gt;&amp;lt;i&amp;gt;Read-Only&amp;lt;/i&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;data access, query&amp;lt;/small&amp;gt;&quot;]
    end

    B --&amp;gt; |&quot;Requires&quot;| E[Explicit Confirmation]
    C --&amp;gt; |&quot;Provides&quot;| F[Action Guidance]
    D --&amp;gt; |&quot;Returns&quot;| G[Data Only]

    classDef server fill:#4285f4,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef operation fill:#34a853,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef effect fill:#fbbc05,stroke:#333,stroke-width:1px,color:#333,rounded:true

    class A server
    class B,C,D operation
    class E,F,G effect
&lt;/pre&gt;
&lt;h3 id=&quot;comparisons-to-restgraphql&quot;&gt;Comparisons to REST/GraphQL&lt;/h3&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
    subgraph REST/GraphQL
        A1[Stateless]
        A2[Resource-centric]
        A3[Fixed Endpoints]
    end

    subgraph MCP
        B1[Stateful]
        B2[Operation-centric]
        B3[Dynamic Tools]
    end

    subgraph Communication
        C1[REST: One-way HTTP]
        C2[GraphQL: Query-focused]
        C3[MCP: Bidirectional with Context]
    end

    subgraph Integration
        D1[REST/GraphQL: Static Integration]
        D2[MCP: Runtime Extension]
    end

    REST/GraphQL -.-&amp;gt; Communication
    MCP -.-&amp;gt; Communication
    REST/GraphQL -.-&amp;gt; Integration
    MCP -.-&amp;gt; Integration

    classDef restStyle fill:#ea4335,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef mcpStyle fill:#4285f4,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef compareStyle fill:#fbbc05,stroke:#333,stroke-width:1px,color:#333,rounded:true

    class A1,A2,A3,C1,C2,D1 restStyle
    class B1,B2,B3,C3,D2 mcpStyle
    class REST/GraphQL,MCP,Communication,Integration compareStyle
&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;MCP represents a significant evolution from static, one‑off API integrations to dynamic, stateful connections that adapt in real time. Its three‑element architecture, comprising the client, server, and protocol, enables advanced features like dynamic tool integration and context‑aware interactions that standard JSON‑RPC cannot support due to its stateless nature.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    M[MCP Protocol] --&amp;gt; A &amp;amp; B &amp;amp; C

    subgraph &quot;Key Capabilities&quot;
        A[Stateful&amp;lt;br/&amp;gt;Communication]
        B[Dynamic Tool&amp;lt;br/&amp;gt;Integration]
        C[Context-Aware&amp;lt;br/&amp;gt;Interactions]
    end

    subgraph &quot;Implementation Benefits&quot;
        D[Real-time&amp;lt;br/&amp;gt;Adaptability]
        E[Enhanced&amp;lt;br/&amp;gt;Security]
        F[Error&amp;lt;br/&amp;gt;Resilience]
        G[Operational&amp;lt;br/&amp;gt;Flexibility]
    end

    A --&amp;gt; D &amp;amp; E
    B --&amp;gt; F &amp;amp; G
    C --&amp;gt; D &amp;amp; G

    classDef main fill:#4285f4,stroke:#333,stroke-width:2px,color:white,rounded:true
    classDef capability fill:#34a853,stroke:#333,stroke-width:1px,color:white,rounded:true
    classDef benefit fill:#fbbc05,stroke:#333,stroke-width:1px,color:#333,rounded:true
    classDef group fill:none,stroke:#ddd,stroke-width:1px,color:#666

    class M main
    class A,B,C capability
    class D,E,F,G benefit
&lt;/pre&gt;
&lt;p&gt;While MCP may not yet be as mature as REST or GraphQL, its enhancements, especially in state management, security, error handling, and bidirectional communication, position it as a promising protocol for the future of agentic AI integration.&lt;/p&gt;
&lt;p&gt;Organisations must balance their dynamic capabilities against the technology’s increased complexity and evolving maturity.&lt;/p&gt;
</content:encoded></item><item><title>Multi-Agent Patterns: A Practical Guide</title><link>https://arrangeactassert.com/posts/multi-agent-patterns/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/multi-agent-patterns/</guid><pubDate>Wed, 05 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;img alt=&quot;multi-agent-patterns.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;768&quot; src=&quot;https://arrangeactassert.com/_astro/multi-agent-patterns.DzBnoJjf_Z1MNjwY.webp&quot; srcset=&quot;/_astro/multi-agent-patterns.DzBnoJjf_Zc6UId.webp 640w, /_astro/multi-agent-patterns.DzBnoJjf_Z19caL1.webp 750w, /_astro/multi-agent-patterns.DzBnoJjf_3G7OW.webp 828w, /_astro/multi-agent-patterns.DzBnoJjf_Z2pyFJp.webp 1080w, /_astro/multi-agent-patterns.DzBnoJjf_r7LNf.webp 1280w, /_astro/multi-agent-patterns.DzBnoJjf_Z1MNjwY.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;p&gt;AI applications are shifting from monolithic large language models to modular, multi-agent systems—a transformation that enhances performance, flexibility, and maintainability.&lt;/p&gt;
&lt;p&gt;In my talk about AI Agents last September, I said AI agents would become increasingly popular. Today, we see this shift happening across industries. By breaking down complex tasks into specialised components, engineers can design smarter, more scalable AI workflows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; Think of multi-agent systems like a well-coordinated orchestra. Each musician (agent) has a specific role, and together, they create a harmonious performance. In software, this means dividing complex problems into manageable, specialised parts that work in concert.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this guide, we’ll explore four key multi-agent patterns, using travel booking as an example. You’ll learn how to choose the right pattern for your application, implementation strategies, and error-handling techniques to build robust multi-agent AI systems.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-domain-challenge&quot;&gt;The Domain Challenge&lt;/h2&gt;
&lt;p&gt;While our examples focus on travel applications, the challenges addressed here are common across many industries:&lt;/p&gt;
&lt;h3 id=&quot;complex-user-interactions&quot;&gt;Complex User Interactions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Interpreting natural language preferences&lt;/li&gt;
&lt;li&gt;Processing dates, locations and multi-step workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sequential-processing-requirements&quot;&gt;Sequential Processing Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Searching and filtering (e.g. flight searches)&lt;/li&gt;
&lt;li&gt;Selecting seats, ancillary services, payment processing, and final confirmation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;external-system-integration&quot;&gt;External System Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Interacting with airline reservation systems, payment gateways, hotel PMS, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;domain-expertise-requirements&quot;&gt;Domain Expertise Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Understanding fare rules, pricing optimisation, route planning, and travel regulations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is a mermaid diagram that visualises these challenges:&lt;/p&gt;
&lt;figcaption&gt;Mermaid diagram: Visualising the main domain challenges in travel booking applications.&lt;/figcaption&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;graph TD
A[Domain Challenges] --&amp;gt; B[Complex User Interactions]
A --&amp;gt; C[Sequential Processing]
A --&amp;gt; D[External Integration]
A --&amp;gt; E[Domain Expertise]
B --&amp;gt; F[Natural Language]
B --&amp;gt; G[Constraints]
C --&amp;gt; H[Search]
C --&amp;gt; I[Booking]
D --&amp;gt; J[APIs &amp;amp; Payment]
E --&amp;gt; K[Pricing]
E --&amp;gt; L[Routing]
&lt;/pre&gt;
&lt;h2 id=&quot;pattern-1-single-agent-workflows&quot;&gt;Pattern 1: Single Agent Workflows&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Use a single agent for focused, well-defined tasks where boundaries are clear and minimal state management is required. This pattern is fast, simple, and ideal for stateless queries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;/h3&gt;
&lt;p&gt;The Single Agent Workflow pattern is ideal for focused, well-defined tasks. Here’s a simplified example of a flight search agent:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; pydantic &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; BaseModel
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; typing &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Optional
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; datetime &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; date

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FlightDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    flight_number&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;
    price&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;
    origin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;
    destination&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;
    departure_date&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; date
    arrival_date&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; date
    duration_hours&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FlightSearchResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    found_flights&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    best_flight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Optional&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
    explanation&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FlightSearchAgent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;system_prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;You are a flight search expert. Your job is to:
        1. Search available flights using the search_flights tool
        2. Analyze the results to find the best option based on price and duration
        3. Provide a clear explanation of why you chose that flight
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# ... initialization code ...&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;search_flights&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; origin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Implementation to search flights&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;when-to-use-single-agent-workflows&quot;&gt;When to Use Single Agent Workflows&lt;/h3&gt;
&lt;p&gt;Single Agent Workflows are most effective when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Task Boundaries are Clear:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;E.g. flight searches with specific criteria, seat selection, or baggage allowance calculations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Minimal State Management is Required:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ideal for one-off, stateless queries and independent transactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance is Critical:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Such as in real-time pricing updates or immediate availability checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;implementation-considerations&quot;&gt;Implementation Considerations&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Consideration&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input Validation&lt;/td&gt;
&lt;td&gt;Ensure all required parameters are provided&lt;/td&gt;
&lt;td&gt;Check date formats, airport codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error Handling&lt;/td&gt;
&lt;td&gt;Comprehensive error catching is essential&lt;/td&gt;
&lt;td&gt;Handling API timeouts, invalid responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response Format&lt;/td&gt;
&lt;td&gt;Structure responses for easy consumption&lt;/td&gt;
&lt;td&gt;Use Pydantic models for type safety&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Track performance and success rates&lt;/td&gt;
&lt;td&gt;Log response times and error rates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;code-example-error-handling&quot;&gt;Code Example: Error Handling&lt;/h3&gt;
&lt;p&gt;Robust error handling is crucial. The example below demonstrates how to implement retries with exponential backoff:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FlightSearchError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Exception&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Base exception for flight search errors&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InvalidSearchCriteriaError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FlightSearchError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Raised when search criteria is invalid&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;search_with_retries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; criteria&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; FlightSearchCriteria&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max_retries&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightSearchResult&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 retry_count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; retry_count &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; max_retries&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_perform_search&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;criteria&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; FlightSearchError &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 retry_count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; retry_count &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; max_retries&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; asyncio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sleep&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; retry_count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Exponential backoff&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A corresponding sequence diagram visualises the process:&lt;/p&gt;
&lt;figcaption&gt;Mermaid sequence diagram: Flight search agent workflow from user input to curated options.&lt;/figcaption&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;sequenceDiagram
 participant U as User
 participant A as Flight Search Agent
 participant D as Flight Database
 participant P as Price Optimiser

 U-&amp;gt;&amp;gt;A: Submit search criteria
 A-&amp;gt;&amp;gt;A: Validate input
 A-&amp;gt;&amp;gt;D: Query flights
 D--&amp;gt;&amp;gt;A: Raw flight data
 A-&amp;gt;&amp;gt;P: Optimise pricing
 P--&amp;gt;&amp;gt;A: Price recommendations
 A-&amp;gt;&amp;gt;A: Apply business rules
 A--&amp;gt;&amp;gt;U: Curated flight options
&lt;/pre&gt;
&lt;h2 id=&quot;pattern-2-agent-delegation&quot;&gt;Pattern 2: Agent Delegation&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Delegate responsibilities to specialist agents, coordinated by a controller. This pattern increases modularity and scalability, but requires robust error handling and coordination.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;implementation-architecture&quot;&gt;Implementation Architecture&lt;/h3&gt;
&lt;p&gt;The Agent Delegation pattern uses a controller agent to coordinate specialized delegate agents. Here’s a simplified example:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; typing &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Optional
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; datetime &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; date
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; pydantic &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; BaseModel

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TravelPlan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    outbound_flight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; FlightDetails
    return_flight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Optional&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    hotel_recommendations&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    activity_suggestions&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    total_budget&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Flight search agent (delegate)&lt;/span&gt;
flight_search_agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    result_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    system_prompt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You are a flight search specialist. Find the best flights matching the given criteria.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Travel planner agent (controller)&lt;/span&gt;
travel_planner_agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    result_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;TravelPlan&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    system_prompt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;You are a travel planning expert. Your job is to:
    1. Use the flight_search tool to find suitable flights
    2. Suggest hotels and activities at the destination
    3. Calculate total budget including flights and estimated other expenses
    &quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;benefits-and-trade-offs&quot;&gt;Benefits and Trade-offs&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Benefits&lt;/th&gt;
&lt;th&gt;Trade-offs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Modularity&lt;/td&gt;
&lt;td&gt;Clear division of responsibilities&lt;/td&gt;
&lt;td&gt;Increased system complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Easy to add specialist agents&lt;/td&gt;
&lt;td&gt;More points of failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Agents can be updated independently&lt;/td&gt;
&lt;td&gt;Requires robust error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Parallel processing is possible&lt;/td&gt;
&lt;td&gt;Additional coordination overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;error-handling-strategies&quot;&gt;Error Handling Strategies&lt;/h3&gt;
&lt;p&gt;Coordinated error handling is key. For example:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TravelPlanningError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Exception&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Base exception for travel planning errors&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AgentCoordinationError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TravelPlanningError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Raised when agent coordination fails&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TravelPlannerAgent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create_travel_plan_with_fallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; origin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dates&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Dict&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; datetime&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Dict&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; TravelPlan&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;create_travel_plan&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dates&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; FlightSearchError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Fallback to alternative dates or routes&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_handle_flight_search_failure&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dates&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; HotelSearchError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Fallback to alternative accommodations&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_handle_hotel_search_failure&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dates&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; ActivityPlanningError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# Create a plan without activities&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_create_basic_travel_plan&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dates&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;implementation-considerations-1&quot;&gt;Implementation Considerations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Agent Communication:&lt;/strong&gt; Use standardised message formats and implement retry mechanisms.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;State Management:&lt;/strong&gt; Track the progress of each sub-agent and maintain booking consistency.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring and Logging:&lt;/strong&gt; Monitor performance metrics and log coordination events.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing:&lt;/strong&gt; Unit test individual agents and integration test their interactions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pattern-3-programmatic-agent-hand-off&quot;&gt;Pattern 3: Programmatic Agent Hand-off&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Explicitly transition between specialised agents for each workflow step. This pattern offers flexibility and strong error recovery, but increases complexity and requires careful state management.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;implementation-details-1&quot;&gt;Implementation Details&lt;/h3&gt;
&lt;p&gt;This pattern manages explicit transitions between specialized agents:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Flight search agent&lt;/span&gt;
flight_search_agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    result_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    system_prompt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Find available flights matching the search criteria.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Seat selection agent&lt;/span&gt;
seat_selection_agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    result_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;SeatPreference&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    system_prompt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Help users select their seat based on their preferences.
    - Rows 1, 14, and 20 have extra legroom
    - Seats A and F are window seats
    &quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Payment processing agent&lt;/span&gt;
payment_agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    result_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;PaymentResult&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    system_prompt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Process payment and generate booking confirmation.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;process_booking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Step 1: Search for flights&lt;/span&gt;
    flight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; search_flights&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;usage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; origin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SFO&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;JFK&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; travel_date&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2024&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Step 2: Select seat&lt;/span&gt;
    seat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; select_seat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;usage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; preferences&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;window seat with extra legroom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Step 3: Process payment&lt;/span&gt;
    payment_result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; process_payment&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;usage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flight&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;flight&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; seat&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;seat&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payment_info&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Credit card ending in 1234&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;error-handling-strategies-1&quot;&gt;Error Handling Strategies&lt;/h3&gt;
&lt;p&gt;Key aspects include state-based recovery, graceful degradation, and robust monitoring. Below is a mermaid state diagram illustrating possible transitions:&lt;/p&gt;
&lt;figcaption&gt;Mermaid state diagram: State transitions in a programmatic agent hand-off workflow.&lt;/figcaption&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;stateDiagram-v2
 [*] --&amp;gt; INITIATED
 INITIATED --&amp;gt; FLIGHTS_SELECTED: Flight search success
 INITIATED --&amp;gt; FAILED: Search error
 FLIGHTS_SELECTED --&amp;gt; SEATS_SELECTED: Seat selection success
 FLIGHTS_SELECTED --&amp;gt; FAILED: Selection error
 SEATS_SELECTED --&amp;gt; PAYMENT_PROCESSING: Payment initiated
 PAYMENT_PROCESSING --&amp;gt; COMPLETED: Payment success
 PAYMENT_PROCESSING --&amp;gt; FAILED: Payment error
 FAILED --&amp;gt; [*]
 COMPLETED --&amp;gt; [*]
&lt;/pre&gt;
&lt;h3 id=&quot;usage-example&quot;&gt;Usage Example&lt;/h3&gt;
&lt;p&gt;An API endpoint that processes a booking using the orchestrator:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/bookings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create_booking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; BookingRequest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; orchestrator&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; BookingOrchestrator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Depends&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get_orchestrator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; BookingResponse&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BookingContext&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        booking_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;generate_booking_id&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        state&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;INITIATED&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        user_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        search_criteria&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search_criteria&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        created_at&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utcnow&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        updated_at&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utcnow&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 final_context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; orchestrator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;process_booking&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; BookingResponse&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        booking_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;booking_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        status&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        error&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        flights&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flights&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        seats&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;selected_seats&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        payment_info&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payment_info
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;implementation-considerations-2&quot;&gt;Implementation Considerations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;State Management:&lt;/strong&gt; Persist the BookingContext (e.g. using a database).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retry Strategies:&lt;/strong&gt; Use exponential backoff where necessary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transaction Boundaries:&lt;/strong&gt; Maintain atomicity of state transitions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt; Record state transition times and error counts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pattern-4-graph-based-control-flow&quot;&gt;Pattern 4: Graph-based Control Flow&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Use a graph structure to manage complex workflows with many possible transitions. This pattern is highly flexible and scalable, but requires comprehensive monitoring and error recovery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;implementation-details-2&quot;&gt;Implementation Details&lt;/h3&gt;
&lt;p&gt;This pattern uses a graph structure to manage complex workflows:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@dataclass&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BookingState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;State maintained throughout the booking process.&quot;&quot;&quot;&lt;/span&gt;
    origin&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;
    destination&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;
    travel_date&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; date
    selected_flight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Optional&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FlightDetails&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
    selected_seat&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Optional&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;SeatPreference&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
    payment_info&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Optional&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
    booking_confirmed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;
    agent_messages&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Dict&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; List&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ModelMessage&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; field&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;default_factory&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@dataclass&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SearchFlights&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseNode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Search for available flights.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; GraphRunContext&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; BaseNode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; End&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; flight_search_agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Find flights from &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; on &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;travel_date&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;selected_flight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; SelectSeat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@dataclass&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SelectSeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseNode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Select seat preferences for the flight.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; GraphRunContext&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; BaseNode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BookingState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; seat_selection_agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;I&apos;d like a window seat with extra legroom if possible&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;selected_seat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ProcessPayment&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;implementation-considerations-3&quot;&gt;Implementation Considerations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;State Design:&lt;/strong&gt; Define clear transitions and metadata.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Error Recovery:&lt;/strong&gt; Implement retryable and monitored nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring and Metrics:&lt;/strong&gt; Track execution times, transitions, and errors.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below is a mermaid diagram representing a typical graph-based workflow:&lt;/p&gt;
&lt;figcaption&gt;Mermaid state diagram: Graph-based control flow for a travel booking system.&lt;/figcaption&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;stateDiagram-v2
 [*] --&amp;gt; SearchFlights
 SearchFlights --&amp;gt; SelectFlights: Flights found
 SearchFlights --&amp;gt; [*]: Error
 SelectFlights --&amp;gt; SearchHotels: Flights selected
 SelectFlights --&amp;gt; [*]: Error
 SearchHotels --&amp;gt; SelectHotels: Hotels found
 SearchHotels --&amp;gt; [*]: Error
 SelectHotels --&amp;gt; SelectSeats: Hotels selected
 SelectSeats --&amp;gt; ProcessPayment: Seats selected
 SelectSeats --&amp;gt; SelectSeats: Retry selection
 ProcessPayment --&amp;gt; [*]: Success/Error
&lt;/pre&gt;
&lt;h3 id=&quot;usage-example-1&quot;&gt;Usage Example&lt;/h3&gt;
&lt;p&gt;An API endpoint employing a graph-based runner might look like this:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/bookings/graph&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create_booking_graph&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; BookingRequest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; runner&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; BookingGraphRunner &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Depends&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get_graph_runner&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; BookingResponse&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 initial_state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BookingGraphState&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        booking_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;generate_booking_id&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        user_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        origin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        destination&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        dates&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dates&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        preferences&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;booking_request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;preferences&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        agent_messages&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 final_state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; runner&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;run&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initial_state&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; BookingResponse&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        booking_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;booking_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        status&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;completed&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;failed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        error&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        flights&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flights&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        hotels&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hotels&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        selected_seats&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;selected_seats&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        payment_info&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;final_state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payment_info
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;choosing-the-right-pattern&quot;&gt;Choosing the Right Pattern&lt;/h2&gt;
&lt;h3 id=&quot;comparative-analysis&quot;&gt;Comparative Analysis&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Single Agent&lt;/th&gt;
&lt;th&gt;Agent Delegation&lt;/th&gt;
&lt;th&gt;Programmatic Hand-off&lt;/th&gt;
&lt;th&gt;Graph-based Flow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State Management&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;td&gt;Very Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error Handling&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Coordinated&lt;/td&gt;
&lt;td&gt;Programmatic&lt;/td&gt;
&lt;td&gt;Comprehensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Very Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Development Speed&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;Very Slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;td&gt;Very Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibility&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Very Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;td&gt;Very Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;real-world-applications&quot;&gt;Real-World Applications&lt;/h3&gt;
&lt;h4 id=&quot;flight-booking-systems&quot;&gt;Flight Booking Systems&lt;/h4&gt;
&lt;p&gt;Example: A multi-city flight booking system using Graph-based Flow to manage complex routing.&lt;/p&gt;
&lt;h4 id=&quot;hotel-booking-systems&quot;&gt;Hotel Booking Systems&lt;/h4&gt;
&lt;p&gt;Example: Using Agent Delegation for optimised hotel search and pricing.&lt;/p&gt;
&lt;h4 id=&quot;travel-package-systems&quot;&gt;Travel Package Systems&lt;/h4&gt;
&lt;p&gt;Example: Building dynamic packages via Programmatic Hand-off to sequence flights, hotels and activities.&lt;/p&gt;
&lt;h4 id=&quot;travel-itinerary-systems&quot;&gt;Travel Itinerary Systems&lt;/h4&gt;
&lt;p&gt;Example: Employing Single Agent Workflows for fast, AI-powered itinerary optimisation.&lt;/p&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best Practices&lt;/h2&gt;
&lt;h3 id=&quot;pattern-selection&quot;&gt;Pattern Selection&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Begin with the most straightforward pattern that meets your needs.&lt;/li&gt;
&lt;li&gt;Consider future scalability and complexity before adding layers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use strong typing with Pydantic models.&lt;/li&gt;
&lt;li&gt;Incorporate comprehensive logging and monitoring.&lt;/li&gt;
&lt;li&gt;Build robust error handling and retry strategies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Unit test individual agents.&lt;/li&gt;
&lt;li&gt;Integration test agent interactions.&lt;/li&gt;
&lt;li&gt;Execute end-to-end tests and stress-test state management.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;monitoring&quot;&gt;Monitoring&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Track performance metrics and state transitions.&lt;/li&gt;
&lt;li&gt;Log error rates and adjust retry strategies as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Multi-agent patterns provide a structured and scalable approach to managing complex tasks in modern applications.&lt;/p&gt;
&lt;p&gt;Whether you’re implementing a simple, single-agent workflow or a comprehensive, graph-based control flow, the right pattern will ensure clarity, reliability, and an excellent user experience.&lt;/p&gt;
&lt;p&gt;By following these best practices and real-world examples from the travel domain, you can build robust and adaptable systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What multi-agent pattern will you try in your next project? Share your experiences, questions, or challenges in the comments or reach out to continue the conversation.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/research/building-effective-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Building Effective Agents (Anthropic Research)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ai.pydantic.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PydanticAI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jreehal/multi-agent-patterns-pydantic-ai&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Multi-Agent Patterns Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>When to Use Agentic Systems</title><link>https://arrangeactassert.com/posts/when-to-use-agentic-systems/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/when-to-use-agentic-systems/</guid><pubDate>Sun, 02 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Agentic systems, where multiple AI agents collaborate through decision-making and handoffs, shine in specific scenarios but add operational complexity.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explore the scenarios where agentic systems are most effective and the challenges you may face when using them.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Anthropic’s guide on &lt;a href=&quot;https://www.anthropic.com/research/building-effective-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;building effective agents&lt;/a&gt; has become the definitive resource in this space.&lt;/p&gt;
&lt;p&gt;Their core advice? Start simple - use the most straightforward solution, and only add complexity when necessary. Agentic systems trade increased latency and cost for improved performance, so validate this tradeoff first.&lt;/p&gt;
&lt;p&gt;From hands-on experience building production systems, agentic approaches prove most valuable when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tasks require multiple steps&lt;/strong&gt;: When a single LLM call can’t complete the job (e.g., research → analysis → report generation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Specialisation matters&lt;/strong&gt;: When different task aspects need tailored models/prompts (e.g., factual lookup vs. creative writing)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flexibility is critical&lt;/strong&gt;: When step sequences can’t be predetermined (e.g., customer service → technical specialist escalation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Domain complexity demands it&lt;/strong&gt;: When knowledge needs compartmentalization (e.g., legal + medical expertise in insurance claims)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my work with clients, optimised single LLM calls with retrieval augmentation often suffice. It’s only when the complexity of the task is such that the agentic approach demonstrably improves outcomes that I recommend adopting agentic patterns.&lt;/p&gt;
&lt;h2 id=&quot;design-principles-for-effective-agents&quot;&gt;Design Principles for Effective Agents&lt;/h2&gt;
&lt;p&gt;Now that we’ve established when agentic systems are appropriate, let’s explore core design principles informed by Anthropic’s research and hard-won implementation lessons:&lt;/p&gt;
&lt;h3 id=&quot;simplicity-first&quot;&gt;Simplicity First&lt;/h3&gt;
&lt;p&gt;Implement the minimal viable system, then iterate. Follow the engineering maxim: “Make it work, make it right, make it fast” - in that order.&lt;/p&gt;
&lt;h3 id=&quot;atomic-responsibilities&quot;&gt;Atomic Responsibilities&lt;/h3&gt;
&lt;p&gt;Each agent should have one clear purpose. Like microservices, maintain a strict separation of concerns (e.g., “Medical Term Explainer” vs “Insurance Policy Parser”).&lt;/p&gt;
&lt;h3 id=&quot;complexity-with-cause&quot;&gt;Complexity with Cause&lt;/h3&gt;
&lt;p&gt;Add components only when metrics prove their value. Remember: More agents = more failure points + latency.&lt;/p&gt;
&lt;h3 id=&quot;transparent-operations&quot;&gt;Transparent Operations&lt;/h3&gt;
&lt;p&gt;Make the active agent always apparent to users and engineers. Visual indicators (e.g., “[Medical Expert] Analysing scan results…”) build trust and aid debugging.&lt;/p&gt;
&lt;h3 id=&quot;failure-resilience&quot;&gt;Failure Resilience&lt;/h3&gt;
&lt;p&gt;Implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Timeouts for all agent interactions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fallback routes for stuck workflows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Input validation guards&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test edge cases ruthlessly - especially handoff transitions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;observability-focus&quot;&gt;Observability Focus&lt;/h3&gt;
&lt;p&gt;Track:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Handoff success rates&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agent-specific latency&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Error hot spots&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Completion metrics&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use this data to drive iterative improvements.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Agentic systems aren’t inherently better; they’re tools with specific strengths. The goal isn’t to build the most sophisticated architecture using the latest flavor of AI patterns but the simplest solution for your users’ needs.&lt;/p&gt;
</content:encoded></item><item><title>Next.js after: Track Analytics and Events Without Slowing Down Your App</title><link>https://arrangeactassert.com/posts/nextjs-after/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/nextjs-after/</guid><pubDate>Thu, 27 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Imagine: you run a busy online shop where every moment matters.&lt;/p&gt;
&lt;p&gt;Your customers expect the fastest page loads, yet you still require dependable analytics to understand user behaviour and drive informed business decisions.&lt;/p&gt;
&lt;p&gt;Relying solely on client-side tracking with tools like PostHog can be fraught with challenges. Many users have ad blockers or privacy extensions that prevent tracking scripts from running, and even when these scripts do execute, they can slow down page rendering and affect conversion rates.&lt;/p&gt;
&lt;p&gt;In this post I’ll go over how you can use Next.js 15’s next/after API to handle analytics and events without slowing down your site.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;blockquote&gt;
&lt;p&gt;The code used in this post is available on &lt;a href=&quot;https://github.com/jagreehal/next-after-server-analytics-example&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-problem-with-client-side-analytics&quot;&gt;The Problem with Client-side Analytics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Browser Blockers&lt;/strong&gt;: Ad blockers or privacy extensions often intercept client-side analytics requests, leading to data loss.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Delays&lt;/strong&gt;: Tracking scripts that run on the client can slow down page loading as they load and execute.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reliability Issues&lt;/strong&gt;: Network hiccups or browser inconsistencies might stop analytics data from being sent reliably.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-solution-server-side-analytics-with-nextafter&quot;&gt;The Solution: Server-side analytics with next/after&lt;/h2&gt;
&lt;p&gt;Next.js 15 introduces the &lt;code&gt;after&lt;/code&gt; function from &lt;code&gt;next/server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This feature lets you run code after the response has been sent to the client. In practice, this means you can offload non-critical tasks, such as tracking user events,to the background, ensuring your users enjoy a fast, seamless experience.&lt;/p&gt;
&lt;h3 id=&quot;benefits-include&quot;&gt;Benefits include&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bypass Browser Restrictions&lt;/strong&gt;: Ad blockers don’t affect server-side requests, ensuring you capture every important event.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Faster Load Times&lt;/strong&gt;: Your users get an immediate response, while the tracking occurs asynchronously.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Improved Reliability&lt;/strong&gt;: Handling analytics on the server minimises issues caused by network fluctuations or browser quirks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Improved UX with Immediate Redirects&lt;/strong&gt;: When a form is submitted, the user is redirected to the success page instantly, without waiting for analytics tracking to complete.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Optimization&lt;/strong&gt;: Computing resources are better utilized as analytics processing doesn’t block your main user flows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Optimal for Serverless&lt;/strong&gt;: Perfect for serverless environments where compute time is limited, as it allows the main response to complete quickly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;implementing-this-with-posthog&quot;&gt;Implementing This with PostHog&lt;/h2&gt;
&lt;h3 id=&quot;1-set-up-your-nextjs-15-project&quot;&gt;1. Set Up Your Next.js 15 Project&lt;/h3&gt;
&lt;p&gt;First, create your Next.js project:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-next-app@latest my-analytics-app&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;after&lt;/code&gt; function is available by default in Next.js 15 without requiring any experimental flags.&lt;/p&gt;
&lt;h3 id=&quot;2-install-posthog-and-secure-your-credentials&quot;&gt;2. Install PostHog and Secure Your Credentials&lt;/h3&gt;
&lt;p&gt;Install the PostHog Node.js library:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; posthog-node&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a utility file to initialise your PostHog client using server-only environment variables. This is important to ensure your API key remains secure:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/lib/posthog.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; PostHog &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;posthog-node&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getPostHogClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PostHog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;POSTHOG_KEY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Use a server-side environment variable&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; host&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;POSTHOG_HOST&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set your credentials in a .env.local file:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;POSTHOG_KEY=your_project_api_key
POSTHOG_HOST=https://app.posthog.com&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-track-events-with-nextafter&quot;&gt;3. Track Events with next/after&lt;/h3&gt;
&lt;p&gt;Use a server action to defer analytics tracking until after the response is sent. This ensures that the analytics process doesn’t hamper user experience:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/actions.ts&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&apos;use server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getPostHogClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/posthog&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; after &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eventName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; posthog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getPostHogClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; posthog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;capture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        distinctId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Flush the queue using the standard shutdown method&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; posthog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Error tracking event:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-integrate-tracking-in-your-components&quot;&gt;4. Integrate Tracking in Your Components&lt;/h3&gt;
&lt;p&gt;For instance, if you wish to track a form submission without delaying the user’s redirect, you might do the following:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/page.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trackEvent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./actions&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; redirect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/navigation&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleSubmit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;formData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;use server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Process form data as required&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// This won&apos;t block the response - analytics happens in the background&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;form_submitted&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;anonymous_user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// User is redirected immediately&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;form action&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleSubmit&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt; placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Enter your email&quot;&lt;/span&gt; required &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;form&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;5-create-a-success-page&quot;&gt;5. Create a Success Page&lt;/h3&gt;
&lt;p&gt;Create a simple success page that users will be redirected to after form submission:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/success/page.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Link &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/link&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SuccessPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Form Submitted Successfully&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Your form has been submitted and analytics are being tracked &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; the background&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Link href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Back to Home&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Link&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;6-run-the-development-server&quot;&gt;6. Run the Development Server&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;7-submit-the-form&quot;&gt;7. Submit the Form&lt;/h3&gt;
&lt;p&gt;Submit the form to see server-side analytics in action. You can check your PostHog dashboard to verify the events are being tracked.&lt;/p&gt;
&lt;h2 id=&quot;why-this-approach-works&quot;&gt;Why This Approach Works&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Instant User Experience&lt;/strong&gt;: The critical page rendering and navigations aren’t delayed by analytics processing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accurate Data&lt;/strong&gt;: Server-side tracking bypasses the limitations of ad blockers and reduces the chance of network-related errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simple Integration&lt;/strong&gt;: The &lt;code&gt;after&lt;/code&gt; function makes managing background tasks straightforward without complex setups.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using Next.js 15’s cutting-edge features combined with PostHog for server-side analytics, you can optimise your website’s performance and the accuracy of your data, ensuring a seamless experience for your users and more reliable insights for your business.&lt;/p&gt;
</content:encoded></item><item><title>Event-Driven Architecture: How I Name Events (A Practical Guide With Examples)</title><link>https://arrangeactassert.com/posts/how-i-name-events/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-i-name-events/</guid><pubDate>Mon, 24 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Getting event names right in event-driven architecture and Domain-Driven Design (DDD) is essential for clarity, consistency, and scalability. A key decision is using singular or plural terms in event names.&lt;/p&gt;
&lt;p&gt;Here’s how I approach it, with examples and reasoning to help you make the best choice.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;1-plural-for-collections&quot;&gt;1. Plural for Collections&lt;/h2&gt;
&lt;p&gt;Example: &lt;code&gt;v1.payees.created&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When an event relates to a collection of entities, the domain should be plural. This clarifies that the event belongs to a broader category and aligns with DDD aggregate roots.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v1.payees.created&lt;/code&gt; → A new payee was created within the payees aggregate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.payments.failed&lt;/code&gt; → A payment failure occurred within the payments domain&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.users.registered&lt;/code&gt; → A user was registered in the users domain&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-singular-for-processes&quot;&gt;2. Singular for Processes&lt;/h2&gt;
&lt;p&gt;Example: &lt;code&gt;v1.transaction.authorised&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If the event describes a business process, workflow, or single entity, use singular to avoid confusion with collections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v1.transaction.authorised&lt;/code&gt; → A single transaction was authorised&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.conversion.trade.settled&lt;/code&gt; → A specific trade within a conversion was settled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.authentication.failed&lt;/code&gt; → A single authentication attempt failed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-plural-for-sub-entities&quot;&gt;3. Plural for Sub-Entities&lt;/h2&gt;
&lt;p&gt;Example: &lt;code&gt;v1.conversion.trades.settled&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When an event relates to sub-entities within a domain, pluralization helps differentiate them from the main domain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v1.conversion.trades.settled&lt;/code&gt; → Multiple trades within a single conversion were settled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.order.items.shipped&lt;/code&gt; → Multiple items in an order were shipped&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.invoice.payments.processed&lt;/code&gt; → Multiple payments related to an invoice were processed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-versioning-at-the-beginning&quot;&gt;4. Versioning at the Beginning&lt;/h2&gt;
&lt;p&gt;Example: &lt;code&gt;v1.domain.event&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best Practice&lt;/strong&gt;: Always place the version number at the beginning to make versioning immediately visible and to facilitate version-based routing and filtering.&lt;/p&gt;
&lt;p&gt;🚫 &lt;strong&gt;Bad Example&lt;/strong&gt;: &lt;code&gt;payments.failed.v1&lt;/code&gt;&lt;br&gt;
✅ &lt;strong&gt;Good Example&lt;/strong&gt;: &lt;code&gt;v1.payments.failed&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;why-version-first&quot;&gt;Why Version First?&lt;/h3&gt;
&lt;p&gt;Placing the version at the beginning offers several advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Immediate visibility&lt;/strong&gt;: Version information is the first thing you see&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier filtering&lt;/strong&gt;: Systems can quickly filter or route by version without parsing the entire event name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clearer version transitions&lt;/strong&gt;: Makes it easier to identify different versions of the same event type&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent with API versioning&lt;/strong&gt;: Aligns with common API versioning practices&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;additional-guidelines&quot;&gt;Additional Guidelines&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Aggregate Naming in DDD&lt;/strong&gt;:&lt;br&gt;
Aggregates in DDD are typically singular (e.g., Order), but event topics use plural names (e.g., &lt;code&gt;v1.payments.failed&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clarity vs. Rigidity&lt;/strong&gt;:&lt;br&gt;
Conventions should adapt to domain needs. For example: &lt;code&gt;v1.conversions.trade.settled&lt;/code&gt; might be valid for process collections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Event Payload Context&lt;/strong&gt;:&lt;br&gt;
Plurality in event names doesn’t dictate entity count. &lt;code&gt;v1.payments.failed&lt;/code&gt; could reference a single payment failure.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plural for collections&lt;/strong&gt;: &lt;code&gt;v1.payees.created&lt;/code&gt;, &lt;code&gt;v1.payments.failed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Singular for processes&lt;/strong&gt;: &lt;code&gt;v1.transaction.authorised&lt;/code&gt;, &lt;code&gt;v1.conversion.trade.settled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plural for sub-entities&lt;/strong&gt;: &lt;code&gt;v1.conversion.trades.settled&lt;/code&gt;, &lt;code&gt;v1.order.items.shipped&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version at the beginning&lt;/strong&gt;: &lt;code&gt;v1.domain.event&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following these naming conventions will make your event-driven architecture structured, scalable, and aligned with domain modelling principles.&lt;/p&gt;
</content:encoded></item><item><title>Building TypeScript Libraries&apos; A Guide to Explicit Exports, Tree Shaking, and Common Pitfalls</title><link>https://arrangeactassert.com/posts/building-typescript-libraries/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/building-typescript-libraries/</guid><pubDate>Thu, 20 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;img alt=&quot;builder building typescript sign&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;768&quot; src=&quot;https://arrangeactassert.com/_astro/building-typescript-libraries.BkqJM5OS_1xtJW7.webp&quot; srcset=&quot;/_astro/building-typescript-libraries.BkqJM5OS_oDryR.webp 640w, /_astro/building-typescript-libraries.BkqJM5OS_Z1JR7jB.webp 750w, /_astro/building-typescript-libraries.BkqJM5OS_ZoPfrN.webp 828w, /_astro/building-typescript-libraries.BkqJM5OS_Z24hKrQ.webp 1080w, /_astro/building-typescript-libraries.BkqJM5OS_1f3fAp.webp 1280w, /_astro/building-typescript-libraries.BkqJM5OS_1xtJW7.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Building a TypeScript library that is both maintainable and optimised for modern bundlers requires careful consideration of exporting functions, types, and other constructs from your modules.&lt;/p&gt;
&lt;p&gt;With several strategies available, from wildcard re-exports to namespaced exports, explicitly named re-exports have emerged as the clear winner. This post explores the alternatives with examples based on an order management system.&lt;/p&gt;
&lt;p&gt;We’ll discuss the benefits of exporting types, how to organise multiple entry routes (such as in &lt;code&gt;/src/orders&lt;/code&gt; and &lt;code&gt;/src/users&lt;/code&gt;), and review the necessary TypeScript configuration options (such as verbatimModuleSyntax) and package.json tweaks. Additionally, we’ll explain how this approach helps prevent circular dependency challenges by enforcing a clear dependency graph.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;building-a-library&quot;&gt;Building a library&lt;/h2&gt;
&lt;p&gt;Imagine you are developing a library for an order management system that handles order lookups, cancellations, and creation. Your project is organised into distinct domains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Orders – containing all logic related to order lookups, cancellations, and creation&lt;/li&gt;
&lt;li&gt;Users – managing user profiles, authentication, and related queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your public API should enable consumers to import functions and types naturally. For instance, they should be able to write:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lookupOrder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cancelOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./orders&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Order &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./orders&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updateUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./users&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The challenge is organising your exports to achieve maximum tree-shaking efficiency, avoid naming collisions, and offer a seamless experience for value and type-only imports.&lt;/p&gt;
&lt;h2 id=&quot;alternative-exporting-approaches&quot;&gt;Alternative Exporting Approaches&lt;/h2&gt;
&lt;h3 id=&quot;1-re-exporting-with-export--from&quot;&gt;1. Re-Exporting with export * from&lt;/h3&gt;
&lt;p&gt;A common method is to re-export everything from a module:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/orders/index.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./commands&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concise and straightforward&lt;/li&gt;
&lt;li&gt;Automatically exposes all exports from the underlying modules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;While modern bundlers generally handle tree shaking well, wildcard exports can occasionally lead to ambiguity in complex dependency graphs&lt;/li&gt;
&lt;li&gt;There is a higher risk of naming collisions if multiple modules export identically named identifiers&lt;/li&gt;
&lt;li&gt;Consumers may have less clarity about which symbols form part of the public API&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-namespace-exports-with-export--as-ns-from&quot;&gt;2. Namespace Exports with export * as ns from&lt;/h3&gt;
&lt;p&gt;Another option is to group exports under a namespace:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/orders/index.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lookup &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; commands &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./commands&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Consumers would then import and access functions as follows:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lookup &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./orders&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
lookup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lookupOrder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimises the risk of naming collisions by encapsulating exports within a namespace&lt;/li&gt;
&lt;li&gt;Clearly indicates the origin of each function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduces an extra level of nesting, which can be less ergonomic&lt;/li&gt;
&lt;li&gt;Consumers must always reference the namespace even if they only require one function&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-explicit-named-re-exports-our-recommended-approach&quot;&gt;3. Explicit Named Re-Exports (Our Recommended Approach)&lt;/h3&gt;
&lt;p&gt;We recommend explicitly listing the exports in your domain’s index file. For example, in the domain of the order:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/orders/index.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lookupOrder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cancelOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createOrder &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./commands&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; OrderStatus &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./types&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in the users domain:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/users/index.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; listUsers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./queries&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; updateUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./commands&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tree Shaking &amp;amp; Bundle Optimisation: Explicit exports enable bundlers such as Webpack, Rollup, and esbuild to eliminate unused code accurately&lt;/li&gt;
&lt;li&gt;Collision Avoidance: Explicitly listing exports prevents accidental name collisions&lt;/li&gt;
&lt;li&gt;Consumer Experience: Consumers benefit from a clean and direct import syntax without unnecessary nesting&lt;/li&gt;
&lt;li&gt;API Clarity: The public API is clearly defined and straightforward to document&lt;/li&gt;
&lt;li&gt;Prevention of Circular Dependencies: By clearly specifying the exports for each module, you enforce a transparent dependency graph&lt;/li&gt;
&lt;li&gt;Future-Proofing: This approach works seamlessly with modern ECMAScript Modules and TypeScript’s verbatimModuleSyntax option&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requires manual updating of index files when new functions or types are added&lt;/li&gt;
&lt;li&gt;Involves slightly more maintenance overhead compared to wildcard re-exports (though modern IDEs can often automate this process)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;typescript-configuration--packagejson-adjustments&quot;&gt;TypeScript Configuration &amp;amp; Package.json Adjustments&lt;/h2&gt;
&lt;p&gt;To fully leverage explicit named re-exports in the ESM era, update your tsconfig.json as follows:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;esnext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;esnext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;verbatimModuleSyntax&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// other options...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The verbatimModuleSyntax option ensures that TypeScript leaves your ES module import/export statements untouched, essential for effective tree shaking by modern bundlers.&lt;/p&gt;
&lt;p&gt;In your package.json, expose your public API entry points:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my-library&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;./orders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./dist/orders/index.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;./users&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./dist/users/index.js&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsc&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;multiple-entry-routes-a-concrete-example&quot;&gt;Multiple Entry Routes: A Concrete Example&lt;/h2&gt;
&lt;p&gt;Assuming your project is structured like this:&lt;/p&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;src/
  orders/
    lookup.ts         // Contains lookupOrder, cancelOrder, etc.
    commands.ts       // Contains createOrder.
    types.ts          // Contains Order, OrderStatus, etc.
    index.ts          // Explicitly re-exports functions and types.
  users/
    queries.ts        // Contains getUser, listUsers, etc.
    commands.ts       // Contains updateUser.
    index.ts&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;exporting-types-why-it-matters&quot;&gt;Exporting Types: Why It Matters&lt;/h2&gt;
&lt;p&gt;Explicitly exporting types along with functions offers several advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clarity for Consumers: Exported types allow users to write precise type annotations that match your public API&lt;/li&gt;
&lt;li&gt;Avoids Global Namespace Pollution: Consumers import only what they need, keeping the global namespace clean&lt;/li&gt;
&lt;li&gt;Enhanced Tree Shaking: Modern bundlers can drop unused type-only imports when using the import type syntax&lt;/li&gt;
&lt;li&gt;Consistency: This approach aligns with the broader industry move towards explicit, module-based API definitions&lt;/li&gt;
&lt;li&gt;Circular Dependency Prevention: By clearly defining which types are exported, you reduce the risk of circular dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, rather than using a wildcard re-export for types:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Avoid: Not ideal for public libraries&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./types&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is preferable to use explicit type exports:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Order&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; OrderStatus &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./types&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Explicitly named re-exports remain the most recommended approach for public libraries in 2025. They provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Superior tree-shaking and bundle optimisation&lt;/li&gt;
&lt;li&gt;A straightforward, unambiguous public API that avoids naming collisions&lt;/li&gt;
&lt;li&gt;A smooth consumer experience with direct, idiomatic imports for both values and types&lt;/li&gt;
&lt;li&gt;Clear benefits in preventing circular dependency issues by enforcing a well-defined dependency structure&lt;/li&gt;
&lt;li&gt;Future-proof compatibility with modern TypeScript options such as verbatimModuleSyntax&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Organising your exports explicitly in each domain’s index file for a library with multiple domains, such as orders and users, ensures that your public API is robust, optimised, and easy to maintain as the ecosystem evolves.&lt;/p&gt;
&lt;p&gt;Hopefully, this guide helps you build more maintainable, optimised, and future-proof libraries.&lt;/p&gt;
</content:encoded></item><item><title>Choosing Your React Framework in 2025: Understanding Next.js Trade-offs</title><link>https://arrangeactassert.com/posts/nextjs-understanding-the-trade-offs/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/nextjs-understanding-the-trade-offs/</guid><pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I love Next.js. It’s been my framework of choice since my first tiny contribution in 2017.&lt;/p&gt;
&lt;p&gt;Yesterday, I joined a team discussion about which React framework to choose. In 2025, that decision is harder than ever, with so many excellent alternatives available.&lt;/p&gt;
&lt;p&gt;While Next.js is recommended by React themselves, and is a very popular choice, the not-so-good parts are often left out on platforms like LinkedIn and YouTube.&lt;/p&gt;
&lt;p&gt;I plan to write about the good things about Next.js 15 in the future, but here are some challenges I still face using it today.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;nextjs-15-and-react-server-components-rsc&quot;&gt;Next.js 15 and React Server Components (RSC)&lt;/h2&gt;
&lt;p&gt;It’s not just me who has doubts about (overhyped) React Server Components, which on paper look fantastic, however…&lt;/p&gt;
&lt;blockquote class= &quot;twitter-tweet&quot;&gt;&lt;p lang= &quot;en&quot; dir= &quot;ltr&quot;&gt;RSC is the most painful new React API in the State of React survey.&lt;br&gt;&lt;br&gt;Complaints: &lt;br&gt;- Hard to test.&lt;br&gt;- Hard to debug.&lt;br&gt;- Hard to reason about.&lt;br&gt;- Confusing mental model.&lt;br&gt;- Seems designed to sell Vercel.&lt;br&gt;- Some think only Next.js supports RSC.&lt;br&gt;- More complexity for little benefit. &lt;a href=&quot;https://t.co/HT5DzXlK3t&quot;&gt;pic.twitter.com/HT5DzXlK3t&lt;/a&gt;&lt;/p&gt;&amp;mdash; Cory House (@housecor) &lt;a href=&quot;https://twitter.com/housecor/status/1889683309707379027?ref_src=twsrc%5Etfw&quot;&gt;February 12, 2025&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;h2 id=&quot;middleware-issues&quot;&gt;Middleware Issues&lt;/h2&gt;
&lt;h3 id=&quot;edge-runtime-limitations&quot;&gt;Edge Runtime Limitations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restricted Node.js API usage:&lt;/strong&gt;&lt;br&gt;
The Next.js Edge Runtime explicitly excludes many native Node.js APIs (such as &lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;net&lt;/code&gt;, etc.), making tasks like direct database connections or session management impossible in middleware.&lt;br&gt;
&lt;em&gt;Verified by the official documentation:&lt;/em&gt;&lt;br&gt;
&lt;a href=&quot;https://vercel.com/docs/functions/edge-middleware/limitations&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vercel’s Edge Middleware Limitations&lt;/a&gt; and the &lt;a href=&quot;https://nextjs.org/docs/api-reference/edge-runtime&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js Edge Runtime API Reference&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication compatibility issues:&lt;/strong&gt;&lt;br&gt;
Third-party libraries that depend on Node.js APIs (for example, MongoDB drivers, Firebase Admin SDK, or Redis clients like ioredis) often face compatibility issues when used in middleware. Several GitHub discussions note struggles with using these libraries in the Edge Runtime.&lt;br&gt;
&lt;em&gt;For example, &lt;a href=&quot;https://github.com/vercel/next.js/discussions/66986&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;this GitHub discussion&lt;/a&gt; highlights user-reported issues regarding such limitations (the core restrictions are detailed in the official docs).&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Good news:&lt;/strong&gt; Node.js runtime support for middleware is merged! The &lt;a href=&quot;https://github.com/vercel/next.js/pull/75624&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PR #75624&lt;/a&gt; by the Next.js team enables middleware to run with full Node.js API support, addressing many of the current limitations. Broader discussions on this topic are tracked in &lt;a href=&quot;https://github.com/vercel/next.js/discussions/71727&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub Discussion #71727&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;single-middleware-file-restriction&quot;&gt;Single Middleware File Restriction&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single entry point:&lt;/strong&gt;&lt;br&gt;
Next.js supports only one middleware file (typically &lt;code&gt;middleware.ts&lt;/code&gt; or &lt;code&gt;middleware.js&lt;/code&gt; placed in the project root or within the &lt;code&gt;src&lt;/code&gt; directory). This forces developers to consolidate all middleware logic into one file. Although not exhaustively documented in a single article, this constraint is implicit in the &lt;a href=&quot;https://nextjs.org/docs/pages/building-your-application/routing/middleware&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;official Next.js Middleware docs&lt;/a&gt; and has been noted in various user reports. Having to use matches and then manually filter is a horrible developer experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;implementation-problems&quot;&gt;Implementation Problems&lt;/h2&gt;
&lt;h3 id=&quot;inconsistent-execution&quot;&gt;Inconsistent Execution&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Middleware Execution Issues:&lt;/strong&gt;&lt;br&gt;
In &lt;a href=&quot;https://github.com/vercel/next.js/issues/58025&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub Issue #58025&lt;/a&gt;, users reported that middleware sometimes doesn’t execute as expected in Next.js v14.2.4, occasionally requiring a hard refresh to function correctly. While this isn’t solely a file placement issue, it underscores the importance of proper middleware configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirect Behavior in Middleware:&lt;/strong&gt;&lt;br&gt;
&lt;a href=&quot;https://github.com/vercel/next.js/issues/59218&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub Issue #59218&lt;/a&gt; discusses problems with middleware redirects, where users experienced unexpected behaviour due to browser caching. This highlights the need for careful implementation and a thorough understanding of middleware behaviour.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;authentication-compatibility&quot;&gt;Authentication Compatibility&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Challenges with authentication libraries:&lt;/strong&gt;&lt;br&gt;
Libraries like NextAuth.js have noted issues when used in middleware—largely because the Edge Runtime lacks certain Node.js APIs (e.g., Node’s &lt;code&gt;crypto&lt;/code&gt; module) required by these libraries.&lt;br&gt;
&lt;em&gt;For more details, refer to the &lt;a href=&quot;https://nextjs.org/docs/api-reference/edge-runtime&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js Edge Runtime API Reference&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fetch-api-and-monkey-patching-issues&quot;&gt;Fetch API and Monkey Patching Issues&lt;/h2&gt;
&lt;h3 id=&quot;global-fetch-modifications&quot;&gt;Global Fetch Modifications&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Next.js extends the Web &lt;code&gt;fetch&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
Next.js extends the standard Web &lt;code&gt;fetch()&lt;/code&gt; API to allow each server-side request to set its persistent caching and revalidation semantics. More details are provided in the &lt;a href=&quot;https://nextjs.org/docs/app/api-reference/functions/fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js fetch documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Memory leaks and compatibility issues:&lt;/strong&gt;&lt;br&gt;
Modifications to the global &lt;code&gt;fetch&lt;/code&gt; (supporting features like caching and Server Actions) have sometimes led to memory leaks.&lt;br&gt;
&lt;em&gt;A documented example is available in &lt;a href=&quot;https://github.com/vercel/next.js/issues/64212&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub Issue #64212&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interference with error handling and third-party libraries:&lt;/strong&gt;&lt;br&gt;
Monkey-patching &lt;code&gt;fetch&lt;/code&gt; can conflict with libraries that rely on or modify it. For example, discussions on Reddit highlight how such modifications may disrupt expected error handling.&lt;br&gt;
&lt;a href=&quot;https://www.reddit.com/r/nextjs/comments/1cajrcc/how_do_i_monkeypatch_fetch/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;See this Reddit thread on monkey-patching fetch&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;msw-integration-challenges&quot;&gt;MSW Integration Challenges&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server-side interception issues:&lt;/strong&gt;&lt;br&gt;
Many developers have reported challenges with server-side request interception when integrating Mock Service Worker (MSW) with the new App Router in Next.js 13+. These issues are likely due to the restricted Edge Runtime, which lacks Node.js APIs (such as the &lt;code&gt;http&lt;/code&gt;/&lt;code&gt;https&lt;/code&gt; modules) required for full HTTP interception.&lt;br&gt;
&lt;a href=&quot;https://mswjs.io/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Learn more about MSW on their official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;no-platform-adapter-unlike-remix-svelte-and-astro&quot;&gt;No Platform Adapter (Unlike Remix, Svelte, and Astro)&lt;/h2&gt;
&lt;p&gt;There is an initiative called &lt;a href=&quot;https://opennext.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;OpenNext&lt;/a&gt;, but it appears to be playing catchup. Vercel remains the best platform to host Next.js, so having adapters for other platforms might introduce conflicts of interest.&lt;/p&gt;
&lt;h2 id=&quot;backward-compatibility-bloat&quot;&gt;Backward Compatibility Bloat&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Legacy systems maintained alongside new features:&lt;/strong&gt;&lt;br&gt;
Next.js continues to support legacy systems (e.g., the Pages Router and Babel) even as it introduces new paradigms like the App Router. This coexistence increases overall complexity.&lt;br&gt;
&lt;a href=&quot;https://nextjs.org/docs/basic-features/pages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Official Next.js Pages Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SWC vs. Babel compatibility:&lt;/strong&gt;&lt;br&gt;
Although Next.js introduced the SWC compiler for performance improvements, Babel compatibility is still maintained—which adds to the bloat.&lt;br&gt;
&lt;a href=&quot;https://nextjs.org/blog/next-12#swc&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js 12 Blog on SWC&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;modern-alternatives&quot;&gt;Modern Alternatives&lt;/h2&gt;
&lt;h3 id=&quot;astro-for-static-sites&quot;&gt;Astro for Static Sites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance benefits:&lt;/strong&gt;&lt;br&gt;
Astro claims to load static content up to 40% faster and deliver 90% less JavaScript than Next.js, making it an attractive option for content-heavy sites.&lt;br&gt;
&lt;a href=&quot;https://astro.build/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Learn more about Astro&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tanstack-router-for-spas&quot;&gt;TanStack Router for SPAs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Superior type safety and flexibility:&lt;/strong&gt;&lt;br&gt;
TanStack Router offers excellent type safety and flexible routing patterns, and being client-side first means you can sprinkle in server actions with server validation when needed.&lt;/p&gt;
&lt;p&gt;Bonus: it uses lightning-quick &lt;a href=&quot;https://nitro.build/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nitro&lt;/a&gt; and &lt;a href=&quot;https://vite.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vite&lt;/a&gt; to bundle and deploy your application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://tanstack.com/router/latest/docs/framework/react/comparison&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TanStack Framework Comparison&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;remixreact-router-7&quot;&gt;Remix/React Router 7/?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Should have been number one to me:&lt;/strong&gt;&lt;br&gt;
Backed by Shopify, with Ryan and Michael leading the way, this would have been my top choice a year ago. I love everything about their approach, from open planning sessions to clear community communication and a commitment to web standards.&lt;/p&gt;
&lt;p&gt;However, &lt;a href=&quot;https://remix.run/blog/merging-remix-and-react-router&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;the merging of Remix and React Router&lt;/a&gt; is a bit confusing at best. During this transition period, it’s a tough sell to recommend it to clients. Hopefully, when things stabilize and we have a clearer picture of what’s what it will be worth another look.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;development-experience-issues&quot;&gt;Development Experience Issues&lt;/h2&gt;
&lt;h3 id=&quot;caching-complexities&quot;&gt;Caching Complexities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inconsistent caching behavior:&lt;/strong&gt;&lt;br&gt;
Next.js 14’s aggressive caching sometimes led to stale data. Although Next.js 15 disabled caching by default to address these complaints, new issues have emerged in some cases.&lt;br&gt;
&lt;a href=&quot;https://github.com/vercel/next.js/discussions&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;See community threads on GitHub discussions&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;architectural-challenges&quot;&gt;Architectural Challenges&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hydration mismatches in Server Components:&lt;/strong&gt;&lt;br&gt;
Blending server and client components can lead to hydration mismatches that are challenging to debug.&lt;br&gt;
&lt;a href=&quot;https://nextjs.org/docs/app/building-your-application/rendering/server-components&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js Server Components Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mandatory file-based routing quirks:&lt;/strong&gt;&lt;br&gt;
The requirement that each page have a &lt;code&gt;page.tsx&lt;/code&gt; file can be confusing and may lead to accidental bundling of server-only code into client bundles.&lt;br&gt;
&lt;a href=&quot;https://nextjs.org/docs/basic-features/pages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Official Next.js Pages Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;upgrades-and-dependency-issues&quot;&gt;Upgrades and Dependency Issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dependency conflicts during upgrades:&lt;/strong&gt;&lt;br&gt;
Some users have experienced issues when migrating between major versions (e.g., from Next.js 14 to 15), especially as many libraries are still catching up with changes introduced in React 19. In some cases, developers have resorted to workarounds like running &lt;code&gt;npm install --legacy-peer-deps&lt;/code&gt; to bypass strict peer dependency checks.&lt;br&gt;
&lt;a href=&quot;https://github.com/shadcn-ui/ui/issues/6585&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;See discussion on this workaround in the shadcn/ui repository&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite these challenges, Next.js remains a powerful and flexible framework that continues to evolve.&lt;/p&gt;
&lt;p&gt;It will improve, and hopefully, one can be seamlessly deployed on many platforms, not just Vercel.&lt;/p&gt;
&lt;p&gt;With a huge ecosystem, it’s still my go-to framework.&lt;/p&gt;
&lt;p&gt;However, modern alternatives like Astro and TanStack Router may offer more focused solutions for developers who find these pain points too limiting.&lt;/p&gt;
&lt;p&gt;Ultimately, the right tool depends on your specific use case and priorities.&lt;/p&gt;
</content:encoded></item><item><title>Tracking Every Decision in Payments: The Context Pattern Approach</title><link>https://arrangeactassert.com/posts/tracking-every-decision-in-payments/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/tracking-every-decision-in-payments/</guid><pubDate>Fri, 31 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Designing a payment system is like any other software solution I’ve worked on.
At first, it appears straightforward, but real-world factors like currency conversions, fees, payee validations and external APIs quickly add complexity.&lt;/p&gt;
&lt;p&gt;When something goes wrong, you need to know exactly which step failed and why.&lt;/p&gt;
&lt;p&gt;In this post, I’ll explain how the Context Pattern helps solve this by storing all important data in a single object.&lt;/p&gt;
&lt;p&gt;Each function returns new information rather than silently modifying the shared state, and the caller explicitly updates the context. This ensures clear data flow, easy debugging and a more maintainable system.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fragmented Logging&lt;/strong&gt;: Logs end up scattered across multiple functions or services, making it difficult to reconstruct a single payment from start to finish.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ambiguous State Changes&lt;/strong&gt;: Without a single data store, you end up with countless parameters or rely on global variables—leading to confusion over which function changed what data and why.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hard to Add Features&lt;/strong&gt;: Introducing new requirements like compliance checks or multi-tier fees means revisiting multiple function calls and logs, increasing the chances of errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Limited Error Context&lt;/strong&gt;: If a step fails, you might only see partial details. Recreating an issue becomes guesswork without a full view of the payment data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;a-real-world-scenario-without-the-context-pattern&quot;&gt;A Real-World Scenario Without the Context Pattern&lt;/h2&gt;
&lt;p&gt;Below is an example of a typical payment flow that returns values from functions, but lacks a single, shared data structure and a proper correlation ID:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// (A) Fetch a conversion rate&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getConversionRate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  clientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sourceCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  targetCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Fetching rate for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sourceCurrency&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;targetCurrency&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Mocked response&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Retrieved rate: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;rate&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; rate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// (B) Process the payment&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  clientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  conversionRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; transactionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Processing payment of &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;amount&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; at rate &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;conversionRate&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Invalid amount: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;amount&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. Cannot process payment.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transactionId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tx-999&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Payment processed with transaction ID &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;transactionId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SUCCESS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transactionId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// (C) Main flow that orchestrates both steps&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mainPaymentFlow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  clientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sourceCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  targetCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getConversionRate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      clientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      sourceCurrency&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      targetCurrency
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paymentResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;clientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Flow complete. Result:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paymentResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clientId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;] Payment flow error:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Simulate usage&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mainPaymentFlow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;client-123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GBP&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;USD&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;whats-lacking-here&quot;&gt;What’s lacking here?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No Single Source of Truth&lt;/strong&gt;: Data is scattered and only passed around ad hoc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weak Correlation&lt;/strong&gt;: &lt;code&gt;clientId&lt;/code&gt; is a shared identifier, but logs can become tangled if multiple payments happen simultaneously for the same client.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Harder to Extend&lt;/strong&gt;: Adding extra steps requires new return values or extra parameters everywhere.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-context-pattern&quot;&gt;The Context Pattern&lt;/h2&gt;
&lt;p&gt;The Context Pattern centres on a &lt;strong&gt;single object&lt;/strong&gt; (the context) that holds all important data throughout the payment lifecycle. Each helper function returns the data it computes, and the &lt;em&gt;caller&lt;/em&gt; decides how to update the context. No mysterious global changes exist, and each log can attach a unique &lt;code&gt;spanId&lt;/code&gt; (or similar).&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
 subgraph Context Flow
 Start([Payment Start]) --&amp;gt; Context[Create Context\nspanId, currencies, amount]
 Context --&amp;gt; Rate[Get Rate\nReturns rate]
 Rate --&amp;gt; Fees[Calculate Fees\nReturns fee structure]
 Fees --&amp;gt; Validate[Validate\nReturns validation result]
 Validate --&amp;gt; Process[Process Payment\nReturns result]
 Process --&amp;gt; Store[(Store Context)]
 end

 subgraph Error Handling
 Rate -- Error --&amp;gt; ErrorLog[Log Error + Full Context]
 Fees -- Error --&amp;gt; ErrorLog
 Validate -- Error --&amp;gt; ErrorLog
 Process -- Error --&amp;gt; ErrorLog
 end
&lt;/pre&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Base logger for the application&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; baseLogger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; level&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;info&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Payment result type&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt;&lt;/span&gt; PaymentResult &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  transactionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The context that holds all relevant fields in one place&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentContext&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  sourceCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  targetCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  conversionRate&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  paymentResult&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentResult&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Fetch a conversion rate&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getConversionRate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; baseLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spanId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;getConversionRate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;Amount must be greater than zero before fetching a conversion rate.&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Fetching rate for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sourceCurrency&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;targetCurrency&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockRate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; mockRate &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Conversion rate retrieved.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mockRate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Process the payment&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;PaymentResult&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; baseLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spanId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;processPayment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Processing payment of &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sourceCurrency&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Invalid amount: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. Cannot process payment.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SUCCESS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transactionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tx-999&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; result &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Payment processed.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Main flow uses a single context&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paymentContext&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;unique-trace-id-123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    sourceCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GBP&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    targetCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;USD&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 1. Retrieve conversion rate&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getConversionRate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    paymentContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;conversionRate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 2. Process payment&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; paymentRes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processPayment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    paymentContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paymentResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; paymentRes&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    baseLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; paymentContext &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Payment flow completed successfully.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Log both the error and context for better debugging&lt;/span&gt;
    baseLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; paymentContext &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;Payment flow encountered an error.&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;advanced-features&quot;&gt;Advanced Features&lt;/h2&gt;
&lt;h3 id=&quot;fee-calculation-and-rounding&quot;&gt;Fee Calculation and Rounding&lt;/h3&gt;
&lt;p&gt;In the real world, payment flows often need multiple fees that must be rounded precisely. You might add a fees field to your context:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentFees&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  base&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  foreign&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  total&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PaymentContext&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  fees&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentFees&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateFees&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;PaymentFees&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; baseFee &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; foreignFee &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sourceCurrency &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;targetCurrency
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;amount &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.005&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; totalFee &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; baseFee &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; foreignFee&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; base&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; baseFee&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; foreign&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; foreignFee&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; total&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; totalFee &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You would then do:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fees &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateFees&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;multi-step-validations&quot;&gt;Multi-step Validations&lt;/h3&gt;
&lt;p&gt;If you have a compliance check or KYC rule, you can create a function that takes context and returns a result (or throws an error), so all data flows through the same pattern.&lt;/p&gt;
&lt;h2 id=&quot;testing-and-persistence&quot;&gt;Testing and Persistence&lt;/h2&gt;
&lt;h3 id=&quot;unit-testing-with-mocks&quot;&gt;Unit Testing with Mocks&lt;/h3&gt;
&lt;p&gt;Because each function returns data, testing them in isolation is simple. For example:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;calculateFees&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;calculates foreign fees correctly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      sourceCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GBP&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      targetCurrency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;USD&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fees &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateFees&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fees&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 2 base + 1 foreign, as an example&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;long-running-transactions&quot;&gt;Long-Running Transactions&lt;/h3&gt;
&lt;p&gt;If your process is asynchronous or spans multiple stages, you can save the context into a database at certain checkpoints:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkpointContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; prisma&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;paymentFlow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;upsert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    where&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spanId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    update&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lastUpdated&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    create&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      spanId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spanId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;IN_PROGRESS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows you to resume or replay from that checkpoint if a later step fails.&lt;/p&gt;
&lt;h2 id=&quot;migrating-existing-code&quot;&gt;Migrating Existing Code&lt;/h2&gt;
&lt;p&gt;A common question is how to refactor older, scattered logic into this pattern. The most straightforward approach is usually incremental:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; data-language=&quot;typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Old approach&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;oldProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... scattered logic and partial logs&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// New approach using context&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;newProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PaymentContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... shared context with proper logs&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might begin by creating a PaymentContext and gradually modifying existing functions to accept context rather than many parameters. Log calls can be redirected through a child logger with spanId.&lt;/p&gt;
&lt;p&gt;Over time, you reduce global variables or repeated parameters and end up with a single context that you can checkpoint, log and debug in one place.&lt;/p&gt;
&lt;h2 id=&quot;real-world-pitfalls&quot;&gt;Real-World Pitfalls&lt;/h2&gt;
&lt;h3 id=&quot;context-object-size&quot;&gt;Context Object Size&lt;/h3&gt;
&lt;p&gt;Keep an eye on how large your context becomes. Use references or IDs if you only need to load extra data on demand. Redundant or overly large fields can affect performance.&lt;/p&gt;
&lt;h3 id=&quot;long-running-flows&quot;&gt;Long-running Flows&lt;/h3&gt;
&lt;p&gt;Store partial context at each step if the transaction is split into multiple asynchronous stages. Use an event-driven architecture with an ID that references a stored context in Redis or a database.&lt;/p&gt;
&lt;h3 id=&quot;clearing-sensitive-data&quot;&gt;Clearing Sensitive Data&lt;/h3&gt;
&lt;p&gt;Some fields (like card numbers or personal info) must not remain in logs. Use redaction features (for example, in Pino) or remove those fields from the context once you no longer need them.&lt;/p&gt;
&lt;h2 id=&quot;comparison-with-other-patterns&quot;&gt;Comparison with Other Patterns&lt;/h2&gt;
&lt;h3 id=&quot;command-pattern&quot;&gt;Command Pattern&lt;/h3&gt;
&lt;p&gt;Ideal if you want each action to be a discrete command object. It can be more complex than a simple context approach and is not always necessary if you just need straightforward flows.&lt;/p&gt;
&lt;h3 id=&quot;event-sourcing&quot;&gt;Event Sourcing&lt;/h3&gt;
&lt;p&gt;Allows you to replay state changes by storing events. It is powerful for auditing but requires a more elaborate design. The Context Pattern is typically more straightforward for most small to medium payment systems.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using a context object, passing it through each stage of your payment flow and returning computed values lets you build a highly transparent, adaptable system.&lt;/p&gt;
&lt;p&gt;If an error occurs, you can log the entire context, making it far easier to diagnose issues later. This pattern also scales well when you need to introduce fees, compliance checks or multi-step validations since each new function simply takes and returns context-related data.&lt;/p&gt;
&lt;p&gt;Whether you stay with the Context Pattern or eventually transition to something like Event Sourcing, you’ll find that starting with a single shared context and a correlation ID ensures your payment code remains both maintainable and easy to evolve.&lt;/p&gt;
</content:encoded></item><item><title>Chasing the AI God: Why We Worship Every New Model</title><link>https://arrangeactassert.com/posts/chasing-the-ai-god/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/chasing-the-ai-god/</guid><pubDate>Wed, 29 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;It’s like a new diet pill has hit the market, promising instant weight loss with no effort, and now everyone’s scrambling to get their hands on it because it’s all over their TikTok.&lt;/p&gt;
&lt;p&gt;Some folks are talking about DeepSeek as if it’s the second coming of AI.&lt;/p&gt;
&lt;p&gt;The clamour might be because it’s the first serious open non-US model with reasoning capabilities from China.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Chasing the AI God&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/chasing-the-ai-god.CuN0npDi_IvkOg.webp&quot; srcset=&quot;/_astro/chasing-the-ai-god.CuN0npDi_qkgLY.webp 640w, /_astro/chasing-the-ai-god.CuN0npDi_ZeWx6Y.webp 750w, /_astro/chasing-the-ai-god.CuN0npDi_1QFDb9.webp 828w, /_astro/chasing-the-ai-god.CuN0npDi_IvkOg.webp 1024w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Most people are confused about which version of DeepSeek they’re using.&lt;/p&gt;
&lt;p&gt;Most providers offer a distilled, watered-down version that’ll run anywhere, so you’re not getting the actual full fat version people are talking as to really see its magic, you’d need a small fortune in computing power.&lt;/p&gt;
&lt;p&gt;It’s like being promised a rare vintage white wine, only to find the bottle filled with slightly grape-scented water. Same brand, same label, but all the depth and character stripped away, leaving you with a hollow imitation.&lt;/p&gt;
&lt;p&gt;The hype suggests it can keep pace with anything OpenAI does, which might sound thrilling if you’re already tired of whatever ChatGPT or its siblings spit out.&lt;/p&gt;
&lt;p&gt;But here’s where the alarm bells should start ringing.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;We have a strange habit of treating new tech like a shiny toy that must be perfect simply because it’s the latest in line. It’s easy to forget that these models are about as trustworthy as me telling you I won’t pinch your biscuit when you’ve nipped out to the loo.&lt;/p&gt;
&lt;p&gt;They make mistakes, they have biases, and they hallucinate with total confidence.&lt;/p&gt;
&lt;p&gt;I predict we’re heading for trouble as people want to believe everything AI generates simply because it’s quick. In a society of short attention spans, it gives people the instant gratification they seek, and there’s no time or desire to question it.&lt;/p&gt;
&lt;p&gt;Picture this scenario: some fringe political group with more money than sense decides to release an AI that’s even easier to use, has no guardrails, and promises unlimited answers in the blink of an eye.&lt;/p&gt;
&lt;p&gt;They hardly restrict it, so you can ask for all the edgy stuff you want without any pesky guidelines. The risk is that people flock to it and gobble up whatever it says just because it’s convenient, fast, and free.&lt;/p&gt;
&lt;p&gt;A few million retweets later, you’ve got a swirling vortex of misinformation.&lt;/p&gt;
&lt;p&gt;This isn’t some wild conspiracy theory. We already live in an age where people retreat into echo chambers that echo back at them. Throw an unregulated AI into the mix, and you’ve effectively given a free megaphone to anyone who can afford it. Forget about analysing sources or thinking things through. We just want immediate answers that confirm what we already believe.&lt;/p&gt;
&lt;p&gt;So yes, DeepSeek and the models that will follow are impressive, and they might do a decent job as long as you keep your wits about you and treat them like any other tool. They’re not wise old sages, nor are they perfect oracles.&lt;/p&gt;
&lt;p&gt;The moment we start worshipping them as flawless fountains of truth is the moment we open the door to a future where the biggest loudmouth with the most populist AI wins.&lt;/p&gt;
&lt;p&gt;Oh, and about the privacy of the personal information and company intellectual property you’re feeding it…&lt;/p&gt;
</content:encoded></item><item><title>Lessons from Building AI Products with Stakeholders</title><link>https://arrangeactassert.com/posts/working-with-ai-product-stakeholders/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/working-with-ai-product-stakeholders/</guid><pubDate>Mon, 27 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Building AI products with stakeholders requires a fundamentally different approach than traditional software development.&lt;/p&gt;
&lt;p&gt;From my experience working with AI, success depends not only on technical implementation but also on bridging the gap between AI capabilities and stakeholder expectations.&lt;/p&gt;
&lt;p&gt;In this post, I’ll share lessons from guiding stakeholders through AI’s possibilities and limitations.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;teaching-stakeholders-about-the-inner-workings-of-ai&quot;&gt;Teaching Stakeholders About the Inner Workings of AI&lt;/h2&gt;
&lt;p&gt;One of the first things I realised when working with AI is how many misconceptions stakeholders have about how it works, what’s possible, and how to maintain AI features.&lt;/p&gt;
&lt;p&gt;Many expect AI models will behave like deterministic tools they’ve used in the past. These misunderstandings often stem from what stakeholders have seen rather than experienced. Industry hype and “demoware” contribute to unrealistic expectations about how easily AI can deliver the results they want.&lt;/p&gt;
&lt;p&gt;For example, stakeholders often ask why OpenAI API results differ from their ChatGPT experience. Addressing these questions early is critical for building trust and setting realistic expectations.&lt;/p&gt;
&lt;p&gt;Explaining how AI generates results helps stakeholders understand its capabilities and limitations. This lays the foundation for collaboration and ensures stakeholders feel involved in shaping the outcomes.&lt;/p&gt;
&lt;h2 id=&quot;starting-with-the-openai-playground&quot;&gt;Starting with the OpenAI Playground&lt;/h2&gt;
&lt;p&gt;Stakeholders need an interactive way to experiment with AI.&lt;/p&gt;
&lt;p&gt;The OpenAI Playground is an excellent starting point. It allows users to test prompts, adjust parameters, and see results immediately.&lt;/p&gt;
&lt;p&gt;This hands-on experience helps stakeholders understand how generative AI works and how changing inputs can influence outputs. For many, it’s their first experience seeing beyond simply entering text into a chat interface.&lt;/p&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;https://arrangeactassert.com/static/images/open-ai-playground.png&quot;
    alt=&quot;The OpenAI Playground provides an interactive environment where stakeholders can experiment with prompts and settings to understand how generative AI works.&quot;
  /&gt;
  &lt;figcaption&gt;
    The OpenAI Playground is an intuitive tool for stakeholders to test prompts, tweak settings, and explore how generative AI works.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The OpenAI Playground also offers built-in collaboration features, making it easy for teams to tweak settings like temperature and learn through trial and error. Its clean, intuitive interface ensures users can get results quickly without being overwhelmed by complexity.&lt;/p&gt;
&lt;h2 id=&quot;educating-stakeholders-using-their-data&quot;&gt;Educating Stakeholders Using Their Data&lt;/h2&gt;
&lt;p&gt;While the OpenAI Playground is a fantastic starting point, I needed to retrieve data from our database and support experimentation with non-OpenAI models. Using personalised data provides a sharper focus on the goals stakeholders want to achieve.&lt;/p&gt;
&lt;p&gt;With my full-stack experience, I built a secure web app that integrated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Database connectivity&lt;/strong&gt; for real-world scenarios using client data (e.g., databases, APIs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support for multiple providers&lt;/strong&gt;, allowing comparisons between OpenAI and non-OpenAI models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time metrics&lt;/strong&gt;, such as token usage, generation time, and associated costs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This customisation streamlined collaboration with stakeholders, allowing them to experiment directly, compare results, and explore what worked best. It turned abstract technical concepts into practical, measurable outcomes, improving alignment and creating a shared learning experience.&lt;/p&gt;
&lt;p&gt;After stakeholders understand how their data can integrate with AI systems, the next step is determining which AI approaches best align with their goals.&lt;/p&gt;
&lt;h2 id=&quot;helping-stakeholders-choose-the-right-ai-approach&quot;&gt;Helping Stakeholders Choose the Right AI Approach&lt;/h2&gt;
&lt;p&gt;There’s no one-size-fits-all approach when building AI products.&lt;/p&gt;
&lt;p&gt;Stakeholders often assume advanced techniques, like fine-tuning, are essential for success. As a consultant, I recommend beginning with straightforward methods that deliver results quickly using fewer resources and at less expense.&lt;/p&gt;
&lt;p&gt;For example, few-shot prompting can be a practical alternative or a precursor to fine-tuning. By providing a few well-crafted examples, the AI can adapt its outputs to meet specific requirements, often achieving the desired results without the need for the added complexity of fine-tuning.&lt;/p&gt;
&lt;p&gt;That’s not to say fine-tuning is never needed, but taking an incremental approach ensures that solutions are evaluated step by step, with short feedback loops to assess their value, keeping progress aligned with stakeholder goals.&lt;/p&gt;
&lt;p&gt;Once stakeholders understand how their data integrates with AI tools and the right approaches to achieve their goals, the next step is to explore trade-offs and implications through experimentation.&lt;/p&gt;
&lt;h2 id=&quot;understanding-trade-offs-through-experimentation&quot;&gt;Understanding Trade-offs Through Experimentation&lt;/h2&gt;
&lt;p&gt;Educating stakeholders about the practical implications of AI is essential. This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The time required&lt;/strong&gt; to generate results with different models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token usage&lt;/strong&gt;: What tokens are, why they matter, and how they affect costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameter choices&lt;/strong&gt;: How settings like temperature influence cost, consistency, and output quality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guardrails and patterns&lt;/strong&gt;: Techniques like LLM-as-a-Judge, where a secondary model evaluates and refines outputs, are critical for maintaining accuracy and reliability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Through experimentation, stakeholders can observe these trade-offs firsthand. For instance, they can see how increasing temperature settings results in more creative but less consistent outputs, or how longer prompts affect processing time and cost.&lt;/p&gt;
&lt;p&gt;These insights enable stakeholders to make data-driven decisions that align with their goals and constraints, ensuring AI solutions are practical, cost-effective, and aligned with their needs.&lt;/p&gt;
&lt;h2 id=&quot;how-to-work-with-stakeholders-when-building-ai-products&quot;&gt;How to Work with Stakeholders When Building AI Products&lt;/h2&gt;
&lt;p&gt;Effective collaboration with stakeholders requires more than just technical expertise. It’s about creating an environment where stakeholders feel empowered to explore, learn, and contribute meaningfully.&lt;/p&gt;
&lt;p&gt;Here’s what I’ve found works best:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Start with Accessible Tools&lt;/strong&gt;: Use tools like the OpenAI Playground to introduce generative AI concepts in an approachable way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus on Education&lt;/strong&gt;: Explain key concepts, such as temperature, token limits, and costs, in simple terms. Use examples to make abstract ideas concrete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaborate Transparently&lt;/strong&gt;: Provide tools that make the decision-making process measurable and clear. Transparency builds trust and fosters alignment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapt to Their Needs&lt;/strong&gt;: Tailor your approach to stakeholder priorities, whether they focus on cost, speed, or quality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experiment&lt;/strong&gt;: Start with small, low-risk tests to gather insights. Scale up once you’ve identified what works best.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use the Best Tools for Their Context&lt;/strong&gt;: Help stakeholders identify the tools and techniques (e.g., fine-tuning, few-shot prompting) that align with their specific goals and constraints, avoiding unnecessary complexity.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By following these steps and fostering collaboration, transparency, and experimentation, you can empower stakeholders to navigate AI’s opportunities and challenges with confidence.&lt;/p&gt;
&lt;p&gt;This approach leads to more informed decisions, and with stakeholder engagement, you can deliver outcomes that align with their goals.&lt;/p&gt;
</content:encoded></item><item><title>Whose Responsibility Is It Anyway? Defining Boundaries with Event-Driven Architecture</title><link>https://arrangeactassert.com/posts/defining-boundaries-with-event-driven-architecture/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/defining-boundaries-with-event-driven-architecture/</guid><pubDate>Mon, 20 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Defining clear boundaries is essential to building clean, scalable, and reliable architectures.&lt;/p&gt;
&lt;p&gt;In my experience, organisational demands often override the focus on boundaries and domain-driven design. This reflects the tension between following technical best practices and delivering business outcomes quickly. While theoretical approaches are widely discussed at conferences, in books, and in videos, the practical implementation of these ideas is often shaped by cultural dynamics, resource constraints, tight deadlines, and internal politics.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explore the challenges of maintaining boundaries and potential solutions, using a payment system as an example. This system facilitates transactions between clients and payment providers, such as PayPal or Stripe, highlighting the distribution of responsibilities within its architecture.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-stateless-systems-are-key-to-loosely-coupled-architecture&quot;&gt;Why Stateless Systems Are Key to Loosely Coupled Architecture&lt;/h2&gt;
&lt;p&gt;Stateless systems are a ket component of loosely coupled architecture. By avoiding unnecessary state storage, they offer several compelling benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Focus on Core Functions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stateless systems adhere to the single responsibility principle, keeping them focused on their primary task.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scale More Easily&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With minimal state to track, these systems can handle higher loads without significant overhead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Simplify Communication&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stateless systems exchange lightweight messages, often limited to essential identifiers like IDs, reducing complexity and ensuring efficient communication.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Take, for example, a payment system that links a client’s payee ID to a payment provider’s ID. This design avoids storing additional details, such as contact information, delegating that responsibility to the client. The client’s database becomes the single source of truth, ensuring a cleaner and more reliable architecture.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart LR
    Client[Client System] --&amp;gt;|Payee ID| Payments[Payments System]
    Payments --&amp;gt;|Provider ID| Provider[Payment Provider]
&lt;/pre&gt;
&lt;p&gt;However, in my experience problems emerge when teams request the systems to take on responsibilities beyond its intended scope.&lt;/p&gt;
&lt;p&gt;For instance, they might ask it to send emails to payees whenever details are updated. Although seemingly convenient, this approach can lead to significant architectural pitfalls.&lt;/p&gt;
&lt;h2 id=&quot;why-adding-contact-details-is-a-bad-idea&quot;&gt;Why Adding Contact Details is a Bad Idea&lt;/h2&gt;
&lt;p&gt;Allowing the payment system to store and manage contact information may seem harmless at first, but in my experience the convenience opens a Pandora’s box and leads to significant problems later down the line:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Duplication of Data&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Contact details must be synchronised between the client’s database and the payment system. This increases the risk of discrepancies and data conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increased Complexity&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The payment system would require additional mechanisms to manage updates, validate data, and resolve conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Misaligned Responsibilities&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Payment systems should focus on processing transactions, not managing user contact details. Expanding their role leads to bloated, harder-to-maintain codebases.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Messaging Failures&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Another challenge arises when considering failures. What happens if the payment system tries to send an email and it fails? Should it handle retries, or should this responsibility lie elsewhere? Adding retry logic and failure handling shifts the focus of the payment system away from its core role of facilitating transactions. This responsibility is better suited to the client, who already has the necessary data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s what happens when responsibilities blur:&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;flowchart TD
    subgraph &quot;Problem: Duplicated Responsibilities&quot;
        A[Client Database] -- Updates --&amp;gt; B[Payments System]
        B -- Sends Emails --&amp;gt; C[Payee]
        C -- Updates --&amp;gt; A
        B -- Retry Loop --&amp;gt; C
    end
&lt;/pre&gt;
&lt;p&gt;To address these challenges and maintain clear boundaries, event-driven architecture offers an effective solution.&lt;/p&gt;
&lt;h2 id=&quot;event-driven-architecture-a-scalable-solution&quot;&gt;Event-Driven Architecture: A Scalable Solution&lt;/h2&gt;
&lt;p&gt;Event-driven architecture offers a clean, scalable solution for maintaining clear system boundaries while enabling flexible workflows.&lt;/p&gt;
&lt;h3 id=&quot;the-problem-overlapping-responsibilities&quot;&gt;The Problem: Overlapping Responsibilities&lt;/h3&gt;
&lt;p&gt;When systems take on responsibilities outside their intended scope, complexity and duplication increase, leading to maintenance challenges and inefficiencies.&lt;/p&gt;
&lt;p&gt;For instance, if the payment system manages both transactions and user contact information or handles email notifications, it blurs boundaries and introduces unnecessary coupling.&lt;/p&gt;
&lt;h3 id=&quot;the-solution-clear-boundaries-with-events&quot;&gt;The Solution: Clear Boundaries with Events&lt;/h3&gt;
&lt;p&gt;Event-driven architecture resolves this by enabling systems to remain focused on their core responsibilities while collaborating seamlessly through events.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Raise Events&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The payment system publishes events like &lt;code&gt;payee.updated&lt;/code&gt; or &lt;code&gt;payment.successful&lt;/code&gt; when specific actions occur, passing only essential identifiers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clients Handle Events&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The client system listens for these events, processes them, and performs actions like updating records or sending emails.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Handle Failures Gracefully&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By delegating retry logic and error handling to the client system, failures in operations like email delivery are isolated from the payment system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-it-works-in-practice&quot;&gt;How It Works in Practice&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Payee Updates Details&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A payee updates their information with a payment provider.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Payment System Emits an Event&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The system raises a &lt;code&gt;payee.updated&lt;/code&gt; event containing only the relevant IDs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Client Listens and Processes&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The client system receives the event, updates its database, and triggers any necessary workflows, such as emailing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retry Logic&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If an email fails to send, the client system handles retries without impacting the performance of the payment system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;sequenceDiagram
participant P as Payment Provider
participant PS as Payments System
participant C as Client System
participant E as Email Service

    P-&amp;gt;&amp;gt;PS: Payment status update
    PS-&amp;gt;&amp;gt;C: Emit payee.updated event
    Note over PS: Only passes IDs
    C-&amp;gt;&amp;gt;C: Process event
    C-&amp;gt;&amp;gt;E: Handle email (with retries)
    Note over C: Manages all contact details&amp;lt;br/&amp;gt;and messaging logic
&lt;/pre&gt;
&lt;h2 id=&quot;benefits-of-event-driven-architecture&quot;&gt;Benefits of Event-Driven Architecture&lt;/h2&gt;
&lt;p&gt;This approach provides long-term benefits for scalability, maintainability, and system integrity.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;br&gt;
Systems with focused responsibilities are easier to manage, test, and extend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;br&gt;
Decoupled systems can scale independently, reducing bottlenecks and enhancing performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Integrity&lt;/strong&gt;&lt;br&gt;
By avoiding data duplication, systems ensure consistency and reduce the risk of conflicts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Customisation&lt;/strong&gt;&lt;br&gt;
Client systems can handle domain-specific logic like email templates, personalisation, and language localisation without impacting the payment system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This architecture ensures robust error handling, clean system boundaries, and a flexible foundation for future enhancements.&lt;/p&gt;
&lt;h2 id=&quot;handling-email-templates-languages-and-personalisation&quot;&gt;Handling Email Templates, Languages, and Personalisation&lt;/h2&gt;
&lt;p&gt;Beyond architectural benefits, event-driven systems also enable domain specific customisation, particularly for tasks like email notifications and user personalisation.&lt;/p&gt;
&lt;p&gt;A client system handling email notifications has the added benefit of full control over:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Email Templates&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Templates can be customised for different use cases, such as notifications, reminders, or promotions. This flexibility ensures that emails align with the client’s branding and messaging strategy.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Language Localisation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The client system can dynamically select the appropriate language for each payee, ensuring clear communication regardless of their preferred language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Personalisation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Personalised content (e.g., using the payee’s name, specific account details, or tailored offers) can be included without requiring the payment system to store sensitive data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By delegating this responsibility to the client, the system provides a better user experience while preserving clear boundaries and minimising complexity.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Clear boundaries between systems are essential for building scalable and maintainable architectures. Systems with focused responsibilities are easier to manage, test, and extend, while decoupled designs scale more effectively as each system evolves independently. Minimising duplication ensures consistency, avoids data conflicts, and reinforces the integrity of the overall system.&lt;/p&gt;
&lt;p&gt;System design often requires balancing user demands with architectural constraints.&lt;/p&gt;
&lt;p&gt;Event-driven architecture offers a powerful way to maintain these clear boundaries while addressing complex requirements. By adopting this approach, each system can focus on its core responsibilities, promoting flexibility, scalability, and reliability.&lt;/p&gt;
&lt;p&gt;The principle I follow is simple: &lt;strong&gt;&lt;em&gt;simplicity scales&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;By embracing event-driven designs, we can create architectures that perform efficiently today and adapt to meet the demands of tomorrow.&lt;/p&gt;
</content:encoded></item><item><title>The Determinism Dilemma: Why Traditional Software Engineers Struggle with AI Development</title><link>https://arrangeactassert.com/posts/the-determinism-dilemma/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-determinism-dilemma/</guid><pubDate>Mon, 13 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;The goal of creating something “predictable,” reliable, and consistent is a shared principle across all the teams I’ve worked with throughout my career.&lt;/p&gt;
&lt;p&gt;Knowing that the same code would always return the same output when given the same inputs was the foundation of everything we built.&lt;/p&gt;
&lt;p&gt;We aimed for no surprises, no matter how complex a workflow might be.
Whether implicitly or explicitly using finite state machines, this determinism enabled us to build testable, monitorable, maintainable, and, most importantly, predictable workflows.&lt;/p&gt;
&lt;p&gt;We read and shared ideas at conferences, promoting patterns and principles like SOLID and DRY to create functional, composable, and extensible software.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-forcing-ai-to-be-deterministic-is-the-wrong-approach&quot;&gt;Why Forcing AI to be Deterministic is the Wrong Approach&lt;/h2&gt;
&lt;p&gt;AI applications challenge this principle in a fundamental way. While AI systems can still be structured and maintainable, their inherent unpredictability requires us to rethink our approach.&lt;/p&gt;
&lt;p&gt;For instance, asking an AI model to summarise a piece of text multiple times often produces different responses, especially when using zero-shot prompting. Many developers, uncomfortable with this unpredictability, try to force consistency by tweaking parameters like temperature or top-k.&lt;/p&gt;
&lt;p&gt;However, forcing an AI model to behave more predictably risks losing its greatest strength. Generative models excel when producing varied and creative outputs. Overfitting an AI model to achieve consistency may make it behave more like traditional software but, in doing so, diminishes its versatility and potential.&lt;/p&gt;
&lt;h2 id=&quot;embracing-ais-creativity&quot;&gt;Embracing AI’s Creativity&lt;/h2&gt;
&lt;p&gt;The key is to tailor the approach to the use case. In payment applications, predictability is paramount. These systems must behave in a consistent and reliable manner.&lt;/p&gt;
&lt;p&gt;In contrast, a chatbot thrives on variety and personalisation. Its responses should feel unique and engaging because its purpose is to interact with users whose goals or needs may not be immediately clear.
This shift in thinking requires developers to embrace AI’s non-deterministic nature when appropriate.&lt;/p&gt;
&lt;p&gt;Rather than suppressing it, we must design systems that take advantage of this quality while incorporating safeguards to manage its limitations.&lt;/p&gt;
&lt;h2 id=&quot;let-go-of-determinism-luke&quot;&gt;“Let Go of Determinism, Luke”&lt;/h2&gt;
&lt;p&gt;To borrow from Obi-Wan Kenobi’s advice: “Use the Force, Luke. Let go.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let Go of Determinism, Luke&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 666px) 666px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;666&quot; height=&quot;375&quot; src=&quot;https://arrangeactassert.com/_astro/ai-determinism.Dh5_Guxm_ZOIxxw.webp&quot; srcset=&quot;/_astro/ai-determinism.Dh5_Guxm_2riYJM.webp 640w, /_astro/ai-determinism.Dh5_Guxm_ZOIxxw.webp 666w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Knowing when to rely on determinism and when to let go of it is crucial.&lt;/p&gt;
&lt;p&gt;For traditional applications, the goal is consistent and predictable behaviour.&lt;/p&gt;
&lt;p&gt;For AI, the focus is often on adaptability and creativity.&lt;/p&gt;
&lt;p&gt;In future posts, I will explore how to balance these approaches.&lt;/p&gt;
&lt;p&gt;For now, remember that the key to success in AI development is not forcing it to follow old rules. The real challenge is learning to use its unique strengths effectively.&lt;/p&gt;
</content:encoded></item><item><title>Déjà Vu: AI Agent Frameworks and the JavaScript Gold Rush Revisited</title><link>https://arrangeactassert.com/posts/ai-gold-rush/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/ai-gold-rush/</guid><pubDate>Sat, 07 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Having lived through the era of a “new JavaScript framework every week,” we now find ourselves in the gold rush of the AI agent framework space.&lt;/p&gt;
&lt;p&gt;New frameworks appear daily, each claiming to be the ‘ultimate’ solution for building AI agents, often backed by YouTubers enthusiastically promoting demoware and usually their own library, framework, or SaaS offering. Unfortunately, this enthusiasm can lead companies to uncritically adopt these tools without considering the long-term implications.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Ai Gold Rush&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/ai-gold-rush.j-tQRsrF_ZPvHd2.webp&quot; srcset=&quot;/_astro/ai-gold-rush.j-tQRsrF_Z1SaIkd.webp 640w, /_astro/ai-gold-rush.j-tQRsrF_O6hk1.webp 750w, /_astro/ai-gold-rush.j-tQRsrF_Z1PSudR.webp 828w, /_astro/ai-gold-rush.j-tQRsrF_ZPvHd2.webp 1024w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;The recent &lt;a href=&quot;https://x.com/pyautogen/status/1857264760951296210&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AutoGen situation&lt;/a&gt; is a prime example of the chaos. Created by Microsoft, one might have expected stability, yet the framework has splintered, with founding contributors releasing their own fork, leaving developers confused and exhausted.&lt;/p&gt;
&lt;p&gt;Similarly, LangChain presents numerous overlapping solutions, and occasional breaking changes can make it more of a hindrance than a help, as they require constant learning and frequent updates.&lt;/p&gt;
&lt;p&gt;The lesson from the JS framework wars is clear: focus on understanding the core principles rather than tightly coupling your solution to any single framework.&lt;/p&gt;
&lt;p&gt;The biggest takeaway we learnt back then was to think in terms of components and composition, which I covered in my &lt;a href=&quot;https://jagreehal.github.io/build-components-not-walls-slides/index.html#/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“Build Components Not Walls”&lt;/a&gt; talk.&lt;/p&gt;
&lt;p&gt;Some AI offerings will undoubtedly emerge as long-term winners, just as React did, but many will fade as early hype and quick profits give way to stability and sustainability.&lt;/p&gt;
&lt;h2 id=&quot;how-to-build-solutions-during-the-age-of-the-ai-gold-rush&quot;&gt;How to build solutions during the age of the AI gold rush?&lt;/h2&gt;
&lt;p&gt;Adopt a “do one thing, and do it well” approach with framework-agnostic functions.&lt;/p&gt;
&lt;p&gt;This will enable you to adapt, experiment, compose, and combine agentic components as the landscape shifts. Having such abstractions allows you to future-proof your approach. By breaking down elements, such as prompts and schemas, you can more easily adapt if a framework falls out of favour or is abandoned.&lt;/p&gt;
&lt;p&gt;However, balance is crucial. Abstract too aggressively, and you may lose the genuine benefits that a framework provides.&lt;/p&gt;
&lt;p&gt;In my upcoming posts, I’ll share examples of how I’ve applied these principles.&lt;/p&gt;
&lt;p&gt;For now, the key takeaway is simple:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Focus on core concepts over fleeting trends.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>What About Using Structured Naming for Event-Driven Messaging?</title><link>https://arrangeactassert.com/posts/structured-naming-event-driven/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/structured-naming-event-driven/</guid><pubDate>Wed, 20 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;It’s a well-known adage that naming things is hard.&lt;/p&gt;
&lt;p&gt;In event-driven architectures, a consistent naming convention is essential for scalability, communication, collaboration and maintainability.&lt;/p&gt;
&lt;p&gt;At the moment, I’m architecting a new event-driven solution, and I planning to adopt a &lt;code&gt;Structured Naming&lt;/code&gt; approach for event types.&lt;/p&gt;
&lt;p&gt;In this post I’ll share my thoughts on this approach and its benefits.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;recommended-practice-embedding-metadata-in-event-payloads&quot;&gt;Recommended Practice: Embedding Metadata in Event Payloads&lt;/h2&gt;
&lt;p&gt;It’s a widely recommended practice to include metadata directly within the event payload.&lt;/p&gt;
&lt;p&gt;This metadata provides essential context about the event, such as its type, domain, and service, in addition to the data payload itself.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;detail&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;01HXHMF28A94NS7NSHC5GM80F4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2020-04-28T07:20:20Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;domain&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-service&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-placed&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;order_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1234567890123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;restaurant_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123456789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;currency&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;USD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;42.42&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;type&lt;/code&gt; field within the metadata specifies the event as &lt;code&gt;order-placed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While this method provides the necessary context, it can lead to challenges in event routing and subscription management, especially if you’re using NATS, where wildcards offer flexibility and agility.&lt;/p&gt;
&lt;p&gt;For instance, if consumers need to subscribe to all events related to orders, they may have to manage subscriptions manually for each type (&lt;code&gt;order-placed&lt;/code&gt;, &lt;code&gt;order-updated&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;h2 id=&quot;why-consider-a-structured-naming-approach&quot;&gt;Why Consider a Structured Naming Approach?&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;Structured Naming&lt;/strong&gt; approach organises event names in a structured, dot-separated format. This structure mirrors the natural categorisation of events, enabling intuitive grouping, routing, and filtering by using dots (&lt;code&gt;.&lt;/code&gt;) as separators.&lt;/p&gt;
&lt;h2 id=&quot;example-of-structured-event-naming&quot;&gt;Example of Structured Event Naming&lt;/h2&gt;
&lt;p&gt;Using a structured naming approach, events related to orders could be organised like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;order.created&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order.updated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order.deleted&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, the prefix &lt;code&gt;order&lt;/code&gt; denotes the domain or entity, while the suffix (&lt;code&gt;created&lt;/code&gt;, &lt;code&gt;updated&lt;/code&gt;, &lt;code&gt;deleted&lt;/code&gt;) specifies the verb. This structure allows consumers to easily subscribe to domain event types, such as all events under &lt;code&gt;order.*&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;consistency-is-key&quot;&gt;Consistency is Key&lt;/h2&gt;
&lt;p&gt;Keeping naming patterns predictable and consistent is critical to reducing cognitive load and avoiding confusion. For instance:
For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;use a single separator style (&lt;code&gt;order.created&lt;/code&gt;) and avoid mixing styles like &lt;code&gt;order-created&lt;/code&gt; and &lt;code&gt;order_created&lt;/code&gt; in the same system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adhering to a clear and consistent format ensures event names remain instantly recognisable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;benefits-of-the-structured-naming-approach&quot;&gt;Benefits of the Structured Naming Approach&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;improved-clarity&quot;&gt;Improved Clarity&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The structured naming convention includes both the event’s domain and action, making it easier to understand the purpose and intent of an event at a glance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;efficient-subscription-management&quot;&gt;Efficient Subscription Management&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consumers can use wildcard subscriptions to receive a broader set of events. For example, subscribing to &lt;code&gt;order.*&lt;/code&gt; captures all events related to orders, such as &lt;code&gt;order.created&lt;/code&gt; and &lt;code&gt;order.updated&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;scalability&quot;&gt;Scalability&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the system grows, adding new event types within a domain becomes seamless. You can introduce new events like &lt;code&gt;order.canceled&lt;/code&gt; or &lt;code&gt;user.profile.updated&lt;/code&gt; without overhauling existing subscription logic.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;sharding-capabilities&quot;&gt;Sharding Capabilities&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A structured naming convention can facilitate sharding by grouping related events with common prefixes (e.g. &lt;code&gt;order.*&lt;/code&gt; or &lt;code&gt;user.*&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This simplifies routing related events to the same shard, improving performance and resource allocation.&lt;/p&gt;
&lt;h2 id=&quot;adopting-a-structured-naming-pattern&quot;&gt;Adopting a Structured Naming Pattern&lt;/h2&gt;
&lt;p&gt;When adopting a structured naming approach, splitting by domain helps communicate intent and related actions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;domain-or-entity&quot;&gt;Domain or Entity&lt;/h3&gt;
&lt;p&gt;Represents the primary category, such as &lt;code&gt;order&lt;/code&gt;, &lt;code&gt;user&lt;/code&gt;, or &lt;code&gt;payment&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&quot;action-or-event-type&quot;&gt;Action or Event Type&lt;/h3&gt;
&lt;p&gt;Specifies the exact type of event, like &lt;code&gt;created&lt;/code&gt;, &lt;code&gt;updated&lt;/code&gt;, or &lt;code&gt;deleted&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;example-of-structured-event-names&quot;&gt;Example of Structured Event Names&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;user-events&quot;&gt;User Events&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;user.registered&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user.logged_in&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user.profile.updated&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&quot;payment-events&quot;&gt;Payment Events&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;payment.initiated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment.completed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment.failed&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This structure provides a consistent and organised approach to naming events, which should prove especially beneficial as systems scale and require more event types across multiple domains.&lt;/p&gt;
&lt;h2 id=&quot;versioning-strategy&quot;&gt;Versioning Strategy&lt;/h2&gt;
&lt;p&gt;When versioning events, a &lt;strong&gt;Version-First&lt;/strong&gt; strategy aligns well with wildcard subscriptions and provides immediate visibility of the version. For instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;versioned-event-types&quot;&gt;Versioned Event Types&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v1.order.created&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v2.order.updated&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v1.user.profile.updated&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach allows services to listen to specific versions or broader categories, such as &lt;code&gt;v2.*&lt;/code&gt;, giving flexibility in routing as schemas evolve.&lt;/p&gt;
&lt;h3 id=&quot;benefits-of-version-first-naming&quot;&gt;Benefits of Version-First Naming&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Immediate visibility&lt;/strong&gt;: Version information is the first thing you see&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier filtering&lt;/strong&gt;: Systems can quickly filter or route by version without parsing the entire event name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clearer version transitions&lt;/strong&gt;: Makes it easier to identify different versions of the same event type&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent with API versioning&lt;/strong&gt;: Aligns with common API versioning practices&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, a service could subscribe to all v1 events across domains with &lt;code&gt;v1.*&lt;/code&gt; or all v2 order events with &lt;code&gt;v2.order.*&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-cases&quot;&gt;Use Cases&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;microservices-architectures&quot;&gt;Microservices Architectures&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a microservices environment, services often respond to events from multiple domains. A structured naming convention allows services to subscribe to broader categories efficiently. For example, subscribing to &lt;code&gt;user.*&lt;/code&gt;simplifies setup by reducing the need to enumerate all event types.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;event-sourcing&quot;&gt;Event Sourcing&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In event-sourced systems, where state is reconstructed from historical events, a structured naming scheme enables systematic grouping and processing of events by category.&lt;/p&gt;
&lt;h2 id=&quot;antipatterns-and-potential-drawbacks-of-structured-naming&quot;&gt;AntiPatterns and Potential Drawbacks of Structured Naming&lt;/h2&gt;
&lt;p&gt;As with all things, there is a danger of overuse and misuse that could lead to complexity and challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;initial-implementation-effort&quot;&gt;Initial Implementation Effort&lt;/h3&gt;
&lt;p&gt;Standardising event names across teams requires upfront planning and governance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&quot;complexity-in-deep-naming-structures&quot;&gt;Complexity in Deep Naming Structures&lt;/h3&gt;
&lt;p&gt;Overly deep structures (e.g., &lt;code&gt;order.process.payment.canceled&lt;/code&gt;) can reduce clarity. Keeping structures simple and well-documented avoids this pitfall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think a structured naming convention for events can offer a straightforward, organised approach that enhances clarity, scalability, and efficiency in event-driven systems.&lt;/p&gt;
&lt;p&gt;Have you tried this approach? I’d love to hear about anything I’ve missed or overlooked, as well as any challenges, advantages, or pitfalls you’ve encountered.&lt;/p&gt;
</content:encoded></item><item><title>AWS Step Functions Cookbook</title><link>https://arrangeactassert.com/posts/aws-step-functions-cookbook/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/aws-step-functions-cookbook/</guid><pubDate>Fri, 01 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;This is my AWS Step Functions Mapping and Patterns and cookbook covering data manipulation, concurrency patterns, error handling, and advanced workflows.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#basic-concepts&quot;&gt;Basic Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#path-processing-fundamentals&quot;&gt;Path Processing Fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#concurrency-patterns&quot;&gt;Concurrency Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#advanced-state-patterns&quot;&gt;Advanced State Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#complex-workflows&quot;&gt;Complex Workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#error-handling--resilience&quot;&gt;Error Handling &amp;amp; Resilience&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#integration-patterns&quot;&gt;Integration Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#best-practices--tips&quot;&gt;Best Practices &amp;amp; Tips&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;basic-concepts&quot;&gt;Basic Concepts&lt;/h2&gt;
&lt;h3 id=&quot;processing-order-visualization&quot;&gt;Processing Order Visualization&lt;/h3&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;Input → InputPath → Parameters → Task → ResultSelector → ResultPath → OutputPath → Output&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;jsonpath-quick-reference&quot;&gt;JSONPath Quick Reference&lt;/h3&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// First book&apos;s title&lt;/span&gt;
$.store.book&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;.title

&lt;span class=&quot;token comment&quot;&gt;// All book titles&lt;/span&gt;
$.store.book&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;.title

&lt;span class=&quot;token comment&quot;&gt;// Books under $10&lt;/span&gt;
$.store.book&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;?(@.price &amp;lt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;)&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// All authors&lt;/span&gt;
$..author

&lt;span class=&quot;token comment&quot;&gt;// Number of books&lt;/span&gt;
$.store.book.length()&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;path-processing-fundamentals&quot;&gt;Path Processing Fundamentals&lt;/h2&gt;
&lt;p&gt;AWS Step Functions allows you to manipulate the data passing through your state machine at various stages using &lt;code&gt;InputPath&lt;/code&gt;, &lt;code&gt;Parameters&lt;/code&gt;, &lt;code&gt;ResultSelector&lt;/code&gt;, &lt;code&gt;ResultPath&lt;/code&gt;, and &lt;code&gt;OutputPath&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;1-inputpath-with-complex-filtering&quot;&gt;1. InputPath with Complex Filtering&lt;/h3&gt;
&lt;h4 id=&quot;example-filter-nested-arrays&quot;&gt;Example: Filter Nested Arrays&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SHIPPED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;requestId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;abc-123&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;InputPath&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessPendingOrders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;InputPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orders[?(@.status == &apos;PENDING&apos;)]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processedOrders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;totalAmount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SHIPPED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PENDING&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;requestId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;abc-123&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedOrders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;processedCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;totalAmount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;example-multiple-field-selection&quot;&gt;Example: Multiple Field Selection&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;street&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123 Main St&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Anytown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;zip&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;12345&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerInfo&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;john@example.com&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Parameters&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessOrderDetails&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;orderDetails&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;items.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.items[*].productId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;shipping.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.address&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;customerEmail.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.customerInfo.email&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderProcessingResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderDetails&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;shipping&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;street&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123 Main St&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Anytown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;zip&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;12345&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerEmail&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;john@example.com&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;confirmationNumber&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CONF-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;estimatedDelivery&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;street&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123 Main St&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;city&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Anytown&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;zip&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;12345&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerInfo&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;john@example.com&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderProcessingResult&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;confirmationNumber&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CONF-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;estimatedDelivery&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-advanced-parameters-usage&quot;&gt;2. Advanced Parameters Usage&lt;/h3&gt;
&lt;h4 id=&quot;example-dynamic-array-processing-and-intrinsic-functions&quot;&gt;Example: Dynamic Array Processing and Intrinsic Functions&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;product-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;product-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;product-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;stockStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;14:30:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-001&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Parameters&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessData&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;itemsArray.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.Array($.item)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;itemsCount.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.ArrayLength($.items)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;hasStock.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.StringToBoolean($.stockStatus)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;processTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;startTime.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.State.EnteredTime&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;formatted.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.Format(&apos;{}T{}Z&apos;, $.date, $.time)&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;executionStartTime.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.Execution.StartTime&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;retryCount.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.State.RetryCount&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;sessionId.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.metadata.sessionId&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processingResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;itemsArray&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;product-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;itemsCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;hasStock&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;startTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T14:30:00Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;formatted&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T14:30:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;executionStartTime&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T14:29:50Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;retryCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-001&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T14:30:10Z&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;product-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;product-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;product-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;stockStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;14:30:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-001&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processingResult&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;processedAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T14:30:10Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-replacing-or-overwriting-data-in-state-output&quot;&gt;3. Replacing or Overwriting Data in State Output&lt;/h3&gt;
&lt;h4 id=&quot;example-1-overwriting-state-data-using-resultpath&quot;&gt;Example 1: Overwriting State Data Using ResultPath&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NEW&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerInfo&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jane Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;jane@example.com&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with ResultPath Overwrite:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessOrderStatus&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;orderDetails&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PROCESSED&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderDetails&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PROCESSED&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SUCCESS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01T10:00:00Z&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SUCCESS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01T10:00:00Z&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;ResultPath&lt;/code&gt; with the &lt;code&gt;&quot;$&quot;&lt;/code&gt; path overwrites the entire state input, replacing it with the result from the Lambda function.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;example-2-partially-replacing-data-with-resultpath&quot;&gt;Example 2: Partially Replacing Data with ResultPath&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;alice@example.com&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;requestId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;req-789&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with Partial Overwrite Using ResultPath:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:UpdateOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;orderId.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;items.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.items[*].productId&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.updatedOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;UPDATED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01T12:30:00Z&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;alice@example.com&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;requestId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;req-789&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;updatedOrder&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;UPDATED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-12-01T12:30:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the &lt;code&gt;ResultPath&lt;/code&gt; directs the result to the &lt;code&gt;updatedOrder&lt;/code&gt; field in the existing state, allowing a partial overwrite.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;concurrency-patterns&quot;&gt;Concurrency Patterns&lt;/h2&gt;
&lt;h3 id=&quot;1-parallel-state-processing&quot;&gt;1. Parallel State Processing&lt;/h3&gt;
&lt;h4 id=&quot;example-basic-parallel-processing&quot;&gt;Example: Basic Parallel Processing&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cust-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Parallel&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Parallel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Branches&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessOrders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;ProcessOrders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessOrders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;UpdateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;UpdateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:UpdateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.parallelResults&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Tasks Receive:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ProcessOrders Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cust-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UpdateInventory Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cust-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;If Lambdas Return:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ProcessOrders Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UpdateInventory Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;inventoryStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Updated&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cust-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;parallelResults&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;orderStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;inventoryStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Updated&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;example-parallel-with-shared-context&quot;&gt;Example: Parallel with Shared Context&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sessionData&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T15:00:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preferences&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with Shared &lt;code&gt;Parameters&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Parallel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;context.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.sessionData&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;userId.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.userId&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Branches&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Branch1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Branch1&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:BranchFunction1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Branch2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Branch2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:BranchFunction2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultSelector&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;branch1Result.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$[0]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;branch2Result.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$[1]&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.branchResults&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Tasks Receive:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Both Lambdas Receive:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;context&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T15:00:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user-456&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;If Lambdas Return:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BranchFunction1 Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;activityLog&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Activity recorded&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BranchFunction2 Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preferenceUpdate&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Preferences saved&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sessionData&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sess-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T15:00:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preferences&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;branchResults&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;branch1Result&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;activityLog&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Activity recorded&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;branch2Result&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;preferenceUpdate&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Preferences saved&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-map-state-with-concurrency-control&quot;&gt;2. Map State with Concurrency Control&lt;/h3&gt;
&lt;h4 id=&quot;example-basic-map-with-concurrency&quot;&gt;Example: Basic Map with Concurrency&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Map&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Map&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ItemsPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;MaxConcurrency&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Iterator&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessSingleOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ProcessSingleOrder&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessSingleOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processedOrders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives (per iteration):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;First Iteration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Second Iteration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;(Up to MaxConcurrency of 2 at a time.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If Lambdas Return:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-X&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;processedOrders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Processed&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;example-map-with-itemselector&quot;&gt;Example: Map with &lt;code&gt;ItemSelector&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;array&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Map&lt;/code&gt; and &lt;code&gt;ItemSelector&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Map&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ItemsPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.array&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ItemSelector&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;index.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.Map.Item.Index&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;value.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.Map.Item.Value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.MathSqrt($$.Map.Item.Value)&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Iterator&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessItem&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ProcessItem&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pass&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.results&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Data Processed in Each Iteration:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;First Iteration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Second Iteration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;array&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;results&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;sqrtValue&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;advanced-state-patterns&quot;&gt;Advanced State Patterns&lt;/h2&gt;
&lt;h3 id=&quot;1-dynamic-branching-with-choice-state&quot;&gt;1. Dynamic Branching with Choice State&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;order&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;priority&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;HIGH&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;STANDARD&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;productId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prod-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FRAGILE&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;shipping&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;express&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Choice&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Choice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Choices&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;And&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.order.total&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;NumericGreaterThan&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.order.priority&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;StringEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;HIGH&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PremiumProcessing&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Or&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.order.items[?(@.category == &apos;FRAGILE&apos;)]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;IsPresent&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.order.shipping.express&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;BooleanEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SpecialHandling&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Default&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;StandardProcessing&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Path:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Since &lt;code&gt;$.order.total&lt;/code&gt; &amp;gt; 1000 and &lt;code&gt;$.order.priority&lt;/code&gt; == “HIGH”, the execution moves to &lt;code&gt;PremiumProcessing&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-wait-states-with-dynamic-duration&quot;&gt;2. Wait States with Dynamic Duration&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;task&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WaitForApproval&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;delay&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Wait for 30 seconds&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Wait&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wait&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;SecondsPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.delay&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CheckApprovalStatus&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The state machine waits for 30 seconds (as specified in &lt;code&gt;$.delay&lt;/code&gt;) before proceeding to &lt;code&gt;CheckApprovalStatus&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;complex-workflows&quot;&gt;Complex Workflows&lt;/h2&gt;
&lt;h3 id=&quot;1-orchestration-pattern&quot;&gt;1. Orchestration Pattern&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-999&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;customerId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cust-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-6&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Machine Definition:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;InitializeOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;InitializeOrder&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:InitializeOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ParallelProcessing&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ParallelProcessing&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Parallel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Branches&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ValidateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;ValidateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ValidateInventory&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessPayment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;ProcessPayment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessPayment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processingResults&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluateResults&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;EvaluateResults&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Choice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Choices&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;And&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processingResults[0].inventoryAvailable&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;BooleanEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.processingResults[1].paymentSuccessful&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token property&quot;&gt;&quot;BooleanEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FulfillOrder&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Default&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;HandleFailure&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;FulfillOrder&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:FulfillOrder&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;HandleFailure&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:HandleFailure&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;InitializeOrder&lt;/strong&gt; Lambda receives the initial input and performs setup tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ParallelProcessing&lt;/strong&gt; runs &lt;strong&gt;ValidateInventory&lt;/strong&gt; and &lt;strong&gt;ProcessPayment&lt;/strong&gt; in parallel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EvaluateResults&lt;/strong&gt; checks if both inventory is available and payment was successful.&lt;/li&gt;
&lt;li&gt;If both are true, it proceeds to &lt;strong&gt;FulfillOrder&lt;/strong&gt;; otherwise, it moves to &lt;strong&gt;HandleFailure&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Depends on the execution path taken. If successful, the order is fulfilled; if not, failure handling is executed.&lt;/p&gt;
&lt;h3 id=&quot;2-saga-pattern-with-compensation&quot;&gt;2. Saga Pattern with Compensation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;reservationDetails&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;flightId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;FL-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;hotelId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;HT-456&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;carRentalId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CR-789&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Machine Definition:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;StartAt&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ReserveFlight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;States&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ReserveFlight&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ReserveFlight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ReserveHotel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Catch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.ALL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.errorInfo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CleanupState&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ReserveHotel&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ReserveHotel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ReserveCar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Catch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.ALL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.errorInfo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CompensateFlight&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ReserveCar&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ReserveCar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CompleteBooking&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Catch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.ALL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.errorInfo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CompensateHotel&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;CompensateHotel&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:CancelHotel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CompensateFlight&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;CompensateFlight&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:CancelFlight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CleanupState&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;CompleteBooking&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:CompleteBooking&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;CleanupState&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pass&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If any reservation step fails, the state machine invokes compensation steps to undo previous actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Depends on the success or failure of each reservation step and the execution of compensation actions.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;error-handling--resilience&quot;&gt;Error Handling &amp;amp; Resilience&lt;/h2&gt;
&lt;h3 id=&quot;1-comprehensive-error-handling&quot;&gt;1. Comprehensive Error Handling&lt;/h3&gt;
&lt;h4 id=&quot;example-retry-configuration-with-catch&quot;&gt;Example: Retry Configuration with Catch&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;State Definition with &lt;code&gt;Retry&lt;/code&gt; and &lt;code&gt;Catch&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessData&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Retry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.Timeout&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;IntervalSeconds&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;MaxAttempts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;BackoffRate&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CustomError&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;IntervalSeconds&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;MaxAttempts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Catch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.ALL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.errorInfo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ErrorHandler&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The task retries on &lt;code&gt;States.Timeout&lt;/code&gt; and &lt;code&gt;CustomError&lt;/code&gt; according to specified settings.&lt;/li&gt;
&lt;li&gt;If all retries fail or another error occurs, it catches the error and transitions to &lt;code&gt;ErrorHandler&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-circuit-breaker-implementation&quot;&gt;2. Circuit Breaker Implementation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;State Definition with Circuit Breaker Logic:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Choice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Choices&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Variable&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.serviceHealth.errorCount&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;NumericGreaterThan&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CircuitOpen&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Default&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessNormally&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Execution Flow:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;$.serviceHealth.errorCount&lt;/code&gt; exceeds 5, the workflow transitions to &lt;code&gt;CircuitOpen&lt;/code&gt;, preventing further processing.&lt;/li&gt;
&lt;li&gt;Otherwise, it proceeds to &lt;code&gt;ProcessNormally&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;integration-patterns&quot;&gt;Integration Patterns&lt;/h2&gt;
&lt;h3 id=&quot;1-service-integration-pattern&quot;&gt;1. Service Integration Pattern&lt;/h3&gt;
&lt;h4 id=&quot;example-sqs-sendmessage-integration&quot;&gt;Example: SQS &lt;code&gt;SendMessage&lt;/code&gt; Integration&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1010&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Order placed successfully.&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with SQS Integration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:states:::sqs:sendMessage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;QueueUrl&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://sqs.region.amazonaws.com/account-id/queue-name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MessageBody.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MessageAttributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;OrderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;DataType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;String&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;StringValue.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderId&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultSelector&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MessageId.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.MessageId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Timestamp.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.State.EnteredTime&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.sqsResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-1010&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Order placed successfully.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;sqsResult&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MessageId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;abcd1234-5678-90ef-ghij-klmnopqrstuv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T16:00:00Z&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-api-gateway-integration&quot;&gt;2. API Gateway Integration&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderData&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2020&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with API Gateway Integration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:states:::apigateway:invoke&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ApiEndpoint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://myapi.execute-api.region.amazonaws.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Headers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/json&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Path&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/orders&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;RequestBody.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.orderData&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultSelector&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;StatusCode.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.StatusCode&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ResponseBody.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.ResponseBody&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.apiResponse&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;orderData&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2020&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;apiResponse&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;StatusCode&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ResponseBody&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Order received&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;orderId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order-2020&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;best-practices--tips&quot;&gt;Best Practices &amp;amp; Tips&lt;/h2&gt;
&lt;h3 id=&quot;1-use-intrinsic-functions-effectively&quot;&gt;1. Use Intrinsic Functions Effectively&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Example: Utilizing Intrinsic Functions in &lt;code&gt;Parameters&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;17:00:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-XYZ&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-XYZ&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;item-ABC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with Intrinsic Functions:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessIntrinsic&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;timestamp.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.Format(&apos;{}T{}Z&apos;, $.date, $.time)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;itemsArray.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.Array($.item)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;itemsCount.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.ArrayLength($.items)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;isValid.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.StringToBoolean($.status)&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.intrinsicResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2023-11-15T17:00:00Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;itemsArray&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;item-XYZ&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;itemsCount&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;isValid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-implement-idempotency-for-reliability&quot;&gt;2. Implement Idempotency for Reliability&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;State Definition with Idempotency Key:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:ProcessWithIdempotency&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;idempotencyKey.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;States.Format(&apos;{}-{}&apos;, $.orderId, $$.State.Name)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;payload.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.idempotentResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Ensures that each execution can be uniquely identified and avoids duplicate processing.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-monitor-execution-progress-with-cloudwatch&quot;&gt;3. Monitor Execution Progress with CloudWatch&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;State Definition with CloudWatch Integration:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:states:::cloudwatch:putMetricData&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Namespace&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;StepFunctions/Processing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MetricData&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;MetricName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ProcessingTime&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Value.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.duration&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Unit&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Milliseconds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;Dimensions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ExecutionId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Value.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$$.Execution.Id&quot;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ResultPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.cloudWatchResult&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Includes metrics data sent to CloudWatch for monitoring purposes.&lt;/p&gt;
&lt;h4 id=&quot;4-replace-data-effectively-with-outputpath&quot;&gt;4. Replace Data Effectively with OutputPath&lt;/h4&gt;
&lt;p&gt;Using &lt;code&gt;OutputPath&lt;/code&gt; to selectively replace or retain data in the output state can help keep workflow data clean and relevant.&lt;/p&gt;
&lt;h5 id=&quot;example-3-replacing-data-with-outputpath&quot;&gt;Example 3: Replacing Data with OutputPath&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Initial State Input:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preferences&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;light&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;settings&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user@example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;subscription&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;basic&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;State Definition with OutputPath Replacement:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:lambda:region:account-id:function:UpdatePreferences&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;userId.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.userId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;preferences.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.preferences&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;OutputPath&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$.preferences&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;End&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lambda Receives:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user-789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;preferences&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;light&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;If Lambda Returns:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dark&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resulting State Output:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot; data-language=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;notifications&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dark&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By setting the &lt;code&gt;OutputPath&lt;/code&gt; to &lt;code&gt;$.preferences&lt;/code&gt;, the final state output retains only the updated preferences data, replacing the initial input with the result of this task.&lt;/p&gt;
</content:encoded></item><item><title>Sometimes Boring is Best</title><link>https://arrangeactassert.com/posts/sometimes-boring-is-best/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/sometimes-boring-is-best/</guid><pubDate>Sat, 26 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;As I stood in the rain as a volunteer race marshal at my local park run, it occurred to me that I wanted the same thing when running applications in production, and that’s absolutely nothing to happen.&lt;/p&gt;
&lt;p&gt;The last thing I wanted to do was be a hero.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Me in the rain volunteering for Parkrun&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 478px) 478px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;478&quot; height=&quot;850&quot; src=&quot;https://arrangeactassert.com/_astro/jag-parkrun.DoK-SIRs_2tTHkN.webp&quot; srcset=&quot;/_astro/jag-parkrun.DoK-SIRs_2tTHkN.webp 478w&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🎸 “Always keep on the right side of the path” – the Parkrun version of Monty Python’s song.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’d rather everyone enjoy a safe, smooth race where I can cheer and encourage people on as they pass, reminding them to keep to the right so they don’t collide with runners coming the other way.&lt;/p&gt;
&lt;p&gt;It’s the same in the land of IT. The only thing I want to see when viewing Grafana dashboards is a sea of green, 200 status codes and steady traffic patterns.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;whats-so-bad-about-heroes&quot;&gt;What’s So Bad About Heroes?&lt;/h2&gt;
&lt;p&gt;Whilst working with consultants on a client engagement, one of my colleagues questioned why we were celebrating someone waking up at 3 AM to “rescue” the application with Superman emojis.&lt;/p&gt;
&lt;p&gt;At first, I didn’t agree, but then I saw their point.&lt;/p&gt;
&lt;p&gt;Reactive, heroic behaviour creates great headlines and attention, but sometimes we should aim for clicking clock levels of excitement.&lt;/p&gt;
&lt;p&gt;After all, the best work in designing, building, architecting, and deploying is often the work nobody notices.&lt;/p&gt;
</content:encoded></item><item><title>Don&apos;t Look Back in Anger: Let&apos;s Design a Better Ticketing System</title><link>https://arrangeactassert.com/posts/a-better-ticketing-system/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/a-better-ticketing-system/</guid><pubDate>Sat, 31 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Saturday’s Oasis ticket sales left thousands of fans disheartened after spending hours in virtual queues. As reported by the &lt;a href=&quot;https://www.bbc.co.uk/news/articles/c5y8wer58x6o&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;BBC&lt;/a&gt; and echoed by fans on &lt;a href=&quot;https://x.com/oasis/status/1829942357581529266?s=&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;X&lt;/a&gt; (formerly Twitter) and &lt;a href=&quot;https://www.reddit.com/r/oasis/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Reddit&lt;/a&gt;, the experience could be aptly described using a quote from Liam Gallagher himself:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Shite&lt;/p&gt;&amp;mdash; Liam Gallagher (@liamgallagher) &lt;a href=&quot;https://twitter.com/liamgallagher/status/1649012883685101572?ref_src=twsrc%5Etfw&quot;&gt;April 20, 2023&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;Like many others, I have long been frustrated with platforms like Ticketmaster, See Tickets, and Gigs and Tours. This weekend, their reputations took another hit as fans faced inflated prices and technical glitches.&lt;/p&gt;
&lt;p&gt;This made me think if I could design a better, more reliable ticketing system that prioritises fairness and user experience.&lt;/p&gt;
&lt;p&gt;Let’s not make Sally wait any longer than she has to.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;some-might-say&quot;&gt;Some Might Say&lt;/h2&gt;
&lt;p&gt;This document outlines the design and technical requirements for an enhanced ticketing system aimed at reducing server load, improving user experience, and ensuring environmental sustainability.&lt;/p&gt;
&lt;p&gt;The proposed system will achieve these goals through random selection, time-limited purchasing, and lightweight verification, with a focus on simplicity and excellent user experience.&lt;/p&gt;
&lt;h2 id=&quot;wonderwall&quot;&gt;Wonderwall&lt;/h2&gt;
&lt;p&gt;Traditional ticketing systems often crumble under the pressure of high-demand events, leading to poor user experiences, system crashes, and unfair ticket distribution.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;graph TD
  A[User Joins Queue] --&amp;gt; B[Wait in Line]
  B --&amp;gt; C{Tickets Available?}
  C --&amp;gt;|Yes| D[Purchase Ticket]
  C --&amp;gt;|No| E[Event Sold Out]
&lt;/pre&gt;
&lt;p&gt;The improved system seeks to address these issues more efficiently and user-friendly.&lt;/p&gt;
&lt;pre class=&quot;mermaid mermaid-graph&quot;&gt;graph TD
A[User Signs Up 24 Hours Before Sale] --&amp;gt; B[Verify Email &amp;amp; Phone]
B --&amp;gt; C[Specify Preferences &amp;amp; Notification Method]
C --&amp;gt; D[Enter Selection Queue]
D --&amp;gt; E{Selected?}
E --&amp;gt;|Yes| F[Receive Notification]
E --&amp;gt;|No| G[Remain in Queue]
F --&amp;gt; H[Purchase Window Opens]
H --&amp;gt; I{User Clicks Link to Purchase}
I --&amp;gt;|Yes| J[10-Minute Purchase Window]
J --&amp;gt; K{Purchase Completed?}
K --&amp;gt;|Yes| L[Ticket Secured]
K --&amp;gt;|No| P[Exit Process]
G --&amp;gt; N{Tickets Remaining?}
N --&amp;gt;|Yes| E
N --&amp;gt;|No| O[Notify: Event Sold Out]
&lt;/pre&gt;
&lt;h2 id=&quot;the-masterplan&quot;&gt;The Masterplan&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🎲 Fair Selection System: A number of initial users (e.g., 1000) are selected randomly from the Queue, ensuring equal chances for all. The system takes user preferences into account, avoiding notifications to those who cannot fulfill their requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;⏱️ Time-Limited Purchase Window: Selected users have 10 minutes to click the link to start purchasing. After clicking the link, they have another 10 minutes to complete their purchase, keeping the process moving efficiently.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;📅 Pre-Sale Deadline: Users must complete sign-up, specify preferences, and select their notification method at least 24 hours before the sale begins. This ensures they are in line for ticket selection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;📱 Multi-Channel Notifications: Users choose how they want to be notified: Push, SMS, Email, or any combination.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔒 Simple Verification: Quick email and phone verification during sign-up ensures user authenticity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🛡️ Anti-Scalping Measures: The system includes checks to prevent multiple accounts and bulk purchases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🚶‍♂️ Stress-Free Waiting Room: Users can go about their day, knowing they’ll be notified if selected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔄 Controlled User Flow: If a selected user does not complete their purchase within the given time, they exit the process. Another user is then selected, maintaining a smooth and efficient flow of ticket sales.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🎯 Preference-Based Notifications: Users specify venue, number of tickets, price band, and accessibility needs in advance. The system only notifies those whose preferences match available tickets, ensuring a more efficient and satisfying purchase process.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;be-here-now&quot;&gt;Be Here Now&lt;/h2&gt;
&lt;p&gt;The system’s architecture is designed for simplicity and efficiency, allowing easy scaling without the need for expensive server infrastructure.&lt;/p&gt;
&lt;p&gt;This design ensures that even with millions of users in the selection Queue, the system remains responsive and doesn’t require overpowered servers.&lt;/p&gt;
&lt;h2 id=&quot;dyou-know-what-i-mean&quot;&gt;D’You Know What I Mean?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🔐 Efficient Sign-up Process: Utilises a CAPTCHA check to prevent bot attacks, reducing server load. Email and phone verification are processed asynchronously to ensure a smooth user experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;⚙️ Event-Driven Architecture: Processes like user selection, notification, and purchase are event-driven, allowing for horizontal scaling and efficient resource use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🚦 Controlled Concurrency: Limits the number of users making purchases simultaneously, naturally throttling demand and preventing server overload.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🗃️ Stateless Design: User state is managed in the database rather than server memory, enabling easy load balancing and server scaling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;📨 Queuing System: Utilises message queues to process notifications and selections, ensuring system stability during high-load periods.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🗄️ Caching Layer: Frequently accessed data, such as event details and available tickets, is cached, reducing database load and improving response times.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;its-gettin-better-man&quot;&gt;It’s Gettin’ Better (Man!!)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;😊 User Satisfaction Rate: Targeting over 90%, measured through short post-process surveys.&lt;/li&gt;
&lt;li&gt;🔼 System Uptime: Aiming for 99.99%, ensuring reliability during high-demand periods.&lt;/li&gt;
&lt;li&gt;⏱️ Average Purchase Time: Less than 5 minutes from notification to completed transaction.&lt;/li&gt;
&lt;li&gt;📉 Server Load Reduction: Targeting a 50% reduction compared to traditional queuing systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;little-by-little&quot;&gt;Little By Little&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;🚀 Efficient Sign-up: A quick form with only essential fields ensures minimal friction during registration.&lt;/li&gt;
&lt;li&gt;🔄 Asynchronous Architecture: Handles traffic spikes smoothly, keeping the system responsive.&lt;/li&gt;
&lt;li&gt;🔐 Data Protection: All user data is encrypted, ensuring privacy and security.&lt;/li&gt;
&lt;li&gt;📱 Unique Accounts: Only one account is allowed per verified phone number, preventing fraud and scalping.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;talk-tonight&quot;&gt;Talk Tonight&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;💬 Effective Communication: Clear and timely communication is essential for a successful ticketing system. Users should be kept informed using simple status screens like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-plaintext&quot; data-language=&quot;plaintext&quot;&gt;&lt;code class=&quot;language-plaintext&quot;&gt;+------------------------------------------+
|          Virtual Waiting Room            |
+------------------------------------------+
| Event: Oasis 2025                        |
|                                          |
| Status: You&apos;re in the queue              |
|                                          |
| We&apos;ll notify you if you&apos;re selected:     |
| • SMS: (44) 7970 123456                  |
| • Email: user@example.com                |
|                                          |
| [Update Contact Info]   [Exit]           |
+------------------------------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;🔔 Clear Notifications: Messages like “You’ve been selected! You have 10 minutes to start purchasing your tickets” keep users informed throughout the process.&lt;/li&gt;
&lt;li&gt;📧 Helpful Emails: Include FAQs and next steps, guiding users through the purchasing process.&lt;/li&gt;
&lt;li&gt;🆘 Support Access: An easy-to-find help section and support contact ensure users can resolve any issues quickly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stand-by-me&quot;&gt;Stand by Me&lt;/h2&gt;
&lt;p&gt;This revised ticketing system prioritises user experience while maintaining simplicity and efficiency.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🧘 Stress-Free Waiting Process: Users can relax without anxiously watching a queue.&lt;/li&gt;
&lt;li&gt;📣 Clear Communication: Users know precisely how and when they’ll be notified.&lt;/li&gt;
&lt;li&gt;⚖️ Fair Chance for All: Random selection gives everyone an equal opportunity.&lt;/li&gt;
&lt;li&gt;⏳ Efficient Purchase Process: Selected users can quickly secure their tickets.&lt;/li&gt;
&lt;li&gt;🖥️ Reduced Server Load: Event-driven architecture handles high demand smoothly.&lt;/li&gt;
&lt;li&gt;🚫 Scalper Prevention: Verification and purchase limits deter bulk buying.&lt;/li&gt;
&lt;li&gt;💸 Cost-Effective Scaling: Simple architecture allows for efficient resource use.&lt;/li&gt;
&lt;li&gt;🔄 Dynamic User Selection: As soon as one user completes or times out, another gets a chance, controlling the number of users purchasing at any time.&lt;/li&gt;
&lt;li&gt;🎯 Preference-Based Notifications: Users specify their needs upfront, and the system only notifies those whose preferences match the available tickets, making the process more efficient and user-friendly.&lt;/li&gt;
&lt;li&gt;📅 Pre-Sale Deadline: Ensures users complete all necessary steps at least 24 hours before the sale starts, confirming their eligibility and ensuring they are in line for selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;live-forever&quot;&gt;Live Forever&lt;/h2&gt;
&lt;p&gt;This system creates a win-win scenario: users enjoy a more pleasant ticket-buying experience, and event organisers benefit from reduced costs and improved customer satisfaction.&lt;/p&gt;
&lt;p&gt;The technical design ensures scalability and performance, using serverless architecture to keep costs low and manageable without requiring additional manual operational resources.&lt;/p&gt;
&lt;p&gt;This approach should resolve the frustrations that Oasis fans encountered on Saturday, ensuring they won’t be looking back in anger.&lt;/p&gt;
</content:encoded></item><item><title>The Leadership Gamble: Why Fighting for Your Team Is Essential for Success</title><link>https://arrangeactassert.com/posts/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success/</guid><pubDate>Tue, 06 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;I’ve been fortunate to work with some incredible leaders throughout my career.&lt;/p&gt;
&lt;p&gt;These individuals have inspired and challenged their teams and driven them to achieve their full potential.&lt;/p&gt;
&lt;p&gt;What truly sets a leader apart, however, is their ability to motivate and their willingness to fight for their team.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There’s something special about a leader who fights for their team.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this post, I’ll explain what happens when a leader truly stands up for their team, sharing my firsthand experiences from a transformative project at Cambridge Assessment in 2007.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A close-up image of an exam answer sheet titled ‘Leadership’ at the top. The sheet features a multiple-choice section with bubbles filled in. A hand is seen holding a pencil, and a bold red ‘A+’ grade is hand-drawn and circled in the center of the sheet. The overall setting has a realistic, academic feel, highlighting the theme of evaluation and achievement&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1024px) 1024px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://arrangeactassert.com/_astro/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success.Csoajmf3_ZGVAJx.webp&quot; srcset=&quot;/_astro/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success.Csoajmf3_2f3peS.webp 640w, /_astro/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success.Csoajmf3_H4qXd.webp 750w, /_astro/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success.Csoajmf3_ZHF2lM.webp 828w, /_astro/the-leadership-gamble-why-fighting-for-your-team-is-essential-for-success.Csoajmf3_ZGVAJx.webp 1024w&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;In the summer of 2007, Cambridge Assessment had just completed marking examination scripts for millions of students worldwide. The existing system, though functional, was slow, inefficient, and error-prone.&lt;/p&gt;
&lt;p&gt;The team responsible had to work long hours to ensure accuracy and timeliness. It became clear that a more robust, scalable solution was needed.&lt;/p&gt;
&lt;p&gt;As I detailed in my previous post, “How Agile Helped Cambridge Assessment to Scale,” I was hired to architect and build a new system as part of a team.&lt;/p&gt;
&lt;h2 id=&quot;leadership-in-action&quot;&gt;Leadership in Action&lt;/h2&gt;
&lt;p&gt;Our tech leader, who had been with Cambridge Assessment for a couple of years, fully understood the complexities of the existing system and the organization’s politics.&lt;/p&gt;
&lt;p&gt;Some stakeholders were concerned that introducing a new team and system would alienate the existing staff, potentially leading to valuable team members leaving and taking with them the knowledge of running and supporting a key system.&lt;/p&gt;
&lt;p&gt;However, our leader, who interviewed and hired us, believed in our ideas and the team’s capabilities. He fought to keep politics away from us, advocating for the new system’s benefits and value.&lt;/p&gt;
&lt;h2 id=&quot;navigating-challenges&quot;&gt;Navigating Challenges&lt;/h2&gt;
&lt;p&gt;Our leader faced a lot of pushback. People questioned our team’s methods, our tech choices, and our shift to agile practices like pair programming and test-driven development.&lt;/p&gt;
&lt;p&gt;He backed our “strangler-fig” approach, where we’d gradually replace the old system. This step-by-step plan reassured everyone that the switch would be smooth and the new system would deliver.&lt;/p&gt;
&lt;h2 id=&quot;unwavering-support&quot;&gt;Unwavering Support&lt;/h2&gt;
&lt;p&gt;Our leader’s support went beyond advocacy to active engagement. He stood firm against scepticism in countless meetings, making a case for our approach and ensuring we had space to experiment, especially with scalability — a critical aspect of the new system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As an architect, I faced many criticisms and doubts. Without my leader’s trust and willingness to gamble on me, I would have been removed from the project. His support was a turning point in my career, and I’m grateful for his faith in me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Taking an innovative approach meant experiencing and failing, which put my leader in challenging positions. Yet he never gave up on me.&lt;/p&gt;
&lt;p&gt;His reputation was on the line, but he continued to fight for me and our team.&lt;/p&gt;
&lt;h2 id=&quot;a-successful-transformation&quot;&gt;A Successful Transformation&lt;/h2&gt;
&lt;p&gt;By the summer of 2008, our solution was fully operational and easily handled the increased workload, significantly benefiting the entire organization with a smoother, more efficient process.&lt;/p&gt;
&lt;p&gt;This experience was life-changing for me. Our leader’s support created an environment where we could grow, innovate, and feel psychologically safe.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;His trust in us was critical to our success.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-power-of-leadership-dedication&quot;&gt;The Power of Leadership Dedication&lt;/h2&gt;
&lt;p&gt;A leader who fights for their team can make all the difference. It’s not just about making intelligent technical decisions; it’s also about navigating the complex human side of projects and building a culture of success.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our leader’s tireless support enabled us to build a solution that raised the bar for Cambridge Assessment. His leadership showed us that believing in your team — and fighting for them — can lead to unprecedented outcomes.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>The Fine Line Between Frustration and Desperation</title><link>https://arrangeactassert.com/posts/the-fine-line-between-frustration-and-desperation/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/the-fine-line-between-frustration-and-desperation/</guid><pubDate>Tue, 16 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;As an England football fan, I know the feeling all too well. The heartbreak of watching your team come so close, only to fall short at the final hurdle once again. It’s now 58 years of hurt.&lt;/p&gt;
&lt;p&gt;It’s a mixture of emotions – frustration, disappointment, and knowing the team could have done more.&lt;/p&gt;
&lt;p&gt;I’ve experienced a similar feeling in my work as a consultant.&lt;/p&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;https://www.reuters.com/resizer/v2/I4GZPSJZ6FJTFCOYTB6LA4X6AY.jpg?auth=e29f6837f98dec79ae158849ad3405ab6d0af8c0e1fb873a97c4e173bd20ad11&amp;width=1920&amp;quality=80&quot;
    alt=&quot;Harry Kane walking past the Euro 2024 trophy&quot;
  /&gt;
  &lt;figcaption &gt;
   &lt;a href=&quot;https://www.reuters.com/pictures/spain-beat-england-win-euro-2024-2024-07-14/I4GZPSJZ6FJTFCOYTB6LA4X6AY/&quot;&gt;Reuters&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;You pour your heart and soul into a project, determined to deliver your best, but sometimes, even when the client is happy, you can’t shake the feeling that the outcome is good, but something is missing from making it great.&lt;/p&gt;
&lt;p&gt;It’s a fine line between frustration and desperation, and it’s easy for others to misunderstand which side of that line you’re on. Frustration is a natural reaction when you know you have more to give and feel like you haven’t quite reached your full potential. Conversely, desperation can be perceived as a sign of weakness, a lack of confidence, or control.&lt;/p&gt;
&lt;p&gt;The truth is, frustration is often a sign of passion, of a deep-seated desire to excel. It’s the driving force that pushes us to strive for greatness, to constantly seek ways to improve and refine our craft. On the other hand, desperation can be a paralysing emotion, leading to poor decision-making and a loss of focus.&lt;/p&gt;
&lt;p&gt;The key is to recognise the difference and channel that frustration productively. Instead of dwelling on the what-ifs and missed opportunities, we need to take a step back, reflect on what we’ve learned, and use that knowledge to improve.&lt;/p&gt;
&lt;p&gt;It’s not easy, and it’s a battle we all face at one point or another. But the true mark of a champion, whether on the football pitch or in the business world, is the ability to turn that frustration into fuel and use it as a driving force to reach new heights.&lt;/p&gt;
&lt;p&gt;&lt;img
 src=&quot;https://arrangeactassert.com/static/images/frustration-vs-desperation.webp&quot;
 alt=&quot;frustration-vs-desperation&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;Even though we’ve talked about the golden generation before, this England team can turn frustration into motivation, learn from their failures, and strive for greatness. By the time the World Cup comes along in 2026, the players will have had more success with their clubs, spent more time playing together, and gained more experience knowing what it takes to win trophies and adapt their game.&lt;/p&gt;
&lt;p&gt;They are not desperate to win the World Cup; they want to win it, and that desire will fuel what they do next.&lt;/p&gt;
&lt;p&gt;Similarly, businesses should recognise the difference between frustration and desperation in their team members. When someone shows frustration, it shows a desire to improve, do their best work, and take ownership and responsibility.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Motivated people consistently deliver more valuable outcomes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, the next time you feel frustrated, remember it’s a sign of your commitment, passion, and desire to be the best. Embrace it, channel it, and let it drive you forward.&lt;/p&gt;
</content:encoded></item><item><title>Empathy: The Underrated Leadership Skill That Boosts Productivity</title><link>https://arrangeactassert.com/posts/empathy-the-underrated-leadership-skill-that-boosts-productivity/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/empathy-the-underrated-leadership-skill-that-boosts-productivity/</guid><pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;As the English Football League nears the climax of another demanding season, leaders are confronted with the challenge of motivating weary players and handling the intense mental and physical pressures of chasing titles, securing promotions, or avoiding relegation.&lt;/p&gt;
&lt;p&gt;As a Barcelona supporter, it might come as a surprise that I using Jose Mourinho, a figure often mired in controversy, who exemplified empathetic leadership during his reign at Inter Milan, leading to their historic treble win.&lt;/p&gt;
&lt;p&gt;&lt;img
 src=&quot;https://arrangeactassert.com//talksport.com/wp-content/uploads/sites/5/2018/08/GettyImages-90175933.jpg?strip=all&amp;w=960&quot;
 alt=&quot;Mourinho and Sneijder&quot;
/&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;During the 2009-2010 season at Inter Milan, Mourinho noticed Wesley Sneijder’s exhaustion. Rather than ignoring the situation, he took an unconventional approach, deifying the usual win-at-all-costs mentality in sports by advising Sneijder to take some time off.&lt;/p&gt;
&lt;p&gt;Mourinho noticed Sneijder’s exhaustion and said, “Wesley, you look tired. Take a few days off. Go get some sun with your wife and child.” This approach was unlike any other coach Sneijder had encountered, who typically focused only on training. Taking Mourinho’s advice, Sneijder went to Ibiza for three days.&lt;/p&gt;
&lt;p&gt;This break not only rejuvenated him but also deepened his loyalty, significantly enhancing his performance for the remainder of the season. Upon his return, he felt so revitalized and committed that he was ready to go to battle for Mourinho. Sneijder later expressed&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I got back, I was prepared to kill and die for him.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a vital lesson for leaders everywhere: by actively listening to and addressing team concerns, you foster an environment of trust and respect.&lt;/p&gt;
&lt;p&gt;In my own experience as a leader, I have witnessed similar transformations.&lt;/p&gt;
&lt;p&gt;Leaders who prioritise empathy consistently prove more effective in revitalizing teams suffering from low morale and productivity. Their empathetic approach infuses these teams with new energy, strengthening loyalty and boosting performance. These experiences underscore that the ability to genuinely connect with and respond to team members not only enhances performance but also fosters a culture of mutual respect and dedication, leading to a more harmonious and productive work environment.&lt;/p&gt;
&lt;p&gt;Empathetic leaders not only enhance team outcomes but also improve overall well-being, creating a supportive work environment that values both people and results.&lt;/p&gt;
</content:encoded></item><item><title>Innovation Redefined: from &apos;Fail Fast&apos; to &apos;Learn Fast&apos;</title><link>https://arrangeactassert.com/posts/innovation-redefined-from-fail-fast-to-learn-fast/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/innovation-redefined-from-fail-fast-to-learn-fast/</guid><pubDate>Tue, 21 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Inspect and adapt loops are the heart of agile development. They enable continuous learning, improvement, and evolution.&lt;/p&gt;
&lt;p&gt;&lt;img
 src=&quot;https://arrangeactassert.com/static/images/learn-fast.png&quot;
 alt=&quot;Learn Fast&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;In this post, I discuss the limitations of the “fail fast” approach and propose a more impactful alternative: “learn Fast”. This mindset embraces the inevitability of failure in innovation and transforms every challenge into a learning opportunity.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;People are perpetual learners. Each product and feature is an opportunity for learning and growth. The more we learn, the more we grow. The more we grow, the more we learn. It’s a virtuous cycle.&lt;/p&gt;
&lt;p&gt;While both principles encourage innovation and aim to have the same outcome, only one principle will make good things great, where every iteration is another lesson learned.&lt;/p&gt;
&lt;h3 id=&quot;-fail-fast&quot;&gt;💔 Fail Fast&lt;/h3&gt;
&lt;p&gt;Fail fast minimises the time and resources spent on something that ultimately won’t work or deliver value. Detecting as soon as possible on when an assumption or bet isn’t working out requires judgment.&lt;/p&gt;
&lt;p&gt;This judgement is critical to reducing waste, in this case, time and energy.&lt;/p&gt;
&lt;p&gt;How the judgement is made should be decided up front and could include factors such as price, suitability, applicability, complexity, compatibility and adaptability.&lt;/p&gt;
&lt;h3 id=&quot;-learn-fast&quot;&gt;🚀 Learn Fast&lt;/h3&gt;
&lt;p&gt;Learning fast is all about making it work, making it right, and making it fast.&lt;/p&gt;
&lt;p&gt;It’s where successful teams have a continuous discovery process where they always identify new opportunities to deliver value.&lt;/p&gt;
&lt;p&gt;It’s not a one-off but continuous, not reactive but proactive, not limited but infinite.&lt;/p&gt;
&lt;h3 id=&quot;learn-fast-in-practice&quot;&gt;Learn Fast in Practice&lt;/h3&gt;
&lt;p&gt;In the next post, I’ll describe how learning fast is applied in practice.&lt;/p&gt;
</content:encoded></item><item><title>Structured logging with Pino</title><link>https://arrangeactassert.com/posts/structured-logging-with-pino/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/structured-logging-with-pino/</guid><pubDate>Tue, 14 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Structured logging focuses on capturing data in a consistent and machine-readable format.&lt;/p&gt;
&lt;p&gt;Unlike traditional text-based logs, structured logs are more straightforward to query and analyse, making extracting insights and debugging issues simpler.&lt;/p&gt;
&lt;p&gt;&lt;img
 src=&quot;https://arrangeactassert.com/static/images/structured-logging.webp&quot;
 alt=&quot;Engineering coding&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;In this post, we’ll take a look at an example of how structured logging with Pino.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;In the examples below the logging approach is unstructured and lacks context, making it hard to parse or search through logs.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;User logged in&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;User: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; logged in at: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead you should switch to structured logging like this:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;User logged in&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This output is structured in JSON format, making parsing and analyzing programmatically more accessible.&lt;/p&gt;
&lt;p&gt;Adopting Pino for structured logging in Node.js applications significantly improves log management. It ensures logs are human-readable and machine-friendly, enhancing debugging and monitoring.&lt;/p&gt;
</content:encoded></item><item><title>A Decade of Leadership: Celebrating Joe Parry&apos;s Legacy at the JavaScript &amp; NodeJS Cambridge Meetup Group</title><link>https://arrangeactassert.com/posts/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group/</guid><pubDate>Mon, 10 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;This post celebrates and thanks &lt;a href=&quot;https://www.linkedin.com/in/joeparry/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Joe Parry&lt;/a&gt; as he takes a well-deserved bow and steps down from his role as the head of the JavaScript &amp;amp; NodeJS Cambridge Meetup Group.&lt;/p&gt;
&lt;p&gt;He has been an extraordinary leader who has dedicated the past ten years to fostering a vibrant community of Javascriptors in Cambridge.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.cambridgeindependent.co.uk/_media/img/750x0/K09PJYME0VPUG1ILVINR.jpg&quot; alt=&quot;Joe Parry&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;Photo from www.cambridgeindependent.co.uk&lt;/div&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Way back on Tuesday, December 11, 2012, Joe began the group on the top floor of The Fountain in Cambridge. His vision, charisma, and passion were infectious, resulting in a group that has grown to include over 1,205 dedicated members, spanning beginners, professionals, and industry leaders.&lt;/p&gt;
&lt;p&gt;Each meeting organised by Joe was a hub of innovation and learning. He worked tirelessly to bring in experts and industry influencers, ensuring every session was brilliant.&lt;/p&gt;
&lt;p&gt;Joe always emphasised inclusivity, creating a safe space for beginners to ask questions, learn, and grow alongside seasoned veterans. The result was a symbiotic community where every member felt valued and welcome.&lt;/p&gt;
&lt;p&gt;Under Joe’s stewardship, the JavaScript &amp;amp; NodeJS Cambridge
Meetup Group went beyond the talks allowing members to build friendships, form valuable professional connections, and foster a supportive community.&lt;/p&gt;
&lt;p&gt;It’s hard to imagine the JavaScript &amp;amp; NodeJS Cambridge
Meetup Group without Joe at the helm. Hopefully, he will continue to participate and be involved somehow.&lt;/p&gt;
&lt;p&gt;Thank you, Joe, for your ten years of service, guidance, and friendship. You have left an indelible mark on the Cambridge JavaScript community, and we will always be grateful for your invaluable contribution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;It’s me presenting at the JavaScript &amp;amp; NodeJS Cambridge Meetup Group&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 3264px) 3264px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;3264&quot; height=&quot;1836&quot; src=&quot;https://arrangeactassert.com/_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_2ezcgP.webp&quot; srcset=&quot;/_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_cFEuj.webp 640w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_ZvSNjy.webp 750w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_9gaFB.webp 828w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_Zg4sYo.webp 1080w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_1uSoDH.webp 1280w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_1yVAaW.webp 1668w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_ZMjOmV.webp 2048w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_1OYHXk.webp 2560w, /_astro/a-decade-of-leadership-celebrating-joe-parrys-legacy-at-the-javascript-and-nodejs-cambridge-meetup-group.Ea11TuaM_2ezcgP.webp 3264w&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;-mt-8 text-left&quot;&gt;Photo of one of my many talks at the group in Hot Numbers, Cambridge.&lt;/div&gt;
&lt;p&gt;I have been lucky enough to have been a regular speaker at the group, and while the group works out what happens next, here’s to Joe – a true champion of the JavaScript and NodeJS community.&lt;/p&gt;
</content:encoded></item><item><title>Empowering Engineers: How Cambridge University Press Adopted a Shift Left Culture</title><link>https://arrangeactassert.com/posts/how-cambridge-unversity-press-adopted-a-shift-left-culture/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-cambridge-unversity-press-adopted-a-shift-left-culture/</guid><pubDate>Wed, 08 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Companies must be agile and respond quickly to changing customer needs in today’s fast-paced and constantly evolving technology landscape. That’s why DevOps practices that emphasise collaboration and communication between development and operations teams to deliver software rapidly, reliably, and at scale have become increasingly popular.&lt;/p&gt;
&lt;p&gt;Shifting left, a core principle of DevOps can significantly benefit companies of all sizes. By empowering engineers to take on more operations responsibilities and promoting a culture of experimentation and innovation, companies can improve collaboration, increase reliability, and deliver high-quality software at scale.&lt;/p&gt;
&lt;p&gt;In this post, I’ll discuss how and why Cambridge University Press adopted a shift left culture.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//unsplash.com/photos/MTND4rgPP88/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjc4MjM2ODA3&amp;amp;force=true&amp;amp;w=1920&quot; alt=&quot;one way sign pointing left&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://arrangeactassert.com//unsplash.com/@m_rags?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Madeleine Ragsdale&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/MTND4rgPP88?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
&lt;/div&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;a-new-culture&quot;&gt;A New Culture&lt;/h2&gt;
&lt;p&gt;Cambridge University Press had a small operations team responsible for hosting Node.js applications used by millions of users daily on EC2.&lt;/p&gt;
&lt;p&gt;They realised engineers needed more operations responsibilities to accommodate new and scale existing applications, so they adopted a shift left culture.&lt;/p&gt;
&lt;p&gt;This led to the developing of a DevOps culture where engineers worked collaboratively with operations to build and deploy high-quality software at scale.&lt;/p&gt;
&lt;p&gt;One of the most critical aspects of our culture was having a no “assholes” attitude, which made it possible for everyone to work together harmoniously towards a common goal.&lt;/p&gt;
&lt;p&gt;There was no gatekeeping, and teams were encouraged to experiment and try new things without permission, creating an environment of trust and empowerment.&lt;/p&gt;
&lt;p&gt;In addition, teams were encouraged to find solutions to their use cases and problems rather than adopting a one-size-fits-all approach, ultimately leading to better outcomes.&lt;/p&gt;
&lt;h2 id=&quot;migrating-to-kubernetes&quot;&gt;Migrating to Kubernetes&lt;/h2&gt;
&lt;p&gt;To foster this new culture, our engineers and operations teams worked closely to migrate the first application to run in Kubernetes.&lt;/p&gt;
&lt;p&gt;While the operations team set constraints, such as structuring environment variables and capturing metrics in Prometheus and dashboards in Grafana, they did not dictate solutions to the engineering teams.&lt;/p&gt;
&lt;p&gt;Keeping things simple, easy and consistent was crucial to our success.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Collaboration to create predefined templates for services, deployment, and ingress files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A folder called’ infrastructure’ in the root directory was all that was required for a Node.js application to run in Kubernetes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Infrastructure as code was in the same repository as the application source code, making continuous integration and delivery easy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;experimentation-and-innovation&quot;&gt;Experimentation and Innovation&lt;/h2&gt;
&lt;p&gt;Teams were encouraged to innovate, create, and explore. Our team was the first in the company to have feature branch previews, allowing product owners, testers and stakeholders to be agile and use features earlier in the development process.&lt;/p&gt;
&lt;p&gt;In addition, we streamlined our deployment process to have zero downtime between deployments and automatic rollbacks if errors were detected.&lt;/p&gt;
&lt;p&gt;Following the principle of “you build it, you own it”, teams were responsible for ensuring they had enough logging and instrumentation to diagnose bugs and performance issues.&lt;/p&gt;
&lt;p&gt;Operations did not intrude on teams but made themselves available for guidance and support. This helped teams be more productive as they didn’t need an embedded ops person, and we were fortunate enough to have curious engineers who wanted to learn and tech.&lt;/p&gt;
&lt;p&gt;Teams would get together to share their learning and adopt each other’s practices, which helped raise the bar in what we accomplished and our SRE skills and knowledge.&lt;/p&gt;
&lt;h2 id=&quot;the-outcome-of-adopting-a-shift-left-culture&quot;&gt;The outcome of adopting a shift left culture&lt;/h2&gt;
&lt;p&gt;Cambridge University Press’s adoption of a shift left culture had significant benefits.&lt;/p&gt;
&lt;p&gt;Within a few months of starting the initiative, we migrated applications to serve traffic from production Kubernetes clusters.&lt;/p&gt;
&lt;p&gt;By empowering engineers with more operations responsibilities and promoting a culture of experimentation and innovation, they could build and deploy high-quality software at scale collaboratively with the operations team.&lt;/p&gt;
&lt;p&gt;The migration to Kubernetes was a critical milestone in this journey. Within a few months of starting the initiative, we migrated applications to serve traffic from production Kubernetes clusters.&lt;/p&gt;
&lt;p&gt;The simplicity, consistency and ease of deployment made it possible for new applications to be Kubernetes-first.&lt;/p&gt;
&lt;p&gt;The benefits of this approach were improved team collaboration, faster time-to-market, increased reliability, reduced downtime and streamlined deployment processes. This approach also helped save costs while maintaining high-quality services for its users.&lt;/p&gt;
&lt;p&gt;Ultimately, Cambridge University Press’s shift left culture allowed them to stay ahead of the curve and respond more quickly to changing market needs.&lt;/p&gt;
</content:encoded></item><item><title>Pino Redaction&apos; A Simple Solution to Secure Logging in Node.js Applications</title><link>https://arrangeactassert.com/posts/pino-redaction-a-simple-solution-to-secure-logging-in-node-js-applications/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/pino-redaction-a-simple-solution-to-secure-logging-in-node-js-applications/</guid><pubDate>Wed, 22 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;a href=&quot;https://getpino.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Pino&lt;/a&gt; is a popular and fast Node.js logging library that is designed for high-performance and low-overhead logging. It has many useful features, including support for structured logging, log levels, and log redaction.&lt;/p&gt;
&lt;p&gt;Pino logging redaction allows you easily redact sensitive information logs, ensuring applications remain secure and compliant with regulations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//live.staticflickr.com/4134/5395824766_09edf7556f_o_d.jpg&quot; alt=&quot;redacted text&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://www.flickr.com/photos/newspaperclub/&quot;&gt;Newspaper Club&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;In this post, we’ll take a closer look at Pino logging redaction functionality, what it is, and how it can be used with examples.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;what-is-pino-logging-redaction&quot;&gt;What is Pino logging redaction?&lt;/h2&gt;
&lt;p&gt;Pino logging redaction is a feature that allows you to mask or remove sensitive data such as passwords, access tokens, or credit card numbers from logs. Redacting this data can help to protect it from unauthorized access, reduce the risk of data breaches and ensure compliance with things like GDPR.&lt;/p&gt;
&lt;p&gt;Pino provides a simple way to configure redaction in your logs. You can use the redact option to define a list of properties that should be redacted from your logs. You can also specify a replacement value for the redacted properties, which is useful when you need to keep some information but want to mask certain parts.&lt;/p&gt;
&lt;h2 id=&quot;examples-of-pino-logging-redaction&quot;&gt;Examples of Pino logging redaction&lt;/h2&gt;
&lt;p&gt;Let’s take a look at some examples of how to use Pino logging redaction.&lt;/p&gt;
&lt;h3 id=&quot;redacting-a-single-property&quot;&gt;Redacting a single property&lt;/h3&gt;
&lt;p&gt;Suppose you have a log entry that contains a password field. You want to redact the password from the log. Here’s how you can do it:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino-pretty&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  redact&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;myPassword123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    payment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      card&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1234-5678-1234-5678&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        issuer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Visa&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Log message&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which outputs:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[19:00:28.282] INFO (7132): Log message
    password: &quot;[Redacted]&quot;
    payment: {
      &quot;card&quot;: {
        &quot;number&quot;: &quot;1234-5678-1234-5678&quot;,
        &quot;issuer&quot;: &quot;Visa&quot;
      }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;redacting-nested-properties&quot;&gt;Redacting nested properties&lt;/h3&gt;
&lt;p&gt;Sometimes, you may need to redact multiple properties from your logs. Here’s an example that redacts a credit card number property from the log output.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino-pretty&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  redact&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment.card.number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;myPassword123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    payment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      card&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1234-5678-1234-5678&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        issuer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Visa&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Log message&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which outputs:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[19:00:28.282] INFO (7132): Log message
    password: &quot;[Redacted]&quot;
    payment: {
      &quot;card&quot;: {
        &quot;number&quot;: &quot;[Redacted]&quot;,
        &quot;issuer&quot;: &quot;Visa&quot;
      }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;using-the-censor-property&quot;&gt;Using the &lt;code&gt;censor&lt;/code&gt; property&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code&gt;censor&lt;/code&gt; property to control how information is redacted.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino-pretty&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  redact&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    paths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment.card.number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    censor&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;🤫&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;myPassword123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    payment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      card&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1234-5678-1234-5678&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        issuer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Visa&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Log message&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which outputs:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[19:00:28.282] INFO (7132): Log message
    password: &quot;🤫&quot;
    payment: {
      &quot;card&quot;: {
        &quot;number&quot;: &quot;🤫&quot;,
        &quot;issuer&quot;: &quot;Visa&quot;
      }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;removing-sensitive-data&quot;&gt;Removing sensitive data&lt;/h3&gt;
&lt;p&gt;Sometimes you may want to remove sensitive data from your logs altogether. You can do this by setting the &lt;code&gt;remove&lt;/code&gt; property to true.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino-pretty&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  redact&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    paths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;payment.card.number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    remove&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;myPassword123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    payment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      card&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1234-5678-1234-5678&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        issuer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Visa&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Log message&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which outputs:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; data-language=&quot;text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[19:00:28.282] INFO (7132): Log message
    payment: {
      &quot;card&quot;: {
        &quot;issuer&quot;: &quot;Visa&quot;
      }
    }&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Don&apos;t repeat yourself: Why you should use child loggers in Node.js</title><link>https://arrangeactassert.com/posts/dont-repeat-yourself-why-you-should-use-child-loggers-in-nodejs/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/dont-repeat-yourself-why-you-should-use-child-loggers-in-nodejs/</guid><pubDate>Mon, 20 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Logging is an essential part of any application, providing insight into the what’s happening behind the scenes. However, as your codebase grows, it can be challenging to keep track of all the different log statements and where they’re coming from. This is where child loggers come in.&lt;/p&gt;
&lt;p&gt;Child loggers are a feature of many of the Node.js logging libraries such as &lt;a href=&quot;https://getpino.io/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Pino&lt;/a&gt;, &lt;a href=&quot;https://github.com/trentm/node-bunyan&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bunyan&lt;/a&gt; and &lt;a href=&quot;https://github.com/winstonjs/winston&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;winston&lt;/a&gt; have that allow you to create a new logger that inherits the configuration of its parent logger.&lt;/p&gt;
&lt;p&gt;This means you can create child loggers that are pre-configured with specific options, making it easier to log messages without repeating the same configuration over and over again.&lt;/p&gt;
&lt;p&gt;In this blog post, we’ll take a look at an example of how child loggers can help cut down on repetition in TypeScript and Pino.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;In this example, we have a function handleRequest that handles an incoming HTTP request. We extract the x-request-id and x-user-id headers from the request and use them as context for our log statements.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino-pretty&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requestId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-request-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-user-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; requestId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Handling request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; requestId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Processing request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; requestId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Finished handling request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; req &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;x-request-id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;x-user-id&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;456&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;handleRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see the in the code above we’re repeating the same details on every log line. This can make the code harder to read and maintain, and it also means that we have to remember to include the same details on every log line.&lt;/p&gt;
&lt;p&gt;The log output looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;[19:40:01.825] INFO (73183): Handling request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;
[19:40:01.825] INFO (73183): Processing request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;
[19:40:01.825] INFO (73183): Finished handling request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;using-child-loggers-to-simplify-logging&quot;&gt;Using Child Loggers to Simplify Logging&lt;/h2&gt;
&lt;p&gt;Using a child logger, we can simplify this code and make it easier to read and maintain. Here’s an example of how we could refactor the code to use a child logger:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pino &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;pino&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; logger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pino&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  prettyPrint&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requestId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-request-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-user-id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/*
  Next, we create a child logger using logger.child({ requestId, userId }).
  
  This child logger inherits all the settings of the parent logger,
  and also includes the requestId and userId as context.   
  */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; childLogger &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; requestId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/*
  We then use the child logger to log additional messages, which automatically
  include the context provided at creation time.
  */&lt;/span&gt;

  childLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Starting to handle request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  childLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Processing request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  childLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Finished handling request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The log output looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;[19:40:01.263] INFO (73809): Starting to handle request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;
[19:40:01.263] INFO (73809): Processing request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;
[19:40:01.263] INFO (73809): Finished handling request
    requestId: &quot;123&quot;
    userId: &quot;456&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the code above shows using a child logger in this way provides several benefits over repeating the same details on every log line e.g.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; data-language=&quot;ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; requestId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Processing request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// vs.&lt;/span&gt;
childLogger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Processing request&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, it reduces the amount of code required to log context, making the code more concise and easier to read.&lt;/p&gt;
&lt;p&gt;Second, it ensures that all log statements for a particular request include the same context, which can be helpful for debugging.&lt;/p&gt;
&lt;p&gt;Finally, it allows you to easily add or remove context as needed without modifying all of your log statements.&lt;/p&gt;
&lt;h2 id=&quot;give-them-a-try&quot;&gt;Give them a try&lt;/h2&gt;
&lt;p&gt;If you’re not already using child loggers in your code, give them a try! They can make a big difference in the readability and maintainability of your logging code.&lt;/p&gt;
&lt;p&gt;Child loggers are not only the future of efficient logging, but they also remind us that even in code, children are the future.&lt;/p&gt;
</content:encoded></item><item><title>Data-Driven vs Assumptions : Why Engineers Should Take a Doctor&apos;s Approach</title><link>https://arrangeactassert.com/posts/data-driven-vs-assumptions/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/data-driven-vs-assumptions/</guid><pubDate>Fri, 10 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Engineers are responsible for designing and building complex systems that are expected to perform optimally under different conditions. However, without a deep understanding of how these systems behave, they risk making assumptions that can result in inefficiencies or even system failures.&lt;/p&gt;
&lt;p&gt;In this post, we’ll discuss why understanding a system like a doctor helping a patient is essential for engineers and by taking a proactive and data-driven approach, engineers can ensure that their systems are performing optimally and can make informed decisions that result in improved performance and reliability.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1585842378054-ee2e52f94ba2?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1932&amp;amp;q=80&quot; alt=&quot;doctor talking to patient&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@zvessels55&quot;&gt;Zach Vessels&lt;/a&gt;
&lt;/div&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Just like a doctor diagnosing a patient, engineers must take a proactive approach to understand the behaviour of their systems. This can involve various techniques such as logging, tracing, and metrics collection. By collecting this information, engineers can gain insight into the performance and behaviour of their systems, reducing the number of assumptions and unknowns.&lt;/p&gt;
&lt;p&gt;For example, if an engineer notices that a system is running slow, they
may assume that it is due to a lack of computing resources. However, upon further investigation through logging and tracing, they may discover that the slow performance is actually due to a bottleneck in the network or an issue with the database.&lt;/p&gt;
&lt;p&gt;By taking a logging, tracing, and metrics approach, engineers can avoid making incorrect assumptions and make data-driven decisions that result in more effective and efficient systems. In addition, they can identify and resolve performance bottlenecks, detect and debug errors, and monitor system behaviour over time.&lt;/p&gt;
&lt;p&gt;In the next post we’ll discuss why this is essential for engineers to be able to give accurate estimations.&lt;/p&gt;
</content:encoded></item><item><title>Why Engineers Should Try to Reproduce Production Issues Locally</title><link>https://arrangeactassert.com/posts/why-engineers-need-to-reproduce-production-bugs-locally/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/why-engineers-need-to-reproduce-production-bugs-locally/</guid><pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;As engineers, one of our primary responsibilities is to ensure that the systems we build are stable and reliable.&lt;/p&gt;
&lt;p&gt;However, despite our best efforts, issues and issues will inevitably arise in production environments. When this happens, it can be tempting to try and patch the problem and move on quickly.&lt;/p&gt;
&lt;p&gt;However, recreating production issues locally is a critical step in the debugging and resolution process.&lt;/p&gt;
&lt;p&gt;In this post, I’ll explain the benefits of reproducing production issues locally.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1517524206127-48bbd363f3d7?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1674&amp;amp;q=80&quot; alt=&quot;engineering examining an engine&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@aahubs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Aaron Huber &lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/iuuJC_pjLU0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
&lt;/div&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;controlled-environment&quot;&gt;Controlled environment&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1532187863486-abf9dbad1b69?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1740&amp;amp;q=80&quot; alt=&quot;purple pipette&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the main benefits of recreating production issues locally is that it allows us to reproduce the issue in a controlled environment.&lt;/p&gt;
&lt;p&gt;By doing so, we can more easily isolate and identify the root cause of the problem. Trying to do this is much more challenging when the issue is only present in a production environment where many other factors are at play.&lt;/p&gt;
&lt;h2 id=&quot;validate-resolutions&quot;&gt;Validate Resolutions&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1530497610245-94d3c16cda28?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1364&amp;amp;q=80&quot; alt=&quot;problem fixed&quot;&gt;&lt;/p&gt;
&lt;p&gt;Recreating production issues locally allows us to test and validate any proposed fixes before deploying them. This is essential for preventing regressions and ensuring the fix resolves the issue. Recreating the issue locally can also help identify and resolve other problems that may have been overlooked.&lt;/p&gt;
&lt;h2 id=&quot;insights-into-the-system&quot;&gt;Insights into the system&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1615906655593-ad0386982a0f?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=987&amp;amp;q=80&quot; alt=&quot;mechanic&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another benefit of recreating production issues locally is that it can help improve our understanding of the system. By closely examining the issue, we can gain valuable insights into how the various components of the system interact, which can help us prevent similar problems from arising.&lt;/p&gt;
&lt;h2 id=&quot;improve-communication-and-collaboration&quot;&gt;Improve communication and collaboration&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1581092333322-31d2fd38a35e?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1740&amp;amp;q=80&quot; alt=&quot;team working together&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@thisisengineering&quot;&gt;thisisengineering&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I’ve also found recreating production bugs locally has helped improve the engineering team’s communication and collaboration. By working together to reproduce and resolve the issue, we shared knowledge and learnt from one another, which helped improve the team’s morale and motivation.&lt;/p&gt;
&lt;h2 id=&quot;is-it-necessary-to-reproduce-every-defect-before-identifying-and-fixing-it&quot;&gt;Is it necessary to reproduce every defect before identifying and fixing it?&lt;/h2&gt;
&lt;p&gt;Of course, not every issue will be reproducible locally because of certain complex conditions and environments, but engineers should at least try to do so. An example of these situations could be the hardware the software is running on, extensions the users’ browser has installed or, as I once encountered, how users within China had a different experience of network conditions from those outside when connecting to an AWS instance within a Chinese region.&lt;/p&gt;
&lt;p&gt;When teams cannot reproduce issues locally, then teams and businesses are put into a position where they have to decide if blind patches are a good idea and will not make a situation worse. One position you don’t want to find yourself in is looking for something similar with the same consequence but a different root cause. Adding more instrumentation can help to prevent this.&lt;/p&gt;
&lt;p&gt;Then, of course, are the pressures on engineering teams to produce a &lt;em&gt;fix&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;These pressures could be internal, from management wanting to see action, or external, to calm down an angry customer.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Engineers should attempt to recreate production bugs to improve reliability and stability of software and not damage the company’s credibility or reputation.&lt;/p&gt;
&lt;p&gt;One of the best ways of recreating production issues locally is by tests, which I’ll discuss in the next post.&lt;/p&gt;
</content:encoded></item><item><title>Documentation isn&apos;t why your onboarding sucks</title><link>https://arrangeactassert.com/posts/documentation-is-not-why-your-onboarding-sucks/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/documentation-is-not-why-your-onboarding-sucks/</guid><pubDate>Tue, 29 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Some organisations have great onboarding processes, others not so much.&lt;/p&gt;
&lt;p&gt;Having experienced onboarding with many clients over the years, I want to share what a good onboarding process is for an engineer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1526933970935-5b59e720c628?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=2338&amp;amp;q=80&quot; alt=&quot;person onborading a place&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@erwanhesry?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Erwan Hesry&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/onboarding?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
&lt;/div&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why-it-matters&quot;&gt;Why it matters?&lt;/h2&gt;
&lt;p&gt;Onboarding is the first impression a new employee has of your company. It’s the first time they get to see how you work, how you communicate, how you solve problems and how you treat your employees.&lt;/p&gt;
&lt;p&gt;A new employee will form an opinion of your company based on their onboarding experience. If it’s a good experience, they will be more likely to stay with your company. If it’s a bad experience, they will be more likely to leave.&lt;/p&gt;
&lt;p&gt;I know when starting with a new client, imposter syndrome kicks in. The faster I feel like I’m adding value, the more confident I can be about doing the job and if I’m going to be able to fit in.&lt;/p&gt;
&lt;h2 id=&quot;do-it-yourself&quot;&gt;Do it yourself&lt;/h2&gt;
&lt;p&gt;Being told there isn’t any documentation and that you should write it yourself as you learn doesn’t work. It’s a terrible idea and a waste of time, as you’ll be writing without knowing the rationale, or constraints the team had when making decisions.&lt;/p&gt;
&lt;p&gt;More often than not, the fact you are writing the documentation yourself means you may struggle to help find people to answer the questions you will be asking.&lt;/p&gt;
&lt;h2 id=&quot;needle-in-a-haystack&quot;&gt;Needle in a haystack&lt;/h2&gt;
&lt;p&gt;Reading outdated confluence pages can be very frustrating because, in my experience, the author didn’t write with the intent to take the reader on a journey. So if the pages don’t follow a structure or are organised in a way to understand what to do or where to go next, you may end up reading endless amounts of irrelevant information and feeling lost.&lt;/p&gt;
&lt;div class=&quot;tenor-gif-embed&quot; data-postid=&quot;20286748&quot; data-share-method=&quot;host&quot; data-aspect-ratio=&quot;1.77778&quot; data-width=&quot;100%&quot;&gt;&lt;a href=&quot;https://tenor.com/view/the-weeknd-super-bowl-half-time-show-searching-looking-for-gif-20286748&quot;&gt;The Weeknd Super Bowl GIF&lt;/a&gt;from &lt;a href=&quot;https://tenor.com/search/the+weeknd-gifs&quot;&gt;The Weeknd GIFs&lt;/a&gt;&lt;/div&gt; &lt;script type=&quot;text/javascript&quot; async src=&quot;https://tenor.com/embed.js&quot;&gt;&lt;/script&gt;
&lt;h2 id=&quot;jira-tickets&quot;&gt;Jira Tickets&lt;/h2&gt;
&lt;p&gt;Trying to learn by piecing together Jira tickets as an onboarding exercise can also be futile. With similar problems to reading confluence pages, there’s no way to know if a ticket is still relevant and have any confidence the actual implementation accurately reflects the acceptance criteria.&lt;/p&gt;
&lt;h2 id=&quot;self-documented-code&quot;&gt;Self-documented code&lt;/h2&gt;
&lt;p&gt;No doubt you’ve heard the saying write once, read many times. Reading code might work in simple cases, and it can be an excellent way to understand some of the team’s standards and how to structure and organise code. However, it doesn’t help explain the why behind the implementation. In addition, it doesn’t give information on what role the code plays in the organisation’s architecture.&lt;/p&gt;
&lt;h2 id=&quot;unit-tests&quot;&gt;Unit tests&lt;/h2&gt;
&lt;p&gt;Unit tests ensure code works in a particular way under various conditions. So while they could help with learning, they won’t have written in an onboarding friendly way.&lt;/p&gt;
&lt;h2 id=&quot;end-to-end-tests&quot;&gt;End-to-end tests&lt;/h2&gt;
&lt;p&gt;End-to-end tests can be helpful when written in collaboration with people who understand the business needs, such as product owners. Then especially in the form of specifications, they can be relied upon to act as a data source to understand product requirements. However, this won’t help in understanding the role this plays in the grand scheme of things or the product vision.&lt;/p&gt;
&lt;h2 id=&quot;pairing&quot;&gt;Pairing&lt;/h2&gt;
&lt;p&gt;Pairing is a great way to onboard a new team member.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1581091870598-36ce9bad5c77?ixlib=rb-4.0.3&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=2370&amp;amp;q=80&quot; alt=&quot;pairing&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;text-xs text-gray-500 -mt-8 text-left&quot;&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@thisisengineering?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;ThisisEngineering RAEng&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/office?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;This doesn’t mean hand-holding through the codebase, but it does mean explaining the problem and the implemented solution.&lt;/p&gt;
&lt;p&gt;It’s also a great way to get to know your new team member and for them to get to know you.&lt;/p&gt;
&lt;p&gt;Depending on their experience, your ability to communicate, how fast they learn and the complexity of your code base and architecture, you may need to pair for a few days or a few weeks.&lt;/p&gt;
&lt;p&gt;There should be breaks to work independently, so they can get a feel for the codebase and the problem they are solving.&lt;/p&gt;
&lt;h2 id=&quot;onboarding-shouldnt-just-be-with-engineers&quot;&gt;Onboarding shouldn’t just be with engineers&lt;/h2&gt;
&lt;p&gt;New team members should spend time understanding the product and expected outcomes with product owners and stakeholders. Otherwise, they may find it difficult, if not impossible, to understand the vision, value and purpose of the work the team are doing.&lt;/p&gt;
&lt;p&gt;Domain experts should be involved in the onboarding process as they can educate and provide guidance on domain boundaries, events, and business rules within the organisation using a ubiquitous (vocabulary shared by everyone involved in a project) language.&lt;/p&gt;
&lt;p&gt;If anyone in your organisation knows rather than thinks how things work, it will be testers. Testers should be able to take you through various scenarios to show the rules and constraints of an application. So while product owners can describe a feature using a user story, testers should be able to verify and demonstrate the implementation of that feature.&lt;/p&gt;
&lt;h2 id=&quot;so-what-is-a-good-onboarding-process&quot;&gt;So, what is a good onboarding process?&lt;/h2&gt;
&lt;p&gt;There isn’t a silver bullet of doing just one thing for a great onboarding process.&lt;/p&gt;
&lt;p&gt;A good onboarding process will be a combination of things, but without a doubt, team culture and collaboration are crucial components of a great onboarding process.&lt;/p&gt;
&lt;p&gt;While collaboration may slow down productivity in the short term, the team will be more productive in the long term, with all team members understanding the “why” and how they can make valuable contributions.&lt;/p&gt;
</content:encoded></item><item><title>Teams should communicate like a team fielding in cricket</title><link>https://arrangeactassert.com/posts/teams-should-communicate-like-a-team-fielding-in-cricket/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/teams-should-communicate-like-a-team-fielding-in-cricket/</guid><pubDate>Tue, 08 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;When working with clients, how teams communicate tells me more about the culture than anything else.&lt;/p&gt;
&lt;p&gt;Successful teams should communicate like a team fielding in a game of cricket who work together towards the same goal giving each other support and encouragement.&lt;/p&gt;
&lt;p&gt;By sharing information about the batters, pitch, conditions and strategy, a feilding team agree on a plan on how to bowl and position themselves.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//visualhunt.com/photos/22/cricket-fielding.jpg&quot; alt=&quot;Teams playing cricket&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;public-vs-private-communication&quot;&gt;Public vs Private communication&lt;/h2&gt;
&lt;p&gt;A team that trusts one another will use public channels more than private channels.&lt;/p&gt;
&lt;p&gt;A team using public channels to communicate honestly and openly can share knowledge and learn from each other.&lt;/p&gt;
&lt;p&gt;Communication in public channels helps a team’s agility by having a shorter feedback loop. They can inspect and adapt without waiting for a retrospective. As a result, some client teams found they didn’t need retrospectives.&lt;/p&gt;
&lt;p&gt;All team members should be able to ensure psychological safety and call out others when they are not adhering to a code of conduct.&lt;/p&gt;
&lt;p&gt;When unable to do so, teams will use private channels to communicate. The lack of transparency and knowledge sharing results in less coordination, efficiency and performance.&lt;/p&gt;
&lt;h2 id=&quot;more-meetings-more-problems&quot;&gt;More meetings, More problems&lt;/h2&gt;
&lt;p&gt;Teams with private channels will have many more meetings than those who communicate over public channels. Ineffective meetings waste a lot of time, energy and effort and often lead to complaints about not having enough time to get work done.&lt;/p&gt;
&lt;h2 id=&quot;effective-vs-ineffective-communication&quot;&gt;Effective vs Ineffective communication&lt;/h2&gt;
&lt;p&gt;The way teams communicate is a reflection of the culture of the team. The culture of the team is a reflection of the leadership of the team. The team’s leadership is a reflection of the organisation’s culture.&lt;/p&gt;
&lt;p&gt;When everyone can contribute to the conversation, there is a greater sense of ownership, responsibility and healthy team spirit.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/fosslien&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Liz Fosslien&lt;/a&gt; perfectly illustrated this&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;zxx&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://t.co/fVr5fPJlR5&quot;&gt;pic.twitter.com/fVr5fPJlR5&lt;/a&gt;&lt;/p&gt;&amp;mdash; Liz Fosslien (@fosslien) &lt;a href=&quot;https://twitter.com/fosslien/status/1571943371165569025?ref_src=twsrc%5Etfw&quot;&gt;September 19, 2022&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;When one person dominates a conversation, teams struggle to communicate when that person isn’t present. Therefore, it’s crucial that team members can facilitate discussions to have meetings with diverse views and outcomes.&lt;/p&gt;
&lt;h2 id=&quot;communication-leads-to-success&quot;&gt;Communication leads to success&lt;/h2&gt;
&lt;p&gt;Many great cricketing sides highlight how communication was crucial to their success.&lt;/p&gt;
&lt;p&gt;Before 2003, the Indian Cricket team had many talented individuals who hadn’t fulfilled their potential.&lt;/p&gt;
&lt;p&gt;During the World Cup in 2003, the team did something different.&lt;/p&gt;
&lt;p&gt;India changed how they played and communicated by sharing knowledge of the conditions and the opposition to their advantage. &lt;a href=&quot;https://www.sportskeeda.com/cricket/sourav-ganguly-s-team-india-men-in-blue-s-journey-2003-world-cup&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“The Great Indian Huddle”&lt;/a&gt; symbolised the change in team spirit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//media.gettyimages.com/id/1858097/photo/indian-cricket-team-in-a-huddle.jpg?s=2048x2048&amp;amp;w=gi&amp;amp;k=20&amp;amp;c=B7VPCQOhBwic2QHevWW9Q5TXct1YSP9XUeF2HZFHrow=&quot; alt=&quot;Indian Cricket Team 2003&quot;&gt;&lt;/p&gt;
&lt;p&gt;India went on to win their first World Cup.&lt;/p&gt;
&lt;p&gt;Product teams can show the same level of success when they communicate effectively.&lt;/p&gt;
&lt;p&gt;Organisations should provide training for them to be able to do so.&lt;/p&gt;
&lt;footer class=&quot;attribution&quot;&gt;
&lt;p&gt;Photo credit: &lt;a href=&quot;https://visualhunt.co/a7/0042ae87&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eltpics&lt;/a&gt; on &lt;a href=&quot;https://visualhunt.com/re10/5a780da1&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;VisualHunt&lt;/a&gt; and &lt;a href=&quot;https://www.gettyimages.co.uk/detail/photo/indian-cricket-team-in-a-huddle-royalty-free-image/1858097&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Getty Images&lt;/a&gt;&lt;/p&gt;
&lt;/footer&gt;
</content:encoded></item><item><title>Facilitation is an art</title><link>https://arrangeactassert.com/posts/facilitation-is-an-art/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/facilitation-is-an-art/</guid><pubDate>Wed, 15 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;A good facilitator seamlessly keeps the flow of conversations fluent and relevant, encouraging people to engage and have equal participation while remaining impartial and patient.&lt;/p&gt;
&lt;p&gt;It’s a role similar to a conductor orchestrating a choir.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com//images.unsplash.com/photo-1593574239502-64f0b64ba1e4?ixlib=rb-1.2.1&amp;amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=2070&amp;amp;q=80&quot; alt=&quot;conductor orchestrating a choir&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;In the development world, a scrum master often performs the facilitation role in agile ceremonies.&lt;/p&gt;
&lt;p&gt;Having worked with many clients over the years, I’ve realised that scrum masters who excelled in facilitation played a crucial role in how teams learnt to trust, build relationships, communicate, organise, coordinate and work together. They allowed product owners, developers, designers, and testers to do what they do best and deliver value.&lt;/p&gt;
&lt;p&gt;These facilitators were passionate about their art. For them, it’s a lifelong journey to improve and adapt their skills by learning and working with different teams at start-ups and enterprises in various industries.&lt;/p&gt;
&lt;p&gt;However, just like a lousy conductor could ruin a concert, a bad facilitator can have severe consequences for teams and companies.&lt;/p&gt;
&lt;p&gt;I’ve sat through many ceremonies where people did not contribute because of fear or not having the opportunity to do so. The facilitator didn’t have the training or skills to intervene or, worst still, hasn’t even realised.&lt;/p&gt;
&lt;p&gt;Facilitators know how to adapt. Instead of sticking to broken ideals and rituals, they work to resolve and improve by collaborating with others to do what’s best for them as a team and reach an outcome they would jointly like to achieve.&lt;/p&gt;
&lt;p&gt;The simple fact is while anyone can facilitate, not everyone is, can or will be a great facilitator.&lt;/p&gt;
</content:encoded></item><item><title>Creating An Animation Sequence Using Framer Motion</title><link>https://arrangeactassert.com/posts/creating-an-animation-sequence-using-framer-motion/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/creating-an-animation-sequence-using-framer-motion/</guid><pubDate>Tue, 01 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;a href=&quot;https://www.framer.com/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Framer Motion&lt;/a&gt; makes creating a sequence of animations easy.&lt;/p&gt;
&lt;p&gt;In this example, we will create a React component that animates a circle in the center of three boxes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com/static/gifs/framer-animation-sequence.gif&quot; alt=&quot;framer animation sequence&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;This works by finding the bounding rectangle of each box. As we’re using React a ref. Which is created like this&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot; data-language=&quot;tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box1Ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLDivElement&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and used as follows&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot; data-language=&quot;tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;w-20 h-20 border-2 border-purple-800 bg-purple-300&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{box1Ref}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a reference to the element the calling &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;getBoundingClientRect&lt;/a&gt; provides us with position and size properties.&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot; data-language=&quot;tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; domRect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DOMRect &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; box1Ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this information we can to calculate the position where the circle to should move to.&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot; data-language=&quot;tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;calculateCenter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; circle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; box&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can create an animation sequence that moves the circle between the three boxes, which is easy as &lt;a href=&quot;https://www.framer.com/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Framer Motion&lt;/a&gt; returns a promise for animations which is resolved upon when the animation is complete.&lt;/p&gt;
&lt;pre class=&quot;language-tsx&quot; data-language=&quot;tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; circleRect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; circleRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateCenter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  box1Ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  circleRect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateCenter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  box2Ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  circleRect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; box3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateCenter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  box3Ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBoundingClientRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  circleRect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  opacity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  transition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; duration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  transition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; duration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  transition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; duration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; animation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; box3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  transition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; duration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The complete code for the example is available on CodePen&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;600&quot; data-default-tab=&quot;js&quot; data-slug-hash=&quot;NWwOEmo&quot; data-user=&quot;jagreehal&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/jagreehal/pen/NWwOEmo&quot;&gt;
  Untitled&lt;/a&gt; by jagreehal (&lt;a href=&quot;https://codepen.io/jagreehal&quot;&gt;@jagreehal&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;script async src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
</content:encoded></item><item><title>How to prevent deadlock for UI tickets</title><link>https://arrangeactassert.com/posts/how-to-prevent-ui-signoff-deadlock/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-prevent-ui-signoff-deadlock/</guid><pubDate>Wed, 18 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Should you build UI components and then add them to a page or build the page first then break it down into UI components is the chicken and egg of software development?&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;There are many approaches to develop UI components.&lt;/p&gt;
&lt;p&gt;One of the aims of breaking a UI into components is to have reusability.&lt;/p&gt;
&lt;p&gt;Reusable components enable companies to provide users with a consistent user experience and avoid the cost and time of solving the same problem over and over.&lt;/p&gt;
&lt;p&gt;So how should a company break down the work of creating a user interface? In my opinion, the question should be how can we verify that independent components are working correctly.&lt;/p&gt;
&lt;p&gt;The answer to that is, it depends :)… but in my experience, you’ll want to end up with a suite of UI components.&lt;/p&gt;
&lt;h3 id=&quot;cant-see-the-wood-for-the-trees&quot;&gt;Can’t see the wood for the trees&lt;/h3&gt;
&lt;p&gt;I’ve seen so many teams getting into the trap of only verifying a component is working when used within a page. In that case, there will be a higher chance of ticket deadlock as neither the component ticket nor the page ticket can’t progress because it’s hard, if not impossible, what is or isn’t working.&lt;/p&gt;
&lt;h3 id=&quot;component-driven-design-ftw&quot;&gt;Component driven design FTW&lt;/h3&gt;
&lt;p&gt;Component driven design allows teams to use composition to develop pages while allowing for variations for how the component would behave in various states, such as empty states.&lt;/p&gt;
</content:encoded></item><item><title>Why great products need strong foundations</title><link>https://arrangeactassert.com/posts/why-great-products-need-strong-foundations/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/why-great-products-need-strong-foundations/</guid><pubDate>Wed, 12 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;You’ve probably heard someone quote Norm Kerths’ &lt;a href=&quot;https://retrospectivewiki.org/index.php?title=The_Prime_Directive&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Prime Directive&lt;/a&gt; during a retrospective&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my experience, engineering teams doing their best at that time inevitably end up having to shoehorn features as requirements change or new information becomes available.&lt;/p&gt;
&lt;p&gt;In this post, I’ll discuss why great products need strong foundations.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;a-solid-product-foundation&quot;&gt;A solid product foundation&lt;/h2&gt;
&lt;p&gt;A solid product foundation can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;influence-an-engineering-teams-morale&quot;&gt;influence an engineering teams morale&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A poorly architected product can kill any motivation for innovation as there will be a significant amount of effort required to make improvements. Engineers may choose the easiest rather than the right thing to do.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;impact-extensibility-maintainability-and-stability-of-the-product&quot;&gt;impact extensibility, maintainability and stability of the product&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a team has to accommodate changes that don’t fit existing patterns, conventions and standards, the harder it will be to keep things simple, consistent or easy to follow.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;allow-for-more-accurate-estimations&quot;&gt;allow for more accurate estimations&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more complex a product architecture, the less accurate the estimation becomes as it is harder to know the side effects of changes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&quot;effect-the-organisations-ability-to-adapt-to-the-market-in-the-long-run&quot;&gt;effect the organisations’ ability to adapt to the market in the long run&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a team cannot release confidently, the business will find it hard to adapt to the market or user needs.&lt;/p&gt;
&lt;h2 id=&quot;this-is-more-than-technical-debt&quot;&gt;This is more than technical debt&lt;/h2&gt;
&lt;p&gt;I’ve used this shopping bag analogy with clients I’ve worked with.&lt;/p&gt;
&lt;p&gt;To begin with, you take a shopping bag to the shops to pick up two orders placed by your partner. At the counter, a staff member gives you the first order containing three things you put into the bag.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Three items in a bag&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 427px) 427px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;427&quot; height=&quot;436&quot; src=&quot;https://arrangeactassert.com/_astro/three-items.es5SgV83_Z2BGWj.webp&quot; srcset=&quot;/_astro/three-items.es5SgV83_Z2BGWj.webp 427w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then you are given the second order containing another three items that you also put into the bag.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Six items in a bag&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 427px) 427px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;427&quot; height=&quot;395&quot; src=&quot;https://arrangeactassert.com/_astro/six-items.CRNdnjEg_ZjDW16.webp&quot; srcset=&quot;/_astro/six-items.CRNdnjEg_ZjDW16.webp 427w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Not ideal, but you can live with that.&lt;/p&gt;
&lt;p&gt;Maybe you can take the hit and file it under technical debt.&lt;/p&gt;
&lt;p&gt;The staff member then hands you three additional items that were also in the second order.&lt;/p&gt;
&lt;p&gt;They are awkward to fit into the bag.&lt;/p&gt;
&lt;p&gt;If you’ve had known about the items at the start, you would have organised your bag differently.&lt;/p&gt;
&lt;p&gt;You have two choices.&lt;/p&gt;
&lt;p&gt;You could add the items. However, the cost of doing so means you can’t use the handle making everything you do next awkward and challenging.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nine items in a bag covering handles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 425px) 425px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;425&quot; height=&quot;452&quot; src=&quot;https://arrangeactassert.com/_astro/nine-items-bad.WwQ_q1Hs_YCKAb.webp&quot; srcset=&quot;/_astro/nine-items-bad.WwQ_q1Hs_YCKAb.webp 425w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Or you could take the time to empty your bag and organise things so you can carry them home.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Nine items in a bag fitting nicely&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 429px) 429px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;429&quot; height=&quot;395&quot; src=&quot;https://arrangeactassert.com/_astro/nine-items-good.CbuwQ1GZ_Z6gakY.webp&quot; srcset=&quot;/_astro/nine-items-good.CbuwQ1GZ_Z6gakY.webp 429w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-should-teams-do&quot;&gt;What should teams do?&lt;/h2&gt;
&lt;p&gt;One is a long term win. The other is a short term win for which the consequences are unknown, and the precedent for ‘temporary fixes’ has been set.&lt;/p&gt;
&lt;p&gt;Stakeholders, product managers etc., should trust engineers in what they think is the right thing to do before a complete rewrite is required or it becomes problematic if not impossible to add value to a product.&lt;/p&gt;
</content:encoded></item><item><title>Introducing Code-First GraphQL APIs at Cambridge University Press</title><link>https://arrangeactassert.com/posts/introducing-code-first-graphql-apis-at-cambridge-university-press/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/introducing-code-first-graphql-apis-at-cambridge-university-press/</guid><pubDate>Mon, 22 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Having experienced the pain of schema-first &lt;a href=&quot;https://graphql.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GraphQL&lt;/a&gt; projects, I wanted to use a different approach for a project I led at Cambridge University Press.&lt;/p&gt;
&lt;p&gt;In this post, I’ll describe what I used and how using code-first GraphQL worked out for us.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;div&gt;
&lt;svg aria-hidden=&quot;true&quot; class=&quot;h-64 w-64 float-left pr-12&quot; style=&quot;shape-outside: circle(50%)&quot; viewBox=&quot;0 0 256 288&quot;&gt;
&lt;title&gt;GraphQL logo&lt;/title&gt;
&lt;path d=&quot;M152.576 32.963l59.146 34.15a25.819 25.819 0 015.818-4.604c12.266-7.052 27.912-2.865 35.037 9.402 7.052 12.267 2.865 27.912-9.402 35.037a25.698 25.698 0 01-6.831 2.72v68.325a25.7 25.7 0 016.758 2.702c12.34 7.125 16.527 22.771 9.402 35.038-7.052 12.266-22.771 16.453-35.038 9.402a25.464 25.464 0 01-6.34-5.147l-58.786 33.94a25.671 25.671 0 011.295 8.08c0 14.103-11.458 25.636-25.635 25.636-14.177 0-25.635-11.46-25.635-25.636 0-2.52.362-4.954 1.037-7.253l-59.13-34.14a25.824 25.824 0 01-5.738 4.52c-12.34 7.051-27.986 2.864-35.038-9.402-7.051-12.267-2.864-27.913 9.402-35.038a25.71 25.71 0 016.758-2.703v-68.324a25.698 25.698 0 01-6.831-2.72C.558 99.897-3.629 84.178 3.423 71.911c7.052-12.267 22.77-16.454 35.037-9.402a25.82 25.82 0 015.79 4.575l59.163-34.159a25.707 25.707 0 01-1.048-7.29C102.365 11.46 113.823 0 128 0c14.177 0 25.635 11.459 25.635 25.635 0 2.548-.37 5.007-1.059 7.328zm-6.162 10.522l59.287 34.23a25.599 25.599 0 002.437 19.831c3.609 6.278 9.488 10.44 16.013 12.062v68.41c-.333.081-.664.17-.993.264L145.725 44.17c.234-.224.464-.452.689-.684zm-36.123.7l-77.432 134.11a25.824 25.824 0 00-1.01-.27v-68.417c6.525-1.622 12.404-5.784 16.013-12.062a25.6 25.6 0 002.427-19.869l59.27-34.22c.239.247.483.49.732.727zm24.872 6.075l77.414 134.08a25.492 25.492 0 00-4.513 5.757 25.7 25.7 0 00-2.702 6.758H50.64a25.71 25.71 0 00-2.704-6.758 25.825 25.825 0 00-4.506-5.724l77.429-134.107A25.715 25.715 0 00128 51.27c2.487 0 4.89-.352 7.163-1.01zm11.795 194.478l58.902-34.008a25.865 25.865 0 01-.473-1.682H50.607a25.87 25.87 0 01-.266.992l59.19 34.175A25.558 25.558 0 01128 236.373a25.564 25.564 0 0118.958 8.365z&quot; fill=&quot;#E535AB&quot; fill-rule=&quot;evenodd&quot;/&gt;
&lt;/svg&gt;
&lt;p&gt;In my experience, having a single source of truth makes applications easier to understand, maintain and add features to.&lt;/p&gt;
&lt;p&gt;A common approach when learning GraphQL is to adopt a schema-first approach. The difficulty and complexity of schema-first GraphQL APIs increases as the project and teams grow, as you have to ensure definitions and resolvers are in sync and have to maintain multiple sources of truth.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;code-first-approach-with-nexus&quot;&gt;Code-first approach with Nexus&lt;/h2&gt;
&lt;p&gt;By using a code-first approach with &lt;a href=&quot;https://nexusjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nexus&lt;/a&gt;, we were able to can have have a single source of truth as it will generate a GraphQL schema for you.&lt;/p&gt;
&lt;p&gt;However Nexus does a lot more than saving from mistakes and time of generating a GraphQL scheme manually.&lt;/p&gt;
&lt;p&gt;Thanks to excellent typescript integration Nexus provides a delightful developer experience with lightning-fast feedback.&lt;/p&gt;
&lt;p&gt;The plugin system and extensibility points enabled us to create a GraphQL API that was easy to maintain and extend.&lt;/p&gt;
&lt;h2 id=&quot;how-how-did-nexus-and-code-first-graphql-work-out-for-us&quot;&gt;How how did Nexus and code-first GraphQL work out for us?&lt;/h2&gt;
&lt;p&gt;Having avoided the pitfalls of schema-first, the benefits of a code-first approach to building GraphQL APIs increased our productivity and enabled us to release features quickly knowing everything was in sync.&lt;/p&gt;
&lt;p&gt;Over the next few months, I’ll post examples of how we used Nexus and share what we learned when creating GraphQL APIs.&lt;/p&gt;
</content:encoded></item><item><title>Introducing Tailwind at Cambridge University Press</title><link>https://arrangeactassert.com/posts/introducing-tailwind-at-cambridge-university-press/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/introducing-tailwind-at-cambridge-university-press/</guid><pubDate>Mon, 22 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Having used &lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind&lt;/a&gt; in my personal projects, I was already a convert of the utility first approach. When I was given the opportunity to lead a new project at Cambridge University Press, Tailwind was the first tool I reached for.&lt;/p&gt;
&lt;p&gt;In this post, I’ll discuss why and how using Tailwind worked out for us.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;the-failed-promise-of-css-frameworks&quot;&gt;The failed promise of CSS Frameworks&lt;/h2&gt;
&lt;p&gt;Throughout my career, I witnessed teams struggling to maintain web applications using UI frameworks such as Bootstrap, Foundation and Material UI.&lt;/p&gt;
&lt;p&gt;The initial benefits didn’t last long, and their web applications eventually ended up the same sorry way.&lt;/p&gt;
&lt;p&gt;Productivity slowed as teams struggled to try to make sense of spaghetti codebases unable to deal with yet another specificity war or struggle to update the UI kit they had built upon.&lt;/p&gt;
&lt;h2 id=&quot;teaching-the-team-about-tailwind&quot;&gt;Teaching the team about Tailwind&lt;/h2&gt;
&lt;div&gt;
&lt;img class=&quot;h-48 w-48 float-left pr-12&quot; style=&quot;shape-outside: circle(50%)&quot; src=&quot;https://tailwindcss.com/_next/static/media/tailwindcss-mark.3c5441fc7a190fb1800d4a5c7f07ba4b1345a9c8.svg&quot; alt=&quot;Tailwind logo&quot;/&gt;
&lt;p&gt;As this would be the first project in the organisation to use Tailwind, I wanted to gain my colleagues’ support. Having experienced the pain of using existing solutions, they were open to an alternative approach.&lt;/p&gt;
&lt;p&gt;So I used our developer meetings to explain how and why I planned to use Tailwind.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I’m currently writing up what I presented. In the meantime, this is the link to the &lt;a href=&quot;https://github.com/jagreehal/tailwind-talk&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;repository I created for my Tailwind Talk&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;so-how-did-choosing-tailwind-work-out-for-us&quot;&gt;So how did choosing Tailwind work out for us?&lt;/h2&gt;
&lt;p&gt;The developer experience and low learning curve of Tailwind, made it easy for people to learn it’s just surgery syntax on top of CSS with well thought out conventions.&lt;/p&gt;
&lt;p&gt;By being able to specify constraints in the Tailwind configuration file, it was straightforward for the team to build components that followed brand guidelines.&lt;/p&gt;
&lt;p&gt;It was simpler to understand what was going on in pull requests as we no longer had to match class names in markup and style in separate files, especially for responsive design.&lt;/p&gt;
&lt;p&gt;Using utility classes in template files made collaboration easier with everyone from design to accessibility experts during pairing sessions.&lt;/p&gt;
&lt;p&gt;The site looked incredible and knowing we only shipped the CSS that was actually being used helped us build a performant web application.&lt;/p&gt;
&lt;p&gt;Using Tailwind was a success for the project, and team members loved using it.&lt;/p&gt;
&lt;p&gt;How do I know this? They went on to use it on projects they led.&lt;/p&gt;
</content:encoded></item><item><title>Introducing Typescript at Cambridge University Press</title><link>https://arrangeactassert.com/posts/introducing-typescript-at-cambridge-university-press/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/introducing-typescript-at-cambridge-university-press/</guid><pubDate>Mon, 22 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Having worked with many clients who struggled to maintain Javascript projects, &lt;a href=&quot;https://www.typescriptlang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Typescript&lt;/a&gt; was a no brainer when choosing what to use for the project I was leading.&lt;/p&gt;
&lt;p&gt;In this post, I’ll share what and how I managed the challenges of introducing and using Typescript.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;svg class=&quot;h-48 w-48 float-right pl-12&quot; style=&quot;shape-outside: circle(50%)&quot; viewBox=&quot;0 0 256 256&quot;&gt;
  &lt;title&gt;Typescript logo&lt;/title&gt;
  &lt;path fill=&quot;#007ACC&quot; d=&quot;M0 128v128h256V0H0z&quot;/&gt;
  &lt;path d=&quot;M56.611 128.85l-.081 10.483h33.32v94.68H113.42v-94.68h33.32v-10.28c0-5.69-.122-10.444-.284-10.566-.122-.162-20.399-.244-44.983-.203l-44.739.122-.122 10.443zM206.567 118.108c6.501 1.626 11.459 4.51 16.01 9.224 2.357 2.52 5.851 7.112 6.136 8.209.08.325-11.053 7.802-17.798 11.987-.244.163-1.22-.894-2.317-2.52-3.291-4.794-6.745-6.867-12.028-7.232-7.76-.529-12.759 3.535-12.718 10.32 0 1.992.284 3.17 1.097 4.796 1.707 3.535 4.876 5.648 14.832 9.955 18.326 7.884 26.168 13.085 31.045 20.48 5.445 8.25 6.664 21.415 2.966 31.208-4.063 10.646-14.14 17.88-28.323 20.277-4.388.772-14.79.65-19.504-.203-10.28-1.829-20.033-6.908-26.047-13.572-2.357-2.601-6.949-9.387-6.664-9.875.122-.162 1.178-.812 2.356-1.503 1.138-.65 5.446-3.13 9.509-5.486l7.355-4.267 1.544 2.276c2.154 3.291 6.867 7.802 9.712 9.305 8.167 4.308 19.383 3.698 24.909-1.26 2.357-2.153 3.332-4.388 3.332-7.68 0-2.966-.366-4.266-1.91-6.5-1.99-2.845-6.054-5.243-17.595-10.24-13.206-5.69-18.895-9.225-24.096-14.833-3.007-3.25-5.852-8.452-7.03-12.8-.975-3.616-1.22-12.678-.447-16.335 2.723-12.76 12.353-21.658 26.25-24.3 4.51-.853 14.994-.528 19.424.57z&quot; fill=&quot;#FFF&quot;/&gt;
&lt;/svg&gt;
&lt;p&gt;While Typescript adoption grew, I was always surprised how many of my clients chose not to use it.&lt;/p&gt;
&lt;p&gt;Some firmly held the view Javascript “wasn’t Java” and shouldn’t be typed, others said their projects were simple and wouldn’t benefit from strong typing.&lt;/p&gt;
&lt;p&gt;Those who understood the benefits didn’t know they could adopt Typescript incrementally without rewriting everything in one go.&lt;/p&gt;
&lt;p&gt;To convince my clients the benefits of Typescript was more than type safety, I presented a talk based on “Making Impossible States Impossible” by &lt;a href=&quot;https://twitter.com/rtfeldman&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Richard Feldman&lt;/a&gt; to clients and at the local Javascript meetup group in Cambridge.&lt;/p&gt;
&lt;div style=&quot;--aspect-ratio: 16/9;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/IcgmSRJHu_8&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;During the talk, I showed how companies could adopt typed Javascript using both Flow and Typescript incrementally.&lt;/p&gt;
&lt;h2 id=&quot;evangelising-typescript&quot;&gt;Evangelising Typescript&lt;/h2&gt;
&lt;p&gt;Having taught developers at &lt;a href=&quot;https://www.arm.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Arm&lt;/a&gt; how to use &lt;a href=&quot;https://stenciljs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Stencil&lt;/a&gt;, a library that required UI components to be written in Typescript, I had learnt how to train colleagues without them feeling overwhelmed.&lt;/p&gt;
&lt;p&gt;My aim was for anyone working on my project to contribute, even if they had little or no experience using Typescript.&lt;/p&gt;
&lt;p&gt;We did many pairing sessions and shared ideas, concepts and patterns while avoiding pitfalls and keeping things simple and easy to understand.&lt;/p&gt;
&lt;p&gt;It was fine for a developer to add ts-ignore comment at the top of a file and exclude a file from being typed checked during a feature’s development.&lt;/p&gt;
&lt;p&gt;This meant developers could focus on the feature they were building and share preview URLs with stakeholders, product owners and testers earlier during the development process. Meanwhile, we worked collaboratively behind the scenes to ensure everything was type-checked before merging the feature branch.&lt;/p&gt;
&lt;p&gt;For the adoption of Typescript to be successful, we needed to be able to demonstrate the value.&lt;/p&gt;
&lt;p&gt;Compared to similar projects at Cambridge University Press, which displayed information for books and articles, our codebase was cleaner as we were able to differentiate between types.&lt;/p&gt;
&lt;p&gt;Over the next few months, I’ll post more examples about how Typescript enabled us to have an awesome developer experience.&lt;/p&gt;
&lt;h2 id=&quot;how-did-using-typescript-workout&quot;&gt;How did using TypeScript workout?&lt;/h2&gt;
&lt;p&gt;I’m confident Typescript will be adopted in both existing and future projects at Cambridge University Press.&lt;/p&gt;
&lt;p&gt;Developers enjoyed using Typescript as it enabled them to focus on building features benefitting from better IntelliSense and faster feedback in their IDE than executing code within a browser. The organisation benefited from increased productivity, fewer bugs and having a product that was easier to maintain and extend.&lt;/p&gt;
</content:encoded></item><item><title>How To Use Tailwind Scoped Css Styles With Next.js</title><link>https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-nextjs/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-nextjs/</guid><pubDate>Thu, 21 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In this post I’ll show why and how you can use scoped styles with &lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind&lt;/a&gt; and &lt;a href=&quot;https://nextjs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;
&lt;p&gt;Using scoped CSS could save you from styling conflicts such as a naming clash where there are multiple classes with the same name, as shown in the example below.&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-96&quot; src=&quot;https://jagreehal.github.io/nextjs-tailwind-scoped-styles/&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;how&quot;&gt;How&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/css-modules/css-modules&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CSS modules&lt;/a&gt; provide the functionality to have scoped styles.&lt;/p&gt;
&lt;p&gt;And the good news is Next.js supports css modules out of the box!&lt;/p&gt;
&lt;p&gt;All you need to do is create a file that ends with ‘&lt;em&gt;.module.css’&lt;/em&gt; such as ‘&lt;em&gt;TailwindScopedComponent.module.css&lt;/em&gt;’&lt;/p&gt;
&lt;pre class=&quot;language-css&quot; data-language=&quot;css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@apply&lt;/span&gt; border border-green-500 bg-green-500 text-white rounded-md px-4 py-2 m-2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then import it within your component&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; styles &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./TailwindScopedComponent.module.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;I&lt;/span&gt; use scoped Tailwind classes&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/nextjs-tailwind-scoped-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The repository for the demo can be found here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;Another approach worth considering is to use a &lt;a href=&quot;https://arrangeactassert.com/posts/using-tailwind-consider-a-using-a-prefix/&quot;&gt;prefix with Tailwind&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>How To Use Tailwind Scoped Css Styles With Svelte</title><link>https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-svelte/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-svelte/</guid><pubDate>Thu, 21 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In this post I’ll show why and how you can use scoped styles with &lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind&lt;/a&gt; and &lt;a href=&quot;https://svelte.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Svelte&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;
&lt;p&gt;Using scoped CSS could save you from styling conflicts such as a naming clash where there are multiple classes with the same name, as shown in the example below.&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-96&quot; src=&quot;https://jagreehal.github.io/svelte-tailwind-scoped-styles/&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;how&quot;&gt;How&lt;/h2&gt;
&lt;p&gt;Svelte makes using converting a component to use scoped styles with Tailwind easy thanks to single file components!&lt;/p&gt;
&lt;p&gt;Before&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; data-language=&quot;html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;border border-green-500 bg-green-500 text-white rounded-md px-4 py-2 m-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  I use Tailwind classes
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After&lt;/p&gt;
&lt;p&gt;and this is what it looks like using scoped styles&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; data-language=&quot;html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;I use scoped Tailwind classes&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;postcss&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;.button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@apply&lt;/span&gt; border border-green-500 bg-green-500 text-white rounded-md px-4 py-2 m-2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/svelte-tailwind-scoped-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The repository for the demo can be found here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;Another approach worth considering is to use a &lt;a href=&quot;https://arrangeactassert.com/posts/using-tailwind-consider-a-using-a-prefix/&quot;&gt;prefix with Tailwind&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>How To Use Tailwind Scoped Css Styles With Vue</title><link>https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-vue/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-vue/</guid><pubDate>Tue, 19 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In this post I’ll show why and how you can use scoped styles with &lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind&lt;/a&gt; and &lt;a href=&quot;https://vuejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vue&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;
&lt;p&gt;Using scoped CSS could save you from styling conflicts such as a naming clash where there are multiple classes with the same name, as shown in the example below.&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-96&quot; src=&quot;https://jagreehal.github.io/vue-tailwind-scoped-styles/&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;how&quot;&gt;How&lt;/h2&gt;
&lt;p&gt;Vue makes using converting a component to use scoped styles with Tailwind easy thanks to single file components!&lt;/p&gt;
&lt;p&gt;Before&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; data-language=&quot;html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;border border-green-500 bg-green-500 text-white rounded-md px-4 py-2 m-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    I use Tailwind classes
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After&lt;/p&gt;
&lt;p&gt;and this is what it looks like using scoped styles&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; data-language=&quot;html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;I use scoped Tailwind classes&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;postcss&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
&lt;span class=&quot;token selector&quot;&gt;.button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@apply&lt;/span&gt; border border-green-500 bg-green-500 text-white rounded-md px-4 py-2 m-2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jagreehal/vue-tailwind-scoped-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The repository for the demo can be found here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;Another approach worth considering is to use a &lt;a href=&quot;https://arrangeactassert.com/posts/using-tailwind-consider-a-using-a-prefix/&quot;&gt;prefix with Tailwind&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Using Tailwind? Consider adding a prefix</title><link>https://arrangeactassert.com/posts/using-tailwind-consider-a-using-a-prefix/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/using-tailwind-consider-a-using-a-prefix/</guid><pubDate>Tue, 19 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;Tailwind is rightly receiving all the attention it deserves. Every developer I’ve introduced it to falls in love with working with CSS again!&lt;/p&gt;
&lt;p&gt;On a recent Nuxt project, I noticed a potential issue when using Tailwind class names.&lt;/p&gt;
&lt;p&gt;Suddenly ‘&lt;em&gt;bg-green-500&lt;/em&gt;’ didn’t behave as expected, as an external component also using the same class had set the color to something else.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com/static/gifs/bg-color-clash.gif&quot; alt=&quot;bg-color-500 clash&quot;&gt;&lt;/p&gt;
&lt;p&gt;Workarounds such as adding !important unnecessarily will get into specificity and wars that inevitably end in tears.&lt;/p&gt;
&lt;p&gt;Another workaround could be to use @apply and scoped styles, CSS modules or CSS-in-JS, but you lose some of the developer experience Tailwind offers.&lt;/p&gt;
&lt;p&gt;Using scoped styles with Tailwind is easy and you can read how to do that with &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-vue/&quot; title=&quot;How To Use Tailwind Scoped Css Styles With Vue&quot;&gt;Vue&lt;/a&gt;, &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-nextjs/&quot; title=&quot;How To Use Tailwind Scoped Css Styles With Next.js&quot;&gt;Next.js&lt;/a&gt; and &lt;a href=&quot;https://arrangeactassert.com/posts/how-to-use-tailwind-scoped-css-styles-with-svelte/&quot; title=&quot;How To Use Tailwind Scoped Css Styles With Svelte&quot;&gt;Svelte&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-prefix-to-tailwind&quot;&gt;Adding a prefix to Tailwind&lt;/h2&gt;
&lt;p&gt;However the simplest thing could be is to set a &lt;a href=&quot;https://tailwindcss.com/docs/configuration#prefix&quot;&gt;prefix&lt;/a&gt; in your Tailwind configuration file.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tw-&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then use the prefix for your tailwind classes so ‘&lt;em&gt;bg-green-500&lt;/em&gt;’ becomes ‘&lt;em&gt;tw-bg-green-500&lt;/em&gt;’&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; data-language=&quot;html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;tw-border tw-border-green-500 tw-bg-green-500 tw-text-white tw-rounded-md tw-px-4 tw-py-2 tw-m-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  Success
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see how to add a prefix below&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://arrangeactassert.com/static/gifs/using-prefix.gif&quot; alt=&quot;Using tailwind prefix&quot;&gt;&lt;/p&gt;
&lt;p&gt;Yes, there’s still a chance of naming conflicts, but this is the best solution I can think of that keeps the awesome developer experience Tailwind with some level of safety without using @apply and scoped styles.&lt;/p&gt;
&lt;p&gt;In my opinion, if you’re building a component library in Tailwind, adding a prefix will save you and your users from styling conflicts.&lt;/p&gt;
&lt;p&gt;If you’re building a large app the earlier you start using a prefix the less headache you’ll have of hunting down and changing Tailwind CSS classes later.&lt;/p&gt;
</content:encoded></item><item><title>Creating Stencil Apps with Tailwind</title><link>https://arrangeactassert.com/posts/creating-stencil-apps-with-tailwind/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/creating-stencil-apps-with-tailwind/</guid><pubDate>Wed, 13 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;&lt;a href=&quot;https://stenciljs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Stencil&lt;/a&gt; is a compiler for creating web components that work alone or with web applications written in React, Vue, Angular, Svelte, Ember or anything else you can think of.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind CSS&lt;/a&gt; deserves all praise love it’s getting right now as the developer experience is incredible.&lt;/p&gt;
&lt;p&gt;In this post I’ll show how to create a Stencil web app using Tailwind CSS.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;You can create a Stencil web application by running&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init stencil&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and choosing ‘app’ when asked to pick a starter&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;stencil-pick-a-starter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1334px) 1334px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1334&quot; height=&quot;300&quot; src=&quot;https://arrangeactassert.com/_astro/stencil-pick-a-starter.B1ktl1_I_gXWJk.webp&quot; srcset=&quot;/_astro/stencil-pick-a-starter.B1ktl1_I_1SMn2b.webp 640w, /_astro/stencil-pick-a-starter.B1ktl1_I_Z1kNdve.webp 750w, /_astro/stencil-pick-a-starter.B1ktl1_I_NU61F.webp 828w, /_astro/stencil-pick-a-starter.B1ktl1_I_Z21tQzV.webp 1080w, /_astro/stencil-pick-a-starter.B1ktl1_I_uB9sL.webp 1280w, /_astro/stencil-pick-a-starter.B1ktl1_I_gXWJk.webp 1334w&quot;&gt;&lt;/p&gt;
&lt;p&gt;next add the following dev dependencies&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; tailwindcss@latest @stencil/postcss@latest autoprefixer@latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and run the following command to create a Tailwind configuration file &lt;em&gt;‘tailwind.config.js’&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx tailwindcss init&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the Tailwind configuration file set the array of paths for where you’ll be using Tailwind classes. This is required for removing unused CSS when creating a production build&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;purge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;purge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./src/**/*.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./src/**/*.tsx&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./src/**/*.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;darkMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// or &apos;media&apos; or &apos;class&apos;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;variants&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can configure Stencil to use PostCSS as a plugin in &lt;em&gt;‘stencil.config.ts’&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Config &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@stencil/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; postcss &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@stencil/postcss&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; tailwindcss &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tailwindcss&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; autoprefixer &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;autoprefixer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// https://stenciljs.com/docs/config&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;globalStyle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src/global/app.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;globalScript&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src/global/app.ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;taskQueue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;async&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;outputTargets&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;www&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// comment the following line to disable service workers in production&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;serviceWorker&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://myapp.local/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;postcss&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tailwindcss&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; autoprefixer&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to inject Tailwind’s ‘base’, ‘components’, and ‘utilities’ styles in &lt;em&gt;‘src/global/app.css’&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot; data-language=&quot;css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@tailwind&lt;/span&gt; base&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@tailwind&lt;/span&gt; components&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@tailwind&lt;/span&gt; utilities&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all the configuration done! Now you can start the Stencil development server by running&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;using-tailwind-in-stencil-components&quot;&gt;Using Tailwind in Stencil Components&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s possible to use Stencil with the ShadowDOM which will be covered in a later post, but lets keep things simple for now&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Open the file &lt;em&gt;‘src/components/app-root/app-root.tsx’&lt;/em&gt; and remove the styleUrl and shadow properties from the component, and replace the header element to use Tailwind CSS classes.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Component&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@stencil/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

@&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;app-root&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;styleUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;app-root.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppRoot&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;header&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Stencil App Starter&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;header&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;header &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bg-purple-700 h-16 flex items-center shadow-md&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-white text-xl font-bold px-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Stencil App Starter&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;header&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;router&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;route&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; scrollTopOffset&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;route url&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt; component&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app-home&quot;&lt;/span&gt; exact&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;route url&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/profile/:name&quot;&lt;/span&gt; component&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app-profile&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;route&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;stencil&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;router&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output for using Tailwind CSS with Stencil is shown below.&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-80&quot; src=&quot;https://stencil-app-with-tailwind.netlify.app/&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The code for how to use &lt;a href=&quot;https://github.com/jagreehal/stencil-app-with-tailwind&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind CSS with Stencil can be found on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In upcoming posts I’ll show how to create component libraries using Stencil and Tailwind covering topics such as scoped CSS styles.&lt;/p&gt;
</content:encoded></item><item><title>How to fix: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission</title><link>https://arrangeactassert.com/posts/how-to-fix-the-request-is-not-allowed-by-the-user-agent-or-the-platform-in-the-current-context-possibly-because-the-user-denied-permission/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-to-fix-the-request-is-not-allowed-by-the-user-agent-or-the-platform-in-the-current-context-possibly-because-the-user-denied-permission/</guid><pubDate>Tue, 05 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;It’s a good thing browsers don’t allow sites to autoplay audio or videos without user interaction.&lt;/p&gt;
&lt;p&gt;However, on iOS in particular, you might encounter the error&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;when there is an async operation between the user interaction and playing of audio.&lt;/p&gt;
&lt;p&gt;The good news is there’s a workaround for it.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h2 id=&quot;playing-audio-in-web-apps&quot;&gt;Playing audio in web apps&lt;/h2&gt;
&lt;p&gt;Before a site can play audio, a user needs to have interacted with it for example, clicking on a play button.&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-40&quot; src=&quot;https://jagreehal.github.io/aaa-react-examples/web-audio-issues/play-audio&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The code for this is simple&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;audioError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setAudioError&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Error&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Audio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;https://www.videomaker.com/sites/videomaker.com/files/downloads/free-sound-effects/Free_ExplosionSharp_6048_97_1.wav&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mb-4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;Clicking play works everywhere&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
        className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;border-2 border-green-700 bg-green-500 text-white rounded-md px-4 py-2 text-center&quot;&lt;/span&gt;
        onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        Play ▶
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audioError &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-4 text-red-600&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AUDIO&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audioError&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, if in between clicking the button and playing audio, an async operation occurs then the behaviour of browsers differ.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Audio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;https://www.videomaker.com/sites/videomaker.com/files/downloads/free-sound-effects/Free_ExplosionSharp_6048_97_1.wav&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, clicking on the ‘play’ button after a promise is resolved in Chrome plays the audio, whereas, in Safari, you’ll see the error below:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;iframe class=&quot;iframe-example h-80&quot; src=&quot;https://jagreehal.github.io/aaa-react-examples/web-audio-issues/play-audio-after-promise&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;fixing-the-the-request-is-not-allowed-bug&quot;&gt;Fixing the ‘The request is not allowed’ bug&lt;/h2&gt;
&lt;p&gt;The workaround is to load the audio in one interaction, and play the audio in another interaction. Now you can run as many promises as you want, the browser won’t error.&lt;/p&gt;
&lt;p&gt;The downside of this approach is you will have to change the UX of your web app.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useState &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;audioError&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setAudioError&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Error&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;audio&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setAudio&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; useState&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLAudioElement&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 1. load the audio in a user interaction&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleLoadClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; _audio &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Audio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;https://www.videomaker.com/sites/videomaker.com/files/downloads/free-sound-effects/Free_ExplosionSharp_6048_97_1.wav&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    _audio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    _audio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;canplaythrough&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;loaded audio&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setAudio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_audio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 2. now you can play the audio on all subsequent events&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    audio &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      audio&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;play&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setAudioError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex flex-col space-y-4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mb-4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        The work around is to load the audio after a user interaction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; Now you can play audio after
        &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; operations on iOS&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
        className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;border-2 border-blue-700 bg-blue-500 text-white rounded-md px-4 py-2 text-center&quot;&lt;/span&gt;
        onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleLoadClick&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        disabled&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audio &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audio &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;▼ Click the button below to play the audio&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Load Audio!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
        className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;border-2 border-green-700 bg-green-500 &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
          audio &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cursor-not-allowed&apos;&lt;/span&gt;
        &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; text-white rounded-md px-4 py-2 mt-4 text-center&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        disabled&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audio &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audio &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Play after resolving a promise ▶&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;▲ Click the button above to load audio&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audioError &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-4 text-red-600&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AUDIO&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;audioError&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; App&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try it for yourself here by loading the audio before clicking the play button&lt;/p&gt;
&lt;iframe class=&quot;iframe-example h-80&quot; src=&quot;https://jagreehal.github.io/aaa-react-examples/web-audio-issues/play-audio-after-promise-workaround&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The full code for the examples above can be found &lt;a href=&quot;https://github.com/jagreehal/aaa-react-examples/tree/master/src/pages/web-audio-issues&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Getting people to believe in your vision</title><link>https://arrangeactassert.com/posts/getting-people-to-believe-in-your-vision/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/getting-people-to-believe-in-your-vision/</guid><pubDate>Mon, 14 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;It can be a struggle, endlessly trying to convince your organisation to believe in your ideas and vision.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;person holding a lightbulb&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1981px) 1981px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1981&quot; height=&quot;1588&quot; src=&quot;https://arrangeactassert.com/_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_2iFmfp.webp&quot; srcset=&quot;/_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_2hdJmk.webp 640w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_Z1ySBml.webp 750w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_ZvXoWK.webp 828w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_Z1h9Ti7.webp 1080w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_Zgxers.webp 1280w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_1PW09s.webp 1668w, /_astro/riccardo-annandale-7e2pe9wjL9M-unsplash.mwL3BZss_2iFmfp.webp 1981w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this post, I’ll share how I managed to do this.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p&gt;Having been part of a team that successfully launched Cambridge Core, a web application providing digital access to books and journals, I left Cambridge University Press to join Compare The Market.&lt;/p&gt;
&lt;p&gt;The tech first attitude at Compare The Market was amazing. The experience taught me better ways to build and architect web applications.&lt;/p&gt;
&lt;p&gt;In 2018 I returned to Cambridge University Press.&lt;/p&gt;
&lt;p&gt;Having had time to reflect on technical choices made when building Cambridge Core, I now knew how we could improve the product.&lt;/p&gt;
&lt;h3 id=&quot;building-reputation-and-trust&quot;&gt;Building reputation and trust&lt;/h3&gt;
&lt;p&gt;I already had trust within my team, but for management to believe in my vision, I needed to demonstrate my ability, commitment and knowledge of the existing product. I did this by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Getting involved when we had production issues. Using the same principles as Compare The Market, I helped the team get a better insight into how the application was performing and how we could improve performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Training, pairing and helping teammates develop features and resolve bugs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Volunteering for things that need doing, but knew nothing about. I took on the lead role of moving an application onto a new Kubernetes platform. By learning on the job and in my own time, I gave the business confidence they could leave it to me to get the job done.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collaborating with product owners to write tickets and develop features to break down silos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Working with our scrum master on improving our workflow, and trying things to make us work even better as a team.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sharing ideas with developers, architects, operations and management about technical improvements we could make.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Presenting talks about my ideas inside and outside of the organisation at user groups and conferences. The feedback from the tasks enabled me to inspect, adapt and improve my ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;take-a-chance-on-me&quot;&gt;Take a chance on me&lt;/h3&gt;
&lt;div style=&quot;--aspect-ratio: 16/9;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/-crgQGdpZR0&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;By doing the above, Cambridge University Press gave me the opportunity to lead a new multi-million-pound project, Higher Education.&lt;/p&gt;
&lt;p&gt;An opportunity that would change my life forever.&lt;/p&gt;
&lt;p&gt;Hopefully, this helps or inspires you to persevere and continue carving out the chance to lead and implement your vision.&lt;/p&gt;
&lt;footer class=&quot;attribution&quot;&gt;
Image source: https://unsplash.com/photos/7e2pe9wjL9M
&lt;/footer&gt;
</content:encoded></item><item><title>How agile helped Cambridge Assessment to scale</title><link>https://arrangeactassert.com/posts/how-agile-helped-cambridge-assessment-to-scale/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/how-agile-helped-cambridge-assessment-to-scale/</guid><pubDate>Mon, 07 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In 2008 the media were reporting on &lt;a href=&quot;http://news.bbc.co.uk/1/hi/education/7490216.stm&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;mistakes and delays in marking examination scripts&lt;/a&gt;. To ensure they never made the front page of newspapers for the wrong reasons, Cambridge Assessment decided to rethink how they electronically marked examination scripts for millions of students worldwide.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;figure&gt;
  &lt;img
    src=&quot;https://arrangeactassert.com/static/images/nguyen-dang-hoang-nhu-qDgTQOYk6B8-unsplash.jpg&quot;
    alt=&quot;Example of a generic marking sheet&quot;
  /&gt;
  &lt;figcaption&gt;
    Example of a generic marking sheet
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Their existing solution, developed using BizTalk, processed tasks in a single long-running transaction. While it was able to process the current number of scripts, Cambridge Assessment wasn’t confident it would be able to handle the ever-growing increase in demand as it had not been designed to work at such a scale.&lt;/p&gt;
&lt;p&gt;I was hired along with two other engineers, &lt;a href=&quot;https://www.linkedin.com/in/richard-miller-200b901/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Richard Miller&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/IJohnson_TNF&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Ian Johnson&lt;/a&gt;, to create a solution that would scale. We joined a team alongside a project manager, test team and a member of the existing development team, whose experience and knowledge of the business domain gave us invaluable insight.&lt;/p&gt;
&lt;h3 id=&quot;our-engineering-manager&quot;&gt;Our Engineering Manager&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/adamstraughan/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Adam Straughan&lt;/a&gt; was a true engineers manager.&lt;/p&gt;
&lt;p&gt;He was open, honest and had the courage to voice his opinions which some of the management team didn’t like.&lt;/p&gt;
&lt;p&gt;He trusted and empowered us to get on with it. He was passionate about creating a development culture to create innovative solutions using practices such as test-driven development and continuous deployment, a first for a project at Cambridge Assessment.&lt;/p&gt;
&lt;p&gt;It wouldn’t be an understatement to say he played a significant role in revolutionising software development at Cambridge Assessment.&lt;/p&gt;
&lt;h3 id=&quot;the-agile-approach&quot;&gt;The agile approach&lt;/h3&gt;
&lt;p&gt;As far as I know, this was one of Cambridge Assessments first agile projects at this scale.&lt;/p&gt;
&lt;p&gt;I had already worked on so many “agile” projects, but this was the best I had experienced.&lt;/p&gt;
&lt;p&gt;All thanks to Richard, who did both a scrum master and engineer role at the highest level.&lt;/p&gt;
&lt;p&gt;He was able to explain why we were doing what we did and made everything ridiculously simple. I still use his ideas in the teams I lead today.&lt;/p&gt;
&lt;p&gt;Stand-ups were short, and to the point, planning sessions focused, and our retrospectives made a difference as we improved as a team throughout the project.&lt;/p&gt;
&lt;h3 id=&quot;gaining-trust-and-confidence-from-the-business&quot;&gt;Gaining trust and confidence from the business&lt;/h3&gt;
&lt;p&gt;Our agile approach was perfect for gaining trust and confidence from the business. We needed to show outcomes rather than just output.&lt;/p&gt;
&lt;p&gt;We had access to a stakeholder who had in-depth knowledge and experience of the complexities and rules in marking examinations.&lt;/p&gt;
&lt;p&gt;After every sprint, we did demos to the business to show we were applying the same marking algorithms and able to compute the same result as the existing solution. We started with simple user stories at the start of the project before moving on more complex scenarios such as remarks.&lt;/p&gt;
&lt;h3 id=&quot;forming-storming-norming-and-performing&quot;&gt;Forming, Storming, Norming, and Performing&lt;/h3&gt;
&lt;p&gt;The four of us had never worked together before. Some of our skills and approaches overlapped others didn’t. We were all passionate about software development and went to the same user groups outside of work.&lt;/p&gt;
&lt;p&gt;Our team grew over time with more engineers joining.&lt;/p&gt;
&lt;p&gt;We learnt a lot from each other, probably no more than when we had conflicting views. It was my first time working with people who were passionate about the product and had to learn how to present my ideas, so they were simple to understand.&lt;/p&gt;
&lt;p&gt;It was a psychologically safe environment to disagree. We trusted each other and ensured discussions remained constructive and not personal.&lt;/p&gt;
&lt;p&gt;We knew how vital collaboration was. All members of the team put forward ideas and paired together when we needed to. We used whiteboards for discussions which helped to ensure all team members had a shared understanding.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;drawing on a whiteboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 5184px) 5184px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;5184&quot; height=&quot;3888&quot; src=&quot;https://arrangeactassert.com/_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_17MdL6.webp&quot; srcset=&quot;/_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_1cBDhh.webp 640w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_28gqCv.webp 750w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_1yhLKN.webp 828w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_1RzF0h.webp 1080w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_ZBwIEm.webp 1280w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_Z2rgQu8.webp 1668w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_1cMpLh.webp 2048w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_Z1oxW7p.webp 2560w, /_astro/kvalifik-5Q07sS54D0Q-unsplash.c3mh5Raj_17MdL6.webp 5184w&quot;&gt;&lt;/p&gt;
&lt;p&gt;To this day, we have no doubt the application would never have been as good as it was without us being passionate, empowered and having a feeling of ownership which gave us the energy to voice our opinions.&lt;/p&gt;
&lt;h3 id=&quot;the-architecture&quot;&gt;The architecture&lt;/h3&gt;
&lt;p&gt;As well as being able to process exam scripts correctly, the scalability of our solution would ultimately determine the success of our solution.&lt;/p&gt;
&lt;p&gt;It didn’t take long for us to work out our approach. As we attended the same talks and read the same resources from blog posts to books, we had similar ideas about what to do.&lt;/p&gt;
&lt;p&gt;We split the application into microservices each having a single responsibility. There was a service for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;storing examination scripts sent from a third party&lt;/li&gt;
&lt;li&gt;for processing examination scripts&lt;/li&gt;
&lt;li&gt;uploading results to an internal service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transactions boundaries were small using queues to communicate between the services, which enabled additional benefits such as replayability.&lt;/p&gt;
&lt;p&gt;So now we could deploy and scale components independently as required. Not bad in the days before auto-scaling!&lt;/p&gt;
&lt;h3 id=&quot;developing-the-solution&quot;&gt;Developing the solution&lt;/h3&gt;
&lt;p&gt;We worked closely with the test team to learn about the business domain, which helped us develop a ubiquitous language.&lt;/p&gt;
&lt;p&gt;We added instrumentation which enabled us to develop dashboards and build tools to replay scripts which helped to debug and troubleshoot.&lt;/p&gt;
&lt;p&gt;We were able to call on architects and database experts to ensure we were on the right path and give advice on best practices and what to look out for.&lt;/p&gt;
&lt;p&gt;Our shared philosophy enabled us to build a culture in which engineers could easily understand the vision, collaborate, share ideas, innovate and contribute.&lt;/p&gt;
&lt;p&gt;Small details such as being able to reproduce a bug with a unit test before fixing ensured we built a high-quality application.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;people with laptops at a table&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 6000px) 6000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;6000&quot; height=&quot;4004&quot; src=&quot;https://arrangeactassert.com/_astro/pexels-fauxels-3183190.DNvLao0C_1Cc98k.webp&quot; srcset=&quot;/_astro/pexels-fauxels-3183190.DNvLao0C_2kRdD0.webp 640w, /_astro/pexels-fauxels-3183190.DNvLao0C_ZSjqh1.webp 750w, /_astro/pexels-fauxels-3183190.DNvLao0C_1diOkP.webp 828w, /_astro/pexels-fauxels-3183190.DNvLao0C_kkHhH.webp 1080w, /_astro/pexels-fauxels-3183190.DNvLao0C_Z1nO9HK.webp 1280w, /_astro/pexels-fauxels-3183190.DNvLao0C_Z1jpQM8.webp 1668w, /_astro/pexels-fauxels-3183190.DNvLao0C_noPe1.webp 2048w, /_astro/pexels-fauxels-3183190.DNvLao0C_3EvVa.webp 2560w, /_astro/pexels-fauxels-3183190.DNvLao0C_1Cc98k.webp 6000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As our team grew, we learned and adapted to ensure people were happy and enjoying working on the project. For example, we dedicated a different engineer every sprint to take on a ‘Batman’ role to answer questions from the business and the test team, allowing other engineers to focus without being distracted and having to switch context.&lt;/p&gt;
&lt;p&gt;Being in a support role helped engineers learn how crucial logging was for them to understand why something was happening. Now when the engineer returned to regular duties, they understood how critical it was to write tests, handle errors and instrument their code.&lt;/p&gt;
&lt;h3 id=&quot;making-the-grade&quot;&gt;Making the grade&lt;/h3&gt;
&lt;p&gt;Our agile approach of having short feedback loops and incrementally adding features helped us keep focus.&lt;/p&gt;
&lt;p&gt;The application was launched on time and successfully processed millions of examination scripts for years to come allowing Cambridge Assessment to build upon its’ excellent reputation as a world-class qualification provider.&lt;/p&gt;
</content:encoded></item><item><title>Creating a product culture at Cambridge University Press</title><link>https://arrangeactassert.com/posts/creating-a-product-culture-at-cambridge-university-press/</link><guid isPermaLink="true">https://arrangeactassert.com/posts/creating-a-product-culture-at-cambridge-university-press/</guid><pubDate>Tue, 01 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;!-- Excerpt Start --&gt;
&lt;p&gt;In 2015 I was hired by Cambridge University Press to develop a web application providing digital access to over 35,000 books and 1.5 million journal articles, consolidating several smaller sites. The application would go onto have over 2 million users a day and generate £65 million in revenue per year.&lt;/p&gt;
&lt;p&gt;It was a fantastic technical learning opportunity, but it was our culture and approach to product development that would teach me the most important lesson of all.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;h3 id=&quot;our-culture&quot;&gt;Our culture&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;hands on top of one another&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 6000px) 6000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;6000&quot; height=&quot;4000&quot; src=&quot;https://arrangeactassert.com/_astro/pexels-fauxels-3184418.DME9Pd-4_Z16mcTx.webp&quot; srcset=&quot;/_astro/pexels-fauxels-3184418.DME9Pd-4_Z2vObMG.webp 640w, /_astro/pexels-fauxels-3184418.DME9Pd-4_ZENGSL.webp 750w, /_astro/pexels-fauxels-3184418.DME9Pd-4_1ezScV.webp 828w, /_astro/pexels-fauxels-3184418.DME9Pd-4_Y0FgK.webp 1080w, /_astro/pexels-fauxels-3184418.DME9Pd-4_ZJ9bIH.webp 1280w, /_astro/pexels-fauxels-3184418.DME9Pd-4_ZEJSN5.webp 1668w, /_astro/pexels-fauxels-3184418.DME9Pd-4_Z5ECMz.webp 2048w, /_astro/pexels-fauxels-3184418.DME9Pd-4_HktUd.webp 2560w, /_astro/pexels-fauxels-3184418.DME9Pd-4_Z16mcTx.webp 6000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;I realised on my very first day that this contract would be different. Unlike every other place I had worked, everyone from the product leader, product owners and scrum master, to testers and developers genuinely wanted to help each other.&lt;/p&gt;
&lt;p&gt;Our team was made up of people from various backgrounds at different stages in their careers. Nobody thought they were better than anyone else, with egos checked in at the door. Team members were happy to get up from their desks to collaborate together. Company politics were kept away from the team, and I was never put in any position where I had to choose a side or get involved in any kind of way.&lt;/p&gt;
&lt;p&gt;All this made it easy for me to settle in.&lt;/p&gt;
&lt;h3 id=&quot;product-leadership&quot;&gt;Product Leadership&lt;/h3&gt;
&lt;p&gt;Up to this point in my career, I had worked with some outstanding people but not an exceptional product leader.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arrangeactassert.com//www.linkedin.com/in/vickydrummond/&quot;&gt;Vicky Drummond&lt;/a&gt; is what authors such as Marty Cagan describe as a great product leader. She had a passion for the product, understood the market and had a clear vision.&lt;/p&gt;
&lt;p&gt;As well as having the skills, knowledge and experience, Vicky was trusted and loved by the team. She encouraged and supported the team to innovate and try things. Her enthusiasm was infectious. Everyone on the team wanted the product to be successful.&lt;/p&gt;
&lt;p&gt;I would have run through a brick wall for Vicky.&lt;/p&gt;
&lt;p&gt;Research into the market and storyboards helped us understand user journeys. Four personas were created, and every user story started with one of them, and so during planning, it was clear to the team why we were building a feature and what the expected outcome was.&lt;/p&gt;
&lt;h3 id=&quot;inspect-and-adapt&quot;&gt;Inspect and adapt&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Post it notes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2560px) 2560px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2560&quot; height=&quot;1707&quot; src=&quot;https://arrangeactassert.com/_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_1CoI9s.webp&quot; srcset=&quot;/_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_Z4ixFr.webp 640w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_Z1qgMSu.webp 750w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_Z1HOjj0.webp 828w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_2eRlwY.webp 1080w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_1jwhkx.webp 1280w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_Z5yI9W.webp 1668w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_vMBVN.webp 2048w, /_astro/david-travis-WC6MJ0kRzGw-unsplash.B-HUM-GR_1CoI9s.webp 2560w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We adapted how we did things throughout the development of the product, ensuring agile was still working for us rather than being a checklist of things we had to do. This happened because the team trusted one another.&lt;/p&gt;
&lt;p&gt;Our retrospectives were a safe place to voice concerns and issues, always starting by reading the prime directive. &lt;a href=&quot;https://www.linkedin.com/in/paul-telford-a0b79139/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Paul Telford&lt;/a&gt;, our excellent scrum master, ensured everyone contributed and helped the team decide how to resolve problems and held us accountable for actions. This was different from many of the places where little was actually done.&lt;/p&gt;
&lt;p&gt;Our stand-ups were more like catch-ups. We shared jokes, and it was something we wanted to do rather than had to do. As some of the team were based remotely, we organised events such as board game evenings when they came to the office in Cambridge, which created a bond between us.&lt;/p&gt;
&lt;p&gt;Instead of the scrum master telling us what to do, he encouraged us to use our initiative and self organise. He wanted to talk less so the team could talk more.&lt;/p&gt;
&lt;p&gt;If anybody was stuck or needed help, they used Slack to raise any things straight away rather than wait until the next morning.&lt;/p&gt;
&lt;p&gt;We had empowerment and ownership of the product we were building.&lt;/p&gt;
&lt;h3 id=&quot;people-create-a-product-culture-not-processes&quot;&gt;People create a product culture, not processes&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://arrangeactassert.com//www.cambridge.org/core/&quot;&gt;Cambridge Core&lt;/a&gt; was successfully launched in 2016, and I left the year after.&lt;/p&gt;
&lt;p&gt;No other workplace has given me the same joyful experience developing a product.&lt;/p&gt;
&lt;p&gt;I’ve read many books, watched talks and listened to podcasts about building a good product team. Many companies think they are doing the right thing by following a process rather than investing in current staff, hiring the right people and having a talented product leader.&lt;/p&gt;
</content:encoded></item></channel></rss>