<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mariano Barcia</title>
    <description>The latest articles on DEV Community by Mariano Barcia (@mbarcia).</description>
    <link>https://dev.to/mbarcia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3186852%2Fc12e3db2-bbe9-47ea-86d4-bfad00f15c5d.JPG</url>
      <title>DEV Community: Mariano Barcia</title>
      <link>https://dev.to/mbarcia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mbarcia"/>
    <language>en</language>
    <item>
      <title>cross-repo testing anyone?</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Tue, 29 Sep 2026 16:37:17 +0000</pubDate>
      <link>https://dev.to/mbarcia/cross-repo-testing-anyone-3oen</link>
      <guid>https://dev.to/mbarcia/cross-repo-testing-anyone-3oen</guid>
      <description>&lt;p&gt;Anyone on my network doing automated testing across multiple repositories / microservices? Curious to know how you are doing, I might have a well-defined product I'd like to build and would love some feedback.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>automation</category>
      <category>microservices</category>
      <category>testing</category>
    </item>
    <item>
      <title>On Jev and Athletics</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Fri, 25 Sep 2026 12:42:47 +0000</pubDate>
      <link>https://dev.to/mbarcia/on-ai-and-athletics-2ghf</link>
      <guid>https://dev.to/mbarcia/on-ai-and-athletics-2ghf</guid>
      <description>&lt;p&gt;I think using AI every day has given us a slightly misleading idea of how easy automation is becoming.&lt;/p&gt;

&lt;p&gt;Models have improved incredibly quickly. Give an AI a browser, some skills and a bit of context and it can do impressive things.&lt;/p&gt;

&lt;p&gt;So it’s easy to think: surely automating the whole process is next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I’m not so sure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’ve been running 100 metres with 30” hurdles — and still hitting a few — and now we’re talking about running 400 metres hurdles at the Olympics.&lt;/p&gt;

&lt;p&gt;A skill that works while you’re watching is very different from something that has to work hundreds of times on its own.&lt;/p&gt;

&lt;p&gt;Small problems multiply. A slow AI call repeated ten times becomes a slow process. Something that’s reliable 98% of the time doesn’t look nearly as good after twenty steps. Websites change, logins expire, bot protection gets tougher. And giving an AI access to everything it might need brings its own obvious problems.&lt;/p&gt;

&lt;p&gt;This is one reason I’ve decided to integrate Jev into The Pipeline Framework.&lt;/p&gt;

&lt;p&gt;Jev doesn’t try to solve all of that. It does something much narrower: make small decisions over supplied data very quickly and very cheaply.&lt;/p&gt;

&lt;p&gt;And that compounds beautifully.&lt;/p&gt;

&lt;p&gt;Data leads to a small decision, which produces more data, which informs another decision, and eventually the software does something.&lt;/p&gt;

&lt;p&gt;That’s much more interesting to me than asking one enormous model to figure out the whole process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Big types
&lt;/h2&gt;

&lt;p&gt;Here’s the lovely coincidence I only noticed after integrating Jev.&lt;/p&gt;

&lt;p&gt;The company behind it is called TypeSafe.&lt;/p&gt;

&lt;p&gt;And strong typing is also one of the ideas at the heart of The Pipeline Framework (as is the case with many programming languages).&lt;/p&gt;

&lt;p&gt;That’s not just a naming coincidence: Jev doesn’t return some prose and hope the application interprets it correctly. You give it a defined set of possible decisions and get a structured result back.&lt;/p&gt;

&lt;p&gt;TPF takes the same idea further through the rest of the application: typed data goes into steps, typed data comes out, and those types connect AI decisions, ordinary code, human input and real-world actions.&lt;/p&gt;

&lt;p&gt;Jev makes the decision faster and cheaper.&lt;/p&gt;

&lt;p&gt;TPF makes the process around the decision something you can actually build software on.&lt;/p&gt;

</description>
      <category>jev</category>
      <category>tpf</category>
      <category>automation</category>
      <category>typesafe</category>
    </item>
    <item>
      <title>It took me 18 hours to add Jev</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Wed, 23 Sep 2026 17:29:21 +0000</pubDate>
      <link>https://dev.to/mbarcia/it-took-me-18-hours-to-add-jev-lk7</link>
      <guid>https://dev.to/mbarcia/it-took-me-18-hours-to-add-jev-lk7</guid>
      <description>&lt;p&gt;It took me 18 months to build The Pipeline Framework.&lt;/p&gt;

&lt;p&gt;18 days to turn it into an AI operating system.&lt;/p&gt;

&lt;p&gt;18 hours to add an entirely new kind of AI.&lt;/p&gt;

&lt;p&gt;TypeSafe released Jev only days ago: a System One model that doesn’t generate language. It makes fast, bounded, probabilistic decisions.&lt;/p&gt;

&lt;p&gt;TPF had been built around functional pipelines, "Functional Core, Imperative Shell", reactiveness, scalability, then generative LLMs, RAG, tools, agent loops, MCP, human interaction, durable effects...&lt;/p&gt;

&lt;p&gt;So how much architecture would a fundamentally different model require? Turns out: almost none. So Jev became another Query provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;invoice-judgment-model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;decision.query.jev&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typesafe/jev-1.13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added a provider-neutral decision protocol:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DecisionRequest → DecisionResult&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;with bounded Choice, Noul and Score questions, then plugged Jev underneath it.&lt;/p&gt;

&lt;p&gt;A real Java application was using it the same day — despite Jev not yet having an official Java SDK.&lt;/p&gt;

&lt;p&gt;And I think that is the milestone I’m happiest about: not that TPF supports the latest AI model, but that it didn’t particularly care that it was new.&lt;/p&gt;

&lt;p&gt;An LLM is a Query. RAG retrieval is a Query. A database lookup is, you guessed it, also a Query. So now a System One probabilistic decision is a Query, as it should.&lt;/p&gt;

&lt;p&gt;Different computational models. Different latency profiles. Different semantics at the provider level. Same application architecture.&lt;/p&gt;

&lt;p&gt;The first 18 months were spent finding the abstractions.&lt;/p&gt;

&lt;p&gt;The next 18 days exploited them.&lt;/p&gt;

&lt;p&gt;The next 18 hours barely disturbed them.&lt;/p&gt;

&lt;p&gt;That’s the compounding return of solid architecture.&lt;/p&gt;

</description>
      <category>jev</category>
      <category>quarkus</category>
      <category>java</category>
      <category>tpf</category>
    </item>
    <item>
      <title>LLMs Generate. Jev Decides. Software Should Know the Difference</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Tue, 22 Sep 2026 16:37:18 +0000</pubDate>
      <link>https://dev.to/mbarcia/llms-generate-jev-decides-software-should-know-the-difference-2dek</link>
      <guid>https://dev.to/mbarcia/llms-generate-jev-decides-software-should-know-the-difference-2dek</guid>
      <description>&lt;h2&gt;
  
  
  Bringing TypeSafe's System One model into a real Java application with The Pipeline Framework
&lt;/h2&gt;

&lt;p&gt;For the last few years, we have been solving an extraordinary range of software problems with essentially the same primitive:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;send some context to a large language model and ask it to generate the answer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That has worked relatively well, but it has also encouraged us to turn problems that are not fundamentally generative into generation problems.&lt;/p&gt;

&lt;p&gt;Classification becomes generation.&lt;/p&gt;

&lt;p&gt;Routing becomes generation.&lt;/p&gt;

&lt;p&gt;Selecting one item from a known catalogue becomes generation.&lt;/p&gt;

&lt;p&gt;Determining whether a condition holds becomes, you guessed it: generation.&lt;/p&gt;

&lt;p&gt;And then, because a generative model is free to generate almost anything, we spend an increasing amount of effort constraining it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Return exactly one of these values.&lt;/p&gt;

&lt;p&gt;Do not invent identifiers.&lt;/p&gt;

&lt;p&gt;Return exactly this JSON structure.&lt;/p&gt;

&lt;p&gt;Do not include an explanation.&lt;/p&gt;

&lt;p&gt;Do not wrap the result in another object.&lt;/p&gt;

&lt;p&gt;Never return anything outside the supplied catalogue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Structured output has made this considerably better. But there is still something slightly peculiar about the underlying architecture.&lt;/p&gt;

&lt;p&gt;We are using a machine designed to generate an open-ended sequence of tokens, and then asking it very politely not to be open-ended.&lt;/p&gt;

&lt;p&gt;TypeSafe's Jev presents a fascinating alternative.&lt;/p&gt;

&lt;p&gt;And when we integrated Jev into The Pipeline Framework and then used it in a real invoice-processing application, something became very clear:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;some of the work we were giving to an LLM was never an LLM problem in the first place.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  System One: AI as a decision function
&lt;/h2&gt;

&lt;p&gt;TypeSafe describes Jev as the first of its &lt;strong&gt;System One Models&lt;/strong&gt;: models designed not primarily to generate language, but to make fast, structured decisions that software can consume directly.&lt;/p&gt;

&lt;p&gt;Instead of an open-ended generation operation, the abstraction is closer to a bounded decision function.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    S[State] --&amp;gt; G[Generative model]
    G --&amp;gt; T[Open-ended tokens]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    S[State] --&amp;gt; D[Bounded questions]
    D --&amp;gt; J[System One model]
    J --&amp;gt; R[Probabilistic decisions]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The distinction is profound.&lt;/p&gt;

&lt;p&gt;TypeSafe currently exposes three particularly useful decision shapes: &lt;code&gt;Choice&lt;/code&gt;, &lt;code&gt;Noul&lt;/code&gt;, and &lt;code&gt;Score&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;Choice&lt;/code&gt; selects from a finite set of alternatives and returns the corresponding probability information.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;Noul&lt;/code&gt; evaluates a proposition probabilistically.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;Score&lt;/code&gt; evaluates something against an ordered scale.&lt;/p&gt;

&lt;p&gt;Several independent questions can be evaluated against the same state in one request.&lt;/p&gt;

&lt;p&gt;The output is not primarily prose intended for a human reader. It is information intended for &lt;strong&gt;software&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That changes what the model is being asked to do.&lt;/p&gt;

&lt;p&gt;Consider the difference.&lt;/p&gt;

&lt;p&gt;A generative approach says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read this invoice and tell me which property it belongs to. Return exactly one ID from this list and do not invent another one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A bounded decision instead defines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which property?

Choice:
    PROPERTY_A
    PROPERTY_B
    PROPERTY_C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first case, selecting a valid identifier is a prompt requirement.&lt;/p&gt;

&lt;p&gt;In the second, it is part of the decision domain.&lt;/p&gt;

&lt;p&gt;That is a much stronger contract.&lt;/p&gt;




&lt;h2&gt;
  
  
  We happened to have exactly the right application
&lt;/h2&gt;

&lt;p&gt;At Mokapot Labs we maintain a small application called Invoice Assistant.&lt;/p&gt;

&lt;p&gt;It is built with The Pipeline Framework (TPF), an open-source framework for constructing typed processing applications.&lt;/p&gt;

&lt;p&gt;The application receives an invoice and a property catalogue, extracts invoice information, determines which property the invoice belongs to, optionally performs visual analysis when the supplier cannot be established from text, presents the result for human confirmation, and then performs the required external effects.&lt;/p&gt;

&lt;p&gt;Its pipeline includes ordinary computation, AI inference, branching, a human Await boundary and replay-safe Commands.&lt;/p&gt;

&lt;p&gt;Before Jev, its text-analysis stage looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[Invoice] --&amp;gt; B[Extract document text]
    B --&amp;gt; C[Gemma 12B]
    C --&amp;gt; C1[Extract supplier/invoice nr/amount]
    C --&amp;gt; C4[Classify supplier evidence]
    C --&amp;gt; C5[Select property]
    C --&amp;gt; C6[Explain recommendation/w note]
    C1 --&amp;gt; D[Route supplier evidence]
    C4 --&amp;gt; D
    C5 --&amp;gt; D
    C6 --&amp;gt; D
    D --&amp;gt;|Sufficient| E[Review]
    D --&amp;gt;|Insufficient| F[Vision model]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This worked.&lt;/p&gt;

&lt;p&gt;It was not disastrously slow. It was not unreliable enough to force a redesign.&lt;/p&gt;

&lt;p&gt;But the LLM call was doing several fundamentally different jobs.&lt;/p&gt;

&lt;p&gt;And our prompt showed it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The old prompt contained the clue
&lt;/h2&gt;

&lt;p&gt;Part of the original prompt said:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Classify supplier evidence with exactly one qualitative
supplierEvidenceStatus:

EXPLICIT_TEXT
STRONG_TEXTUAL_IDENTITY
INSUFFICIENT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another part said:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Select exactly one property ID present in the supplied
catalogue.

Do not invent, rewrite or normalize property IDs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read those requirements again in the context of a System One model.&lt;/p&gt;

&lt;p&gt;They describe &lt;strong&gt;Choices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We had an LLM generating a result and a prompt instructing it to behave as though the output space were closed.&lt;/p&gt;

&lt;p&gt;But the output space really &lt;em&gt;was&lt;/em&gt; closed.&lt;/p&gt;

&lt;p&gt;For supplier evidence, there were three possible answers.&lt;/p&gt;

&lt;p&gt;For the property recommendation, the possible answers were precisely the properties already supplied to the application.&lt;/p&gt;

&lt;p&gt;The problem was not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate a property identifier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Choose one of these properties.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That difference sounds small.&lt;/p&gt;

&lt;p&gt;Architecturally, it is enormous.&lt;/p&gt;




&lt;h2&gt;
  
  
  But not everything was a Choice
&lt;/h2&gt;

&lt;p&gt;This is where the distinction becomes useful rather than ideological.&lt;/p&gt;

&lt;p&gt;The application also needs to determine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supplier      = "Some arbitrary company name"
invoiceNumber = "INV-2026-18473"
totalAmount   = 68.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are open-world values.&lt;/p&gt;

&lt;p&gt;The supplier can be a string we have never encountered before.&lt;/p&gt;

&lt;p&gt;The invoice number is arbitrary.&lt;/p&gt;

&lt;p&gt;The amount is arbitrary.&lt;/p&gt;

&lt;p&gt;These are extraction problems, and our existing generative LLM remains well suited to them.&lt;/p&gt;

&lt;p&gt;So we did &lt;strong&gt;not&lt;/strong&gt; replace the LLM with Jev.&lt;/p&gt;

&lt;p&gt;We split the problem according to its semantics.&lt;/p&gt;

&lt;p&gt;The result became:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[Invoice] --&amp;gt; B[Extract document text]
    B --&amp;gt; C["Generative LLM&amp;lt;br/&amp;gt;Gemma"]
    C --&amp;gt; C1[Supplier]
    C --&amp;gt; C2[Invoice number]
    C --&amp;gt; C3[Total amount]

    C1 --&amp;gt; D[Prepare DecisionRequest]
    C2 --&amp;gt; D
    C3 --&amp;gt; D

    D --&amp;gt; J["Jev&amp;lt;br/&amp;gt;System One"]
    J --&amp;gt; J1["Supplier evidence&amp;lt;br/&amp;gt;Choice"]
    J --&amp;gt; J2["Property&amp;lt;br/&amp;gt;Choice"]

    J1 --&amp;gt; P[Probabilistic judgments]
    J2 --&amp;gt; P

    P --&amp;gt; R[Deterministic application policy]
    R --&amp;gt;|Sufficient evidence| H[Review]
    R --&amp;gt;|Insufficient evidence| V["Existing vision model&amp;lt;br/&amp;gt;VLM"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The generative model generates.&lt;/p&gt;

&lt;p&gt;The decision model decides.&lt;/p&gt;

&lt;p&gt;The application governs what happens next.&lt;/p&gt;

&lt;p&gt;That separation turned out to be more important than simply changing model providers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The LLM prompt got dramatically smaller
&lt;/h2&gt;

&lt;p&gt;The revised generative step now has a much narrower job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Extract only the supplier, invoice number and total amount
from the invoice evidence.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, perhaps more revealingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not classify supplier evidence,
select a property,
explain a choice,
generate a note...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM is no longer responsible for everything that happens to involve semantic understanding.&lt;/p&gt;

&lt;p&gt;It is responsible for the part of the problem that genuinely requires open-ended extraction.&lt;/p&gt;

&lt;p&gt;That is an important architectural lesson.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Uses AI" is not a sufficient reason for two operations to belong to the same model call.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Their semantic shapes matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  The System One decision is ordinary Java
&lt;/h2&gt;

&lt;p&gt;There was another complication.&lt;/p&gt;

&lt;p&gt;TypeSafe currently publishes official Python and JavaScript/TypeScript SDKs, but not an official Java SDK.&lt;/p&gt;

&lt;p&gt;Invoice Assistant is a Java application.&lt;/p&gt;

&lt;p&gt;We could have waited.&lt;/p&gt;

&lt;p&gt;We could have introduced Python into the application.&lt;/p&gt;

&lt;p&gt;We could have written a thin application-specific HTTP client.&lt;/p&gt;

&lt;p&gt;Instead, this became an opportunity to establish something more reusable in The Pipeline Framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a provider-neutral Java protocol for bounded AI decisions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application constructs an ordinary &lt;code&gt;DecisionRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For supplier evidence, it declares:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DecisionQuestion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"supplierEvidence"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;DecisionQuestionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CHOICE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Judge only the strength of textual evidence identifying the invoice supplier."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DecisionCriterion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"EXPLICIT_TEXT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"The issuer or supplier is directly labelled or named."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DecisionCriterion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"STRONG_TEXTUAL_IDENTITY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Several consistent textual identity cues identify the issuer."&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DecisionCriterion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"INSUFFICIENT"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Text is absent, generic, conflicting, or ambiguous."&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The property decision is constructed dynamically from the application's actual property catalogue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DecisionCriterion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"; "&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;canonicalAddress&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"; aliases: "&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="o"&gt;()))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DecisionQuestion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"property"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;DecisionQuestionType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CHOICE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Select the supplied property best supported by the invoice evidence."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of my favourite consequences of the change.&lt;/p&gt;

&lt;p&gt;Previously we told the LLM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not invent property IDs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the set of possible property IDs &lt;strong&gt;is the decision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The safety property moved from prose into structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  One state, multiple judgments
&lt;/h2&gt;

&lt;p&gt;The application constructs a state containing the information Jev actually needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extractedFacts
invoiceText
originalFilename
properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and submits both questions together.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    S["Decision state&amp;lt;br/&amp;gt;extractedFacts&amp;lt;br/&amp;gt;invoiceText&amp;lt;br/&amp;gt;originalFilename&amp;lt;br/&amp;gt;properties"]
    S --&amp;gt; R[DecisionRequest]
    R --&amp;gt; Q1["supplierEvidence&amp;lt;br/&amp;gt;Choice"]
    R --&amp;gt; Q2["property&amp;lt;br/&amp;gt;Choice"]
    Q1 --&amp;gt; J[Jev]
    Q2 --&amp;gt; J
    J --&amp;gt; A1["Supplier evidence judgment&amp;lt;br/&amp;gt;choice + probabilities"]
    J --&amp;gt; A2["Property judgment&amp;lt;br/&amp;gt;choice + probabilities"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;That maps naturally onto the System One model.&lt;/p&gt;

&lt;p&gt;The application is not conducting an agent conversation with the model.&lt;/p&gt;

&lt;p&gt;It is not asking one question, parsing the answer, constructing another prompt and asking another question.&lt;/p&gt;

&lt;p&gt;It describes the state and the bounded judgments it requires.&lt;/p&gt;

&lt;p&gt;The model evaluates them and returns structured results.&lt;/p&gt;

&lt;p&gt;That is a much more application-shaped interaction.&lt;/p&gt;




&lt;h2&gt;
  
  
  The model judges. Software governs.
&lt;/h2&gt;

&lt;p&gt;This may be the most important architectural property of the whole integration.&lt;/p&gt;

&lt;p&gt;Jev does &lt;strong&gt;not&lt;/strong&gt; decide whether the pipeline should execute visual analysis.&lt;/p&gt;

&lt;p&gt;It does not decide whether the application should ask a human.&lt;/p&gt;

&lt;p&gt;It does not execute another capability.&lt;/p&gt;

&lt;p&gt;It doesn't become the workflow engine.&lt;/p&gt;

&lt;p&gt;It returns judgments.&lt;/p&gt;

&lt;p&gt;The application then applies policy.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    J[Jev] --&amp;gt; P["Probabilistic judgments"]
    P --&amp;gt; A["Deterministic application policy"]
    A --&amp;gt;|Text evidence accepted| R[Review]
    A --&amp;gt;|More evidence required| V[Vision analysis]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This boundary matters.&lt;/p&gt;

&lt;p&gt;A probabilistic model is excellent at answering questions such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which supplied property is most strongly supported by this evidence?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should not automatically acquire authority over:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should the business process do next?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are different concerns.&lt;/p&gt;

&lt;p&gt;TPF makes that distinction very natural.&lt;/p&gt;




&lt;h2&gt;
  
  
  This is where The Pipeline Framework gets interesting
&lt;/h2&gt;

&lt;p&gt;At first glance, integrating a new AI model might sound like a framework feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kind: jev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We deliberately did not do that.&lt;/p&gt;

&lt;p&gt;Jev is not a new kind of pipeline operation.&lt;/p&gt;

&lt;p&gt;From TPF's perspective, Jev observes something the pipeline does not currently know.&lt;/p&gt;

&lt;p&gt;That makes it a &lt;strong&gt;Query&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;TPF's semantic rule is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;known execution-local data   → carry it
fresh external observation   → Query
external side effect         → Command
deferred external completion → Await
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether the external observation came from PostgreSQL, an HTTP API, an LLM or a System One decision model does not fundamentally change that semantic boundary.&lt;/p&gt;

&lt;p&gt;So the pipeline contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Judge Invoice&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
  &lt;span class="na"&gt;cardinality&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ONE_TO_ONE&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InvoiceJudgmentRequest&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InvoiceJudgmentResult&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;invoice-judgment-model&lt;/span&gt;
  &lt;span class="na"&gt;operation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;decide&lt;/span&gt;
  &lt;span class="na"&gt;operationVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the provider binding is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;invoice-judgment-model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;decision.query.jev&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typesafe/jev-1.13&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openrouter-primary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all the pipeline needs to know.&lt;/p&gt;

&lt;p&gt;There is no Jev step kind.&lt;/p&gt;

&lt;p&gt;There is no System One workflow engine.&lt;/p&gt;

&lt;p&gt;There is no Jev-specific branch operator.&lt;/p&gt;

&lt;p&gt;There is simply another typed external observation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Provider-neutral protocol, provider-specific implementation
&lt;/h2&gt;

&lt;p&gt;This distinction is crucial for avoiding framework lock-in.&lt;/p&gt;

&lt;p&gt;The application does not model its domain using Jev's Python SDK classes.&lt;/p&gt;

&lt;p&gt;Its canonical pipeline types refer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;tpf.decision.DecisionRequest&amp;gt;
&amp;lt;tpf.decision.DecisionResult&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application code constructs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;DecisionRequest&lt;/span&gt;
&lt;span class="nc"&gt;DecisionQuestion&lt;/span&gt;
&lt;span class="nc"&gt;DecisionCriterion&lt;/span&gt;
&lt;span class="nc"&gt;DecisionQuestionType&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The provider happens to be &lt;code&gt;decision.query.jev&lt;/code&gt; today.&lt;/p&gt;

&lt;p&gt;The conceptual layering is therefore:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[Application domain]
    A --&amp;gt; P["TPF bounded-decision protocol&amp;lt;br/&amp;gt;DecisionRequest / DecisionResult"]
    P --&amp;gt; Q["TPF Query&amp;lt;br/&amp;gt;decide / v1"]
    Q --&amp;gt; X[Provider adapter]
    X --&amp;gt; J[Jev]
    X -. future .-&amp;gt; O[Another bounded-decision engine]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This is substantially different from writing an unofficial Java clone of TypeSafe's SDK.&lt;/p&gt;

&lt;p&gt;TPF is defining the capability the application needs.&lt;/p&gt;

&lt;p&gt;Jev is implementing it.&lt;/p&gt;

&lt;p&gt;That leaves the application architecture independent of one vendor's client library.&lt;/p&gt;




&lt;h2&gt;
  
  
  Java gets a native System One path in the process
&lt;/h2&gt;

&lt;p&gt;This has an interesting practical consequence.&lt;/p&gt;

&lt;p&gt;TypeSafe's official SDKs currently target Python and JavaScript/TypeScript.&lt;/p&gt;

&lt;p&gt;TPF applications can nevertheless use Jev from Java through ordinary typed application code.&lt;/p&gt;

&lt;p&gt;There is no requirement for a Python sidecar.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    J[Java application] --&amp;gt; DR[DecisionRequest]
    DR --&amp;gt; Q[TPF Query]
    Q --&amp;gt; A[decision.query.jev]
    A --&amp;gt; V[Jev]
    V --&amp;gt; RS[DecisionResult]
    RS --&amp;gt; J&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Nor does application code need to manually construct vendor HTTP payloads.&lt;/p&gt;

&lt;p&gt;And because the Java-facing contract is provider-neutral, this integration is useful beyond Jev itself.&lt;/p&gt;

&lt;p&gt;It establishes bounded probabilistic decisions as an application capability in the Java ecosystem rather than merely exposing one vendor endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  The output contract became better too
&lt;/h2&gt;

&lt;p&gt;The old property recommendation contained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;propertyId
explanation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new result contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;propertyId
confidence
probabilities[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supplier evidence similarly carries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status
confidence
probabilities[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This represents a significant change in what the application expects from AI.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    subgraph Before
        A1[AI] --&amp;gt; A2[Answer]
        A1 --&amp;gt; A3[Prose explanation]
    end

    subgraph After
        B1[AI] --&amp;gt; B2[Judgment]
        B1 --&amp;gt; B3[Confidence]
        B1 --&amp;gt; B4[Probability distribution]
    end&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;We had originally added explanations partly as a crutch while introducing the first real LLM Query into the application.&lt;/p&gt;

&lt;p&gt;But prose explanation and model uncertainty are not the same thing.&lt;/p&gt;

&lt;p&gt;A convincing explanation does not necessarily mean a model is confident.&lt;/p&gt;

&lt;p&gt;A terse answer does not necessarily mean it is uncertain.&lt;/p&gt;

&lt;p&gt;For application decisions, explicit probabilistic information is often much more useful.&lt;/p&gt;

&lt;p&gt;The application can inspect it.&lt;/p&gt;

&lt;p&gt;Policy can act on it.&lt;/p&gt;

&lt;p&gt;Telemetry can record it.&lt;/p&gt;

&lt;p&gt;Humans can see uncertainty where useful.&lt;/p&gt;

&lt;p&gt;And future policy changes do not require rewriting a prompt merely to change what confidence means operationally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dead generative work disappeared
&lt;/h2&gt;

&lt;p&gt;The refactoring also exposed functionality that no longer justified its existence.&lt;/p&gt;

&lt;p&gt;The old model generated a short mnemonic note.&lt;/p&gt;

&lt;p&gt;In practice, it was not used.&lt;/p&gt;

&lt;p&gt;So it disappeared.&lt;/p&gt;

&lt;p&gt;The recommendation explanation had largely existed to make early LLM behaviour inspectable.&lt;/p&gt;

&lt;p&gt;It disappeared too.&lt;/p&gt;

&lt;p&gt;This is another benefit of decomposing model responsibilities.&lt;/p&gt;

&lt;p&gt;Large prompts have a tendency to accumulate requirements because adding another sentence feels cheap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;While you're there, also generate...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But inference responsibilities then become coupled together.&lt;/p&gt;

&lt;p&gt;Once the application explicitly separates extraction, decision, policy and presentation, each output has to justify why it exists.&lt;/p&gt;

&lt;p&gt;That is healthy architecture, AI or otherwise.&lt;/p&gt;




&lt;h2&gt;
  
  
  TPF's Functional Core / Imperative Shell model survives AI
&lt;/h2&gt;

&lt;p&gt;One of the recurring problems in agentic systems is that the model gradually absorbs application architecture.&lt;/p&gt;

&lt;p&gt;The model decides what to call.&lt;/p&gt;

&lt;p&gt;The model decides whether to retry.&lt;/p&gt;

&lt;p&gt;The model decides what state matters.&lt;/p&gt;

&lt;p&gt;The model decides when the workflow is finished.&lt;/p&gt;

&lt;p&gt;Eventually the "application" becomes a prompt wrapped around a tool registry.&lt;/p&gt;

&lt;p&gt;TPF deliberately takes another direction.&lt;/p&gt;

&lt;p&gt;The pipeline owns composition.&lt;/p&gt;

&lt;p&gt;Canonical types own application contracts.&lt;/p&gt;

&lt;p&gt;Queries own fresh observations.&lt;/p&gt;

&lt;p&gt;Commands own external effects and, optionally, deferred completion.&lt;/p&gt;

&lt;p&gt;Ordinary application functions own deterministic business policy.&lt;/p&gt;

&lt;p&gt;AI fits inside those boundaries rather than replacing them.&lt;/p&gt;

&lt;p&gt;Invoice Assistant demonstrates that particularly well.&lt;/p&gt;

&lt;p&gt;The model can judge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supplierEvidence =
    STRONG_TEXTUAL_IDENTITY

confidence =
    0.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but ordinary application code determines what that means for the workflow.&lt;/p&gt;

&lt;p&gt;Likewise, Jev may select a property, but it does not archive the invoice.&lt;/p&gt;

&lt;p&gt;Archiving is an external effect and therefore remains a TPF Command.&lt;/p&gt;

&lt;p&gt;Human property confirmation does not become an agent loop waiting in memory; that, remains an Await boundary.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    P[Typed TPF pipeline]

    P --&amp;gt; Q[Query]
    P --&amp;gt; C[Command (and await)]

    Q --&amp;gt; O[Fresh observation]
    C --&amp;gt; E[External effect]

    O --&amp;gt; L[Generative LLM]
    O --&amp;gt; J[System One / Jev]
    O --&amp;gt; X[Database / API / other provider]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;AI becomes part of software architecture rather than a replacement for it&lt;/p&gt;

</description>
      <category>ai</category>
      <category>jev</category>
      <category>llm</category>
      <category>java</category>
    </item>
    <item>
      <title>One does not simply @Inject in TPF</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Thu, 03 Sep 2026 22:50:05 +0000</pubDate>
      <link>https://dev.to/mbarcia/stop-inject-lm5</link>
      <guid>https://dev.to/mbarcia/stop-inject-lm5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frwr7nhe160aopa3scx5w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frwr7nhe160aopa3scx5w.jpg" alt="One does not simply @Inject in TPF" width="651" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I remember IntelliJ IDEA constantly nudging me away from field injection and toward constructor parameters. Funny how relevant that feels now. The principle was sound: make dependencies explicit. &lt;br&gt;
A pipeline should say what it needs, where it comes from, and how it flows—without invisible framework magic: TPF applies that instinct to the whole application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pipelineframework.org" rel="noopener noreferrer"&gt;https://pipelineframework.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tpf</category>
      <category>springboot</category>
      <category>java</category>
      <category>quarkus</category>
    </item>
    <item>
      <title>Where the business actually lives</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Thu, 09 Jul 2026 18:04:01 +0000</pubDate>
      <link>https://dev.to/mbarcia/where-is-the-business-actually-3h72</link>
      <guid>https://dev.to/mbarcia/where-is-the-business-actually-3h72</guid>
      <description>&lt;p&gt;Read the previous episode here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mbarcia/data-fails-first-3mj3" class="crayons-story__hidden-navigation-link"&gt;Data fails first&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mbarcia" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3186852%2Fc12e3db2-bbe9-47ea-86d4-bfad00f15c5d.JPG" alt="mbarcia profile" class="crayons-avatar__image" width="800" height="1422"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mbarcia" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mariano Barcia
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mariano Barcia
                
                
              
              &lt;div id="story-author-preview-content-3718510" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mbarcia" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3186852%2Fc12e3db2-bbe9-47ea-86d4-bfad00f15c5d.JPG" class="crayons-avatar__image" alt="" width="800" height="1422"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mariano Barcia&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mbarcia/data-fails-first-3mj3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mbarcia/data-fails-first-3mj3" id="article-link-3718510"&gt;
          Data fails first
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tpf"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tpf&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/quarkus"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;quarkus&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/datascience"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;datascience&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/mbarcia/data-fails-first-3mj3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Software has a strange way of rewarding patience.&lt;/p&gt;

&lt;p&gt;When Marta first introduced TPF into the project, some of her colleagues quietly wondered if the pipeline would become just another obstacle everyone would have to avoid. A few months later, those worries faded. The framework became background noise, the business continued to develop, and people only discussed the architecture when they really needed to.&lt;/p&gt;

&lt;p&gt;Marta thought that was probably a good sign.&lt;/p&gt;

&lt;p&gt;In the meantime, the application had evolved. A second developer joined the team, another carrier integrated, customer support got a small dashboard to check failed orders, and finance requested a daily reconciliation process. None of these changes altered the application's core function. They simply made it more useful.&lt;/p&gt;

&lt;p&gt;Looking back, Marta realized this was exactly the evolution she had hoped for. The pipeline lengthened in some areas, new operators appeared, the generated contracts changed with the business, yet the application felt reassuringly familiar. Reading the pipeline from top to bottom still felt a lot like reading a business process. The architecture remained mostly hidden.&lt;/p&gt;

&lt;p&gt;At least, that’s what she thought.&lt;/p&gt;

&lt;p&gt;Daniel spent most of the previous week adding support for another shipping provider. The implementation went smoothly, but during the code review, he hesitated over a change that seemed harmless at first.&lt;/p&gt;

&lt;p&gt;“I changed the pipeline here,” he said, pointing at the screen, “but I’m not sure the business has changed.”&lt;/p&gt;

&lt;p&gt;Marta leaned in.&lt;/p&gt;

&lt;p&gt;The modification was exactly what she expected. One integration replaced another. The tests passed. The contracts still matched. It was technically sound.&lt;/p&gt;

&lt;p&gt;“What’s bothering you?”&lt;/p&gt;

&lt;p&gt;Daniel took a moment before he replied.&lt;/p&gt;

&lt;p&gt;“I’m not sure yet.”&lt;/p&gt;

&lt;p&gt;He closed the pull request without merging it.&lt;/p&gt;

&lt;p&gt;Later that afternoon, Marta found herself at the coffee machine with Elena. Elena had a knack for listening just enough to ask the right question.&lt;/p&gt;

&lt;p&gt;“You look like you’re debugging something that isn’t broken,” Elena said.&lt;/p&gt;

&lt;p&gt;Marta smiled. “Daniel changed a pipeline step. Everything works. But he thinks the business didn’t change.”&lt;/p&gt;

&lt;p&gt;“And you think?”&lt;/p&gt;

&lt;p&gt;“I think he’s right. I just don’t know why.”&lt;/p&gt;

&lt;p&gt;Elena leaned against the counter. “Walk me through it.”&lt;/p&gt;

&lt;p&gt;Marta hesitated for a moment but then began.&lt;/p&gt;

&lt;p&gt;“Orders come in. We validate them. We reserve inventory. We authorize payment. Then we hand things off to the warehouse.”&lt;/p&gt;

&lt;p&gt;“Sounds like a business,” Elena said.&lt;/p&gt;

&lt;p&gt;“It does. But in between, there are steps that don’t feel like that. We wait for a payment provider. We publish messages. We react to callbacks.”&lt;/p&gt;

&lt;p&gt;Elena nodded slowly. “So?”&lt;/p&gt;

&lt;p&gt;“If I read the pipeline as ‘this is how our business works’, some parts feel... different.”&lt;/p&gt;

&lt;p&gt;Elena picked up her cup. “Different how?”&lt;/p&gt;

&lt;p&gt;Marta thought for a moment. “If we stopped validating orders, the business wouldn’t exist. The same goes for inventory or payment decisions.”&lt;/p&gt;

&lt;p&gt;“What about the other parts?”&lt;/p&gt;

&lt;p&gt;“If we changed how orders arrive, or how the warehouse gets notified, the business wouldn’t describe itself any differently.”&lt;/p&gt;

&lt;p&gt;Elena smiled. “So some steps are the business. Others are just how the business talks to the world.”&lt;/p&gt;

&lt;p&gt;Marta blinked. “Yes. Exactly.”&lt;/p&gt;

&lt;p&gt;They stood there for a moment.&lt;/p&gt;

&lt;p&gt;“So what will you do about it?” Elena asked.&lt;/p&gt;

&lt;p&gt;Marta shrugged lightly. “Nothing dramatic. Just… stop pretending they’re the same thing.”&lt;/p&gt;

&lt;p&gt;Elena laughed. “That’s usually a good start.”&lt;/p&gt;

&lt;p&gt;Back at her desk, Marta reopened the pipeline and read it again, this time thinking of Elena’s words; some steps showed decisions the business cared about, and others showed conversations the application needed to have.&lt;/p&gt;

&lt;p&gt;They were all necessary, but they were not the same.&lt;/p&gt;

&lt;p&gt;She leaned back, thinking how right had Daniel been to hesitate and point out the new code hadn’t changed the business, and revealed where the business actually was.&lt;/p&gt;

</description>
      <category>tpf</category>
      <category>fcis</category>
      <category>springboot</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Data fails first</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Thu, 21 May 2026 14:56:57 +0000</pubDate>
      <link>https://dev.to/mbarcia/data-fails-first-3mj3</link>
      <guid>https://dev.to/mbarcia/data-fails-first-3mj3</guid>
      <description>&lt;p&gt;The strange thing was that the first real scaling problems had nothing to do with scale. Or at least, scale as in "infrastructure scale".&lt;/p&gt;

&lt;p&gt;The application was still relatively small. Traffic was growing, yes, but nothing dramatic. CPUs were healthy, latency was acceptable, deployments remained pleasantly uneventful. From the outside, the system still looked exactly like what it technically was: a single Quarkus application running as a monolith, with pipeline steps invoking one another directly inside the same process.&lt;/p&gt;

&lt;p&gt;And yet developers had started speaking about it differently.&lt;/p&gt;

&lt;p&gt;Not formally. Nobody walked into a meeting and announced that “the architecture had changed.” It emerged indirectly, through the kind of comments engineers make when systems begin slipping away from them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Be careful changing that field.”&lt;/li&gt;
&lt;li&gt;“I think another step depends on this.”&lt;/li&gt;
&lt;li&gt;“We should probably keep the old format for compatibility.”&lt;/li&gt;
&lt;li&gt;“I’m not entirely sure who consumes this anymore.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The incidents themselves were subtle enough to avoid triggering panic. Customer support found two apparently identical shipments taking different routing paths. Finance noticed that premium customers occasionally missed SLA prioritization. A new carrier integration introduced a field named &lt;code&gt;region&lt;/code&gt;, while another team added &lt;code&gt;shipping_region&lt;/code&gt;, and for several months both quietly coexisted because somewhere in the middle of the pipeline a mapper handled the ambiguity without anybody realizing it.&lt;/p&gt;

&lt;p&gt;Nothing crashed.&lt;/p&gt;

&lt;p&gt;That was precisely the problem.&lt;/p&gt;

&lt;p&gt;The failures were no longer technical failures. They were semantic failures. The system continued running while different parts of the application slowly stopped agreeing on what the data actually meant.&lt;/p&gt;

&lt;p&gt;Marta recognized the smell immediately because she had seen it before in event-driven and serverless systems: payloads beginning life as wonderfully flexible JSON blobs and gradually hardening into undocumented distributed contracts. Except this time, it was happening entirely inside a monolith.&lt;/p&gt;

&lt;p&gt;That realization bothered her more than any infrastructure issue they had faced so far because it exposed something most engineers rarely think about when they talk about distributed systems.&lt;/p&gt;

&lt;p&gt;When people hear “distributed systems,” they usually imagine the visible mechanics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;remote calls&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;eventual consistency&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;concurrency&lt;/li&gt;
&lt;li&gt;partitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those are often second-order effects. The deeper problem appears much earlier, when independently evolving parts of a system begin sharing meaning imperfectly.&lt;/p&gt;

&lt;p&gt;Two teams interpreting the same field differently. A payload surviving longer than the assumptions under which it was created. Producers and consumers changing independently without realizing the semantic contract between them has drifted.&lt;/p&gt;

&lt;p&gt;That is already a distributed systems problem, even if everything still runs inside one JVM.&lt;/p&gt;

&lt;p&gt;And that was the moment Marta realized something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Distribution is not a deployment problem. It starts as a data problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The architecture diagrams had not changed yet, but the organizational reality already had. Different teams owned different stages of the pipeline. External integrations introduced their own semantics. Some transformations were deterministic and easy to reason about; others depended on databases, carrier APIs, fraud services, and infrastructure outside the team’s control. The application might still have been physically centralized, but conceptually it had already become a collection of independently evolving boundaries.&lt;/p&gt;

&lt;p&gt;That was where TPF started becoming much more than a convenient orchestration framework.&lt;/p&gt;

&lt;p&gt;The team was not using it as a generic workflow interpreter where loosely defined tasks execute dynamically at runtime. What TPF increasingly provided was something much closer to a typed application pipeline compiler: a system capable of understanding the boundaries between stages well enough to generate contracts, validate transformations, wire transports, expose endpoints, and fail builds when parts of the pipeline drifted out of alignment.&lt;/p&gt;

&lt;p&gt;The distinction mattered enormously.&lt;/p&gt;

&lt;p&gt;The pipeline steps themselves remained ordinary application code. Developers wrote Quarkus services, plain Java methods, some reactive Mutiny handlers where concurrency justified the complexity, some blocking implementations where simplicity mattered more than theoretical throughput. Nobody had to abandon the normal ergonomics of application development to “enter the workflow engine.”&lt;/p&gt;

&lt;p&gt;But the boundaries between those steps became explicit.&lt;/p&gt;

&lt;p&gt;Instead of passing anonymous maps through the system and hoping conventions would survive organizational growth, stages now declared typed inputs and outputs, mapper rules, cardinality expectations, operator contracts, and transport compatibility in ways the compiler could actually verify.&lt;/p&gt;

&lt;p&gt;The effect on development was immediate and surprisingly human. Refactoring became less frightening. Teams stopped relying on tribal knowledge to understand dependencies. A mapper mismatch became a compilation error instead of a production incident discovered three weeks later through telemetry dashboards and apologetic Slack messages.&lt;/p&gt;

&lt;p&gt;Peace of mind was alas, restored, once all the data contracts between steps were formalised, and the architecture stopped evolving accidentally.&lt;/p&gt;

</description>
      <category>tpf</category>
      <category>java</category>
      <category>quarkus</category>
      <category>datascience</category>
    </item>
    <item>
      <title>The Lift and Shift</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Thu, 07 May 2026 18:12:31 +0000</pubDate>
      <link>https://dev.to/mbarcia/the-lift-n-shift-378b</link>
      <guid>https://dev.to/mbarcia/the-lift-n-shift-378b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the continuation of &lt;a href="https://dev.to/mbarcia/the-script-that-refused-to-stay-small-1mod"&gt;"The script that refused to stay small"&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The conversation had already been happening for months: three data centers, rising costs, aging hardware, and a growing sense that the whole setup was one incident away from becoming a liability.&lt;/p&gt;

&lt;p&gt;The decision came quickly after the "kalima" event: everything had to move.&lt;/p&gt;

&lt;p&gt;What followed was not elegant, as the platform team scrambled to pull off a lift &amp;amp; shift to the cloud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hypervisor VMs mapped 1:1 into cloud instances&lt;/li&gt;
&lt;li&gt;network rules replicated (and occasionally guessed)&lt;/li&gt;
&lt;li&gt;storage reattached, sometimes awkwardly&lt;/li&gt;
&lt;li&gt;timelines optimistic, then revised, then ignored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most applications... just came along for the ride whilst Marta watched all of this unfold.&lt;/p&gt;

&lt;p&gt;Her service was, technically, just another VM in the inventory. It could have been copied over, like everything else, but the lift and shift was rushed and was accumulating tech debt almost by definition. So she made a different call.&lt;/p&gt;

&lt;p&gt;Instead of following the 1:1 VM migration path, she opted into an early container platform the company had been experimenting with—something not yet standard, slightly under-documented, but good enough.&lt;/p&gt;

&lt;p&gt;Not because she was trying to be innovative, but because her system made it easy.&lt;/p&gt;




&lt;p&gt;Containerizing the application turned out to be almost trivial.&lt;/p&gt;

&lt;p&gt;Quarkus already produced a lean runtime, with the pipeline living inside a single process with well-defined boundaries. There were no hidden dependencies on the host, no fragile startup scripts, no tight coupling to the underlying machine.&lt;/p&gt;

&lt;p&gt;Marta wrote a Dockerfile, wired a couple of environment variables, and that was… mostly it.&lt;/p&gt;

&lt;p&gt;The hardest part wasn’t the application, but everything around it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;getting the right network access&lt;/li&gt;
&lt;li&gt;aligning with security policies&lt;/li&gt;
&lt;li&gt;making sure it could talk to the same external systems as before&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So while most systems were being translated from one VM to another, Marta’s was quietly being repackaged.&lt;/p&gt;

&lt;p&gt;And once it ran, something became clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It was still a monolith&lt;/li&gt;
&lt;li&gt;Steps still called each other directly, in-process&lt;/li&gt;
&lt;li&gt;The pipeline still lived entirely inside a single runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the execution environment had changed.&lt;/p&gt;




&lt;p&gt;That was the first quiet lesson &lt;a href="https://pipelineframework.org" rel="noopener noreferrer"&gt;The Pipeline Framework&lt;/a&gt; taught the team: you can move where something runs without changing how it behaves.&lt;/p&gt;

&lt;p&gt;A few weeks later, someone asked Marta how long her migration had taken; she hesitated (because the honest answer sounded wrong: “About a day. Maybe two, if you count the networking issues.”&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Photo credit: Javier Mediavilla E, CC BY-SA 2.5 &lt;a href="https://creativecommons.org/licenses/by-sa/2.5" rel="noopener noreferrer"&gt;https://creativecommons.org/licenses/by-sa/2.5&lt;/a&gt;, via Wikimedia Commons&lt;/em&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>tpf</category>
      <category>serverless</category>
    </item>
    <item>
      <title>The Script That Refused to Stay Small</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Thu, 09 Apr 2026 21:54:41 +0000</pubDate>
      <link>https://dev.to/mbarcia/the-script-that-refused-to-stay-small-1mod</link>
      <guid>https://dev.to/mbarcia/the-script-that-refused-to-stay-small-1mod</guid>
      <description>&lt;p&gt;It started, as these things often do, with a single process running on a single machine in a server room nobody liked visiting. The system took in shipment requests, enriched them with a few heuristics, and spat out routing hints. Nothing fancy, just enough logic to save operations teams a few hours a day, and Marta built it on her own as a side project.&lt;/p&gt;

&lt;p&gt;Marta wasn’t new to Java, she had spent a few months working in a microservices project in Spring and liked the serverless functional-style thinking: small transformations composed together. She had enough scar-tissue by now having experienced the inevitable issues with Spring and wanted to experiment with Quarkus anyway.&lt;/p&gt;

&lt;p&gt;She picked TPF because, on top of featuring a canvas UI to design the pipeline, she got the complete app's scaffolding as a pure Quarkus project. She could keep developing on her IDE as usual, only with the addition of the Quarkus environment plugin. And, she got to use Dev Services which she also wanted to try.&lt;/p&gt;

&lt;p&gt;Her choices for the script were deliberately boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a JVM runtime (a single process) with&lt;/li&gt;
&lt;li&gt;no high availability&lt;/li&gt;
&lt;li&gt;a traditional direct method invocation between the orchestrator and the pipeline steps&lt;/li&gt;
&lt;li&gt;no DB, just basic HTML responses to human queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each step in the pipeline was just a function. Input came in as loosely structured key/value data. No rigid schema, no upfront modeling, no SQL persistence.&lt;/p&gt;

&lt;p&gt;She didn’t yet have to think about&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;execution tracking or audits&lt;/li&gt;
&lt;li&gt;fan-out/fan-in logic&lt;/li&gt;
&lt;li&gt;retry semantics&lt;/li&gt;
&lt;li&gt;error handling&lt;/li&gt;
&lt;li&gt;availability&lt;/li&gt;
&lt;li&gt;high throughput&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;integrations with 3rd parties&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;li&gt;security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And because she had started using AI-assisted coding tools, even the tests came almost for free, as TPF’s step isolation made it trivial to generate meaningful unit tests for each transformation.&lt;br&gt;
It was fast. It was understandable. It worked and, crucially, it already had shape—even if nobody called it that yet.&lt;/p&gt;

&lt;p&gt;But during one summer's day, a sandstorm from the Sahara impacted  Valencia and caused temperatures to rise (a phenomenon called kalima). The A/C unit in the server room failed and, by the next morning morning, alerts were firing, CPUs were throttling, and someone mentioned, only half jokingly, the possibility of actual fire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0tquvjm4qn8haoc57at.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0tquvjm4qn8haoc57at.webp" alt="Dust cloud over Gandia, Valencia" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>tpf</category>
      <category>unittest</category>
    </item>
    <item>
      <title>Architectural mobility for stronger software</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Tue, 07 Apr 2026 19:37:36 +0000</pubDate>
      <link>https://dev.to/mbarcia/architectural-mobility-for-stronger-software-2nh4</link>
      <guid>https://dev.to/mbarcia/architectural-mobility-for-stronger-software-2nh4</guid>
      <description>&lt;p&gt;There’s a concept in sports science that’s easy to overlook because it sounds so basic: “mobility”. Mobility is defined as “the ability of a joint to move actively through its full, functional range of motion with control, stability, and strength“.&lt;/p&gt;

&lt;p&gt;If you look at a simplified “athlete performance” pyramid, the foundation isn’t power or strength; it’s mobility. Everything else builds on top of that, but we spend most of our time discussing the upper layers and very little attention is paid to what sits at the foundation of the pyramid. Take away mobility, and the strength will falter.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       / - \
      /     \
     / Power \    Athlete Performance Pyramid
    /_________\
   / Strength  \  
  /_____________\
 /   Mobility    \ 
/_________________\
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, the reasons why mobility is so important are many and complex, but basically have to do with how the nervous system is able to recruit muscle fibres, whilst at the same time staying healthy (ie. by doing “reciprocal inhibition”). &lt;/p&gt;

&lt;p&gt;Putting aside the inherent complexity of the muscles in the human body, I think software systems behave in a similar way, and we spend most of our time discussing the upper layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scalability&lt;/li&gt;
&lt;li&gt;throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;whilst paying very little attention to what sits underneath all of that.&lt;/p&gt;

&lt;p&gt;Most software systems miss something fundamental: they cannot change shape without breaking themselves.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You move from containers to functions → everything rewrites&lt;/li&gt;
&lt;li&gt;You switch from REST to gRPC → contracts ripple through the system&lt;/li&gt;
&lt;li&gt;You change how remote work is executed → business logic gets entangled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system might be “strong” in its current form, but it lacks mobility. It’s rarely stated explicitly, and runtime, transport, and protocol are treated as the same decision.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You deploy to containers → you expose REST → you serialise JSON.&lt;/li&gt;
&lt;li&gt;Or you go serverless → you wire HTTP → you pass payloads around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing looks wrong and in fact, it feels coherent, but still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your execution model has dictated your transport&lt;/li&gt;
&lt;li&gt;your transport has dictated your protocol&lt;/li&gt;
&lt;li&gt;and all three together have dictated your system shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This affects “architectural mobility” because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You cannot change where things run without rewriting how they communicate&lt;/li&gt;
&lt;li&gt;You cannot change how they communicate without rewriting what they mean&lt;/li&gt;
&lt;li&gt;You cannot evolve protocols without locking yourself into a runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That mobility is what allows your business logic to evolve regardless of any external infrastructure decision, and will allow you to make these deliberate choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do your workloads belong in containers?&lt;/li&gt;
&lt;li&gt;do your workloads belong in serverless functions?&lt;/li&gt;
&lt;li&gt;do they benefit from gRPC, or REST?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://pipelineframework.org" rel="noopener noreferrer"&gt;The Pipeline Framework&lt;/a&gt;, architectural mobility is enabled by decoupling the transport from the execution platform from the runtime topology, like so: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     Transport
               (LOCAL / REST / gRPC / Proto-HTTP)
                           ↑
                           │
                           │
                           │
                           │
                           │
                           ●───────────────→ Execution Platform
                          /                (COMPUTE / FUNCTION)
                         /
                        /
                       /
                      ↓
             Runtime Topology
  (Monolith / Pipeline / Modular)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Photo credit: &lt;a href="https://unsplash.com/es/@weareambitious" rel="noopener noreferrer"&gt;https://unsplash.com/es/@weareambitious&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
      <category>java</category>
      <category>software</category>
      <category>tpf</category>
    </item>
    <item>
      <title>From majestic monoliths to runtime topologies</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Wed, 25 Mar 2026 21:50:26 +0000</pubDate>
      <link>https://dev.to/mbarcia/from-majestic-monoliths-to-runtime-topologies-497g</link>
      <guid>https://dev.to/mbarcia/from-majestic-monoliths-to-runtime-topologies-497g</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/mbarcia/the-old-works-or-the-humble-monolith-5fdl"&gt;previous post&lt;/a&gt;, I used a scene from &lt;em&gt;The Eternaut&lt;/em&gt; — Favalli starting an old car after an EMP — as a way to introduce the “humble monolith” and how that differs from the "majestic monolith". Also, why the monolith vs microservices discussion is the tree in front of the forest: &lt;strong&gt;rigidity&lt;/strong&gt; is the real problem hiding behind it. So, how could we be more flexible?&lt;/p&gt;

&lt;p&gt;What if we could have the same business logic, adopting not one but &lt;em&gt;many&lt;/em&gt; runtime shapes? I realised that the functional and reactive pipelines underpinning &lt;a href="https://pipelineframework.org" rel="noopener noreferrer"&gt;&lt;strong&gt;The Pipeline Framework&lt;/strong&gt;&lt;/a&gt;, paired with the TPF's own architecture could actually enable &lt;em&gt;choices&lt;/em&gt; for the users: should I go for a monolith? Or deploy steps as microservices? I thought, why have to choose?&lt;/p&gt;

&lt;p&gt;Introducing: runtime topologies in &lt;strong&gt;The Pipeline Framework&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The Pipeline Framework&lt;/strong&gt; treats the &lt;em&gt;business flow&lt;/em&gt; as the stable asset, and the &lt;em&gt;runtime topology&lt;/em&gt; as something that can change over time, and even co-exist (local environment vs. production). Let's take a look at the currently supported runtime topology shapes.&lt;/p&gt;

&lt;p&gt;None of these shapes is inherently “better.” They are just different ways of balancing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how much change you can isolate
&lt;/li&gt;
&lt;li&gt;how much infrastructure you want to operate
&lt;/li&gt;
&lt;li&gt;how much latency you can afford
&lt;/li&gt;
&lt;li&gt;where your security boundaries sit
&lt;/li&gt;
&lt;li&gt;how teams are organised
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet, in most systems, choosing one of these ends up locking you in. TPF instead makes this possible by adapting the input/outputs of each step in an elegant way at build time, to match the runtime shape of choice.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Monolith
&lt;/h3&gt;

&lt;p&gt;Everything runs in-process: steps, orchestrator, and plugins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7xdg5h0msy42onwbnjs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7xdg5h0msy42onwbnjs.png" alt="Monolith runtime topology" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the simplest possible setup. No network hops, minimal operational overhead, very direct debugging.&lt;/p&gt;

&lt;p&gt;The trade-off is clear: everything shares the same blast radius.&lt;/p&gt;




&lt;h3&gt;
  
  
  Pipeline Runtime
&lt;/h3&gt;

&lt;p&gt;Here, the orchestrator is separated, but the pipeline steps still run in a grouped runtime. Plugins are also externalised as shared services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskr2uap6w7id48lbpsxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskr2uap6w7id48lbpsxb.png" alt="Pipeline runtime topology" width="800" height="344"&gt;&lt;/a&gt;&lt;br&gt;
This tends to be a very practical middle ground.&lt;/p&gt;

&lt;p&gt;You get a clear ingress point, reduced exposure of internal components, and some separation of concerns — without fully embracing distributed complexity.&lt;/p&gt;




&lt;h3&gt;
  
  
  Modular / Distributed
&lt;/h3&gt;

&lt;p&gt;Each step becomes independently deployable, and plugins remain shared services rather than being embedded per step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m83lrf8wyn5cyoulh34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m83lrf8wyn5cyoulh34.png" alt="Modular/distributed runtime topology" width="799" height="354"&gt;&lt;/a&gt;&lt;br&gt;
This gives you strong isolation, independent scaling, and clearer ownership boundaries.&lt;/p&gt;

&lt;p&gt;It also introduces the usual trade-offs: more infrastructure, more network hops, and more operational complexity.&lt;/p&gt;




&lt;p&gt;In the framework, the pipeline itself is defined independently of where it runs. Runtime mapping (&lt;code&gt;PipelineRuntimeMapping&lt;/code&gt; and its resolver) determines &lt;em&gt;placement&lt;/em&gt;, not behavior. In the &lt;a href="https://github.com/The-Pipeline-Framework/pipelineframework/blob/main/examples/csv-payments/README.md" rel="noopener noreferrer"&gt;&lt;code&gt;csv-payments&lt;/code&gt;&lt;/a&gt; example, the same pipeline can run as a monolith, inside a pipeline runtime, or in a more modular layout — without rewriting the business logic.&lt;/p&gt;

&lt;p&gt;That separation shows up elsewhere too. Step contracts define intent, mappers isolate boundaries, and services remain focused on transformation logic. Transport concerns don’t leak into the core, which means the system doesn’t become hostage to how components communicate.&lt;/p&gt;

&lt;p&gt;Even at generation level, there’s a single semantic model that gets projected into different execution modes. Local calls, gRPC, REST, protobuf-over-http — they’re not treated as fundamentally different architectures, but as different ways of expressing the same flow.&lt;/p&gt;

&lt;p&gt;And importantly, this isn’t just theoretical. The same reference system is built and tested in more than one topology, so the idea of switching shapes is exercised, not just claimed.&lt;/p&gt;

&lt;p&gt;While the 3 topologies above are actual values in a YAML config, none of this means architecture becomes automatic or point-n-click: you still choose your topology deliberately, and maintain the build.&lt;/p&gt;

&lt;p&gt;But that choice stops being irreversible: if the business flow can outlive the topology, then moving from a monolith to something more distributed (or even back again) stops being a rewrite and becomes a transition.&lt;/p&gt;

&lt;p&gt;And that’s a very different place to be.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>quarkus</category>
      <category>java</category>
    </item>
    <item>
      <title>The old works! (or the humble monolith)</title>
      <dc:creator>Mariano Barcia</dc:creator>
      <pubDate>Mon, 23 Mar 2026 18:47:29 +0000</pubDate>
      <link>https://dev.to/mbarcia/the-old-works-or-the-humble-monolith-5fdl</link>
      <guid>https://dev.to/mbarcia/the-old-works-or-the-humble-monolith-5fdl</guid>
      <description>&lt;p&gt;In the Netflix series The Eternaut, there’s a moment that hits harder than it probably should.&lt;/p&gt;

&lt;p&gt;After the electromagnetic pulse wipes out anything electronic, the world just… stops. Modern cars are useless, cities freeze, everything familiar suddenly becomes fragile.&lt;/p&gt;

&lt;p&gt;Then Favalli finds an old car and tries to start it.&lt;/p&gt;

&lt;p&gt;And it works.&lt;/p&gt;

&lt;p&gt;“Lo viejo funciona, Juan.” &lt;em&gt;("the old works, Juan")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s a simple line, but it lands because it does something subtle: it pulls you back in time. Not just to “older technology,” but to a different world — ten, twenty, forty years ago — when things worked differently, when we were different, when the assumptions we made about the future were completely different.&lt;/p&gt;

&lt;p&gt;That feeling shows up in a lot of stories. A forgotten machine that still works. An old tool that suddenly becomes essential. Not because it’s better, but because it was built for a different context — and somehow fits the present moment again.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Over the past few years, many microservices projects have turned into cautionary tales: systems that looked elegant on paper but became difficult to operate, evolve, or even understand.&lt;/p&gt;

&lt;p&gt;In response, the idea of the “majestic monolith” has made a comeback.&lt;/p&gt;

&lt;p&gt;And to be fair, there are majestic monoliths — just like there are beautifully restored classic cars. Carefully engineered, impressive, and sometimes exactly the right thing.&lt;/p&gt;

&lt;p&gt;But also, very expensive and time-consuming and perhaps over-engineered, which is why that framing can be misleading.&lt;/p&gt;

&lt;p&gt;Because most systems don’t need to be majestic. They need to be appropriate for their context, especially over the next one, two, or three years.&lt;/p&gt;

&lt;p&gt;If you’re honest about those constraints, the question becomes less ideological and more practical: what kind of system will let you move, adapt, and operate with the least friction?&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;That’s where the idea of the “humble monolith” feels more grounded.&lt;/p&gt;

&lt;p&gt;Not as a statement, but as a baseline.&lt;/p&gt;

&lt;p&gt;A system with fewer moving parts, clearer boundaries, and behavior that is easier to reason about when something goes wrong. Something you can understand without needing to reconstruct a distributed narrative across multiple components.&lt;/p&gt;

&lt;p&gt;Of course, monoliths can degrade into tightly coupled, hard-to-change systems. We’ve all seen that.&lt;/p&gt;

&lt;p&gt;But so can distributed architectures — and often in ways that are harder to see and harder to fix.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Which points to the real issue.&lt;/p&gt;

&lt;p&gt;The problem is not monolith vs microservices.&lt;/p&gt;

&lt;p&gt;It’s rigidity.&lt;/p&gt;

&lt;p&gt;We make architectural decisions early, based on assumptions about scale, growth, and future needs. And then those decisions get embedded into the system in ways that are difficult to reverse.&lt;/p&gt;

&lt;p&gt;What started as a good fit becomes a constraint.&lt;/p&gt;

&lt;p&gt;The system needs to evolve, but the architecture doesn’t.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Maybe that’s why moments like “lo viejo funciona” resonate so much.&lt;/p&gt;

&lt;p&gt;Not because the past was better, but because it reminds us that different choices made sense under different conditions — and that those choices can still be valid when circumstances change.&lt;/p&gt;

&lt;p&gt;In software, we rarely give ourselves that flexibility.&lt;/p&gt;

&lt;p&gt;We pick a shape, and we’re stuck with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9v0yrj3a810a9k9s3w3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9v0yrj3a810a9k9s3w3.webp" alt="Juan and Favalli in The Eternaut" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next post, I’ll explore a different approach: what it looks like when architecture becomes a runtime decision, and how the same system can take on different shapes — from a humble monolith to something more distributed — without rewriting everything.&lt;/p&gt;

&lt;p&gt;Because sometimes, what matters isn’t choosing the right architecture upfront.&lt;/p&gt;

&lt;p&gt;It’s being able to choose again when the world changes.&lt;/p&gt;




&lt;p&gt;Thank you for having reached this far, I hope you find these ideas interesting. Now, have you worked on monoliths? how would you call it :-) , Or perhaps, contributed to projects using microservices or server-less architecture? I'm curious to hear from you in the comments! &lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Photo credits:&lt;br&gt;
El Eternauta. César Troncoso As Favalli In El Eternauta. Cr. Marcos Ludevid / Netflix ©2025&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>discuss</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
