<?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: Alok Ranjan Daftuar</title>
    <description>The latest articles on DEV Community by Alok Ranjan Daftuar (@aloknecessary).</description>
    <link>https://dev.to/aloknecessary</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%2F3791551%2F62fbfeb5-1fba-4e79-bc4b-780b7ce52748.jpg</url>
      <title>DEV Community: Alok Ranjan Daftuar</title>
      <link>https://dev.to/aloknecessary</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aloknecessary"/>
    <language>en</language>
    <item>
      <title>Multi-Cluster ArgoCD Architecture: Hub-and-Spoke vs. Per-Cluster, Done Right</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Mon, 10 Aug 2026 05:48:33 +0000</pubDate>
      <link>https://dev.to/aloknecessary/multi-cluster-argocd-architecture-hub-and-spoke-vs-per-cluster-done-right-p17</link>
      <guid>https://dev.to/aloknecessary/multi-cluster-argocd-architecture-hub-and-spoke-vs-per-cluster-done-right-p17</guid>
      <description>&lt;p&gt;Every ArgoCD tutorial ends with one cluster, one ArgoCD instance, and &lt;code&gt;kubectl config current-context&lt;/code&gt; pointing at the same place ArgoCD is installed. That works fine — until you have two clusters. By the time you're at 10 or 15, across AWS and Azure, the architecture you picked on day one is either quietly paying for itself or quietly costing you an incident a quarter.&lt;/p&gt;

&lt;p&gt;The two dominant patterns — hub-and-spoke and ArgoCD-per-cluster — are both reasonable in the right context and both wrong when applied past the cluster count and team topology they were designed for.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Two Bad Defaults Teams Back Into
&lt;/h2&gt;

&lt;p&gt;Rather than choosing deliberately, most teams end up at one of two failure modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ArgoCD-per-cluster sprawl&lt;/strong&gt; — every cluster gets its own ArgoCD because that's what the getting-started guide showed. Nobody has a single view of what's deployed where. Upgrading ArgoCD becomes N separate change requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single hub that becomes a bottleneck&lt;/strong&gt; — one team stands up ArgoCD once, registers every cluster against it, and doesn't revisit that decision until the application controller is falling behind on reconciliation or a hub outage takes down deployments for every team at once.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Pattern 1: Hub-and-Spoke
&lt;/h2&gt;

&lt;p&gt;One management cluster runs ArgoCD. Every other cluster is registered as a remote destination via a &lt;code&gt;Secret&lt;/code&gt; containing that cluster's API server address and credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt; single pane of glass, centralized RBAC and SSO, one audit trail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it costs you:&lt;/strong&gt; the hub becomes a scaling bottleneck at high cluster/Application count; blast radius covers every spoke if the hub is compromised; network reachability to every spoke's API server is a real design requirement, not just an IAM policy.&lt;/p&gt;

&lt;p&gt;Two blast-radius shapes worth planning for specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis under memory pressure&lt;/strong&gt; — ArgoCD's application controller caches live-vs-desired state in Redis across every Application it manages. An OOM or eviction storm on that single Redis instance stalls reconciliation for every cluster the hub manages simultaneously. From the outside it looks like "ArgoCD is stuck everywhere" — the root cause is capacity planning on a component most teams treat as an implementation detail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A quietly broken peering path&lt;/strong&gt; — a security group rule tightened on one spoke's cluster security group doesn't fail loudly. It shows up as that spoke going &lt;code&gt;Unknown&lt;/code&gt; in the UI while everything else stays green, easy to dismiss as a blip until someone needs to ship a fix to that cluster and can't.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network Reachability — The Part Tutorials Skip
&lt;/h3&gt;

&lt;p&gt;On &lt;strong&gt;AWS&lt;/strong&gt;: VPC peering or Transit Gateway gets the hub's control plane traffic to each spoke's private EKS API server endpoint. Private API server endpoints are the right default for spoke clusters, but every private-by-default decision adds a network path the hub now has to be deliberately connected to.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;Azure&lt;/strong&gt;: VNet peering or Azure Private Link between the hub's VNet and each spoke AKS cluster's VNet. Same shape of problem — the hub's egress needs a routable, authorized path to a spoke's control plane.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controller Sharding Past 10 Clusters
&lt;/h3&gt;

&lt;p&gt;A hub managing 12 spoke clusters with ~50 Applications each (600 total) on a single unsharded controller will start lagging live cluster state by 3-4 minutes during normal operation, and considerably longer after a bulk change. The fix is multiple controller replicas with shard annotations on cluster secrets:&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="c1"&gt;# argocd-application-controller StatefulSet&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cluster Secret with shard annotation&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/shard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;ARGOCD_CONTROLLER_REPLICAS=4&lt;/code&gt; and shard annotations spread across 12 spoke secrets, each replica watches 3 clusters instead of all 12 — reconciliation lag drops back to single-digit seconds. This change isn't complete without also moving to a Redis HA (Sentinel-backed) deployment, since a single Redis becomes the new bottleneck once four controller replicas hit it concurrently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pattern 2: ArgoCD-per-Cluster
&lt;/h2&gt;

&lt;p&gt;Each cluster runs its own ArgoCD instance and manages only itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt; fault isolation, no cross-cluster network dependency, clean blast radius.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it costs you:&lt;/strong&gt; N places to upgrade and patch; fragmented visibility; RBAC and project config duplicated N times with all the drift that implies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where this genuinely wins:&lt;/strong&gt; regulated environments where a cluster's isolation boundary is a compliance requirement; air-gapped clusters with no viable network path back to a central hub; edge deployments where each site operates independently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cluster Registration — EKS
&lt;/h2&gt;

&lt;p&gt;The clean way to register a spoke EKS cluster is IRSA or EKS access entries — not a static kubeconfig with a long-lived token. The cluster secret uses the &lt;code&gt;aws eks get-token&lt;/code&gt; exec plugin:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&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;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&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;spoke-eks-prod-us-east-1&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/secret-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&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;spoke-eks-prod-us-east-1&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://EXAMPLE1234567890.gr7.us-east-1.eks.amazonaws.com&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"execProviderConfig": {&lt;/span&gt;
        &lt;span class="s"&gt;"command": "aws",&lt;/span&gt;
        &lt;span class="s"&gt;"args": [&lt;/span&gt;
          &lt;span class="s"&gt;"eks", "get-token",&lt;/span&gt;
          &lt;span class="s"&gt;"--cluster-name", "spoke-eks-prod",&lt;/span&gt;
          &lt;span class="s"&gt;"--region", "us-east-1",&lt;/span&gt;
          &lt;span class="s"&gt;"--role-arn", "arn:aws:iam::111122223333:role/argocd-hub-spoke-access"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"apiVersion": "client.authentication.k8s.io/v1beta1"&lt;/span&gt;
      &lt;span class="s"&gt;},&lt;/span&gt;
      &lt;span class="s"&gt;"tlsClientConfig": { "insecure": false, "caData": "&amp;lt;base64 cluster CA&amp;gt;" }&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full chain: create the IAM role on the spoke account with a trust policy scoped to the hub's IRSA role → create an EKS access entry mapping that role to a Kubernetes group → bind that group to a scoped &lt;code&gt;ClusterRole&lt;/code&gt; (not cluster-admin) → grant the hub's IRSA service account &lt;code&gt;sts:AssumeRole&lt;/code&gt; → apply the Secret → verify with &lt;code&gt;argocd cluster list&lt;/code&gt;. A &lt;code&gt;Successful&lt;/code&gt; status confirms the exec plugin chain worked end to end.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cluster Registration — AKS
&lt;/h2&gt;

&lt;p&gt;On AKS, the equivalent is Azure AD Workload Identity with the &lt;code&gt;kubelogin&lt;/code&gt; exec plugin:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&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;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&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;spoke-aks-prod-westeurope&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;argocd.argoproj.io/secret-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cluster&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&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;spoke-aks-prod-westeurope&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://spoke-aks-prod-dns-a1b2c3d4.hcp.westeurope.azmk8s.io&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"execProviderConfig": {&lt;/span&gt;
        &lt;span class="s"&gt;"command": "kubelogin",&lt;/span&gt;
        &lt;span class="s"&gt;"args": [&lt;/span&gt;
          &lt;span class="s"&gt;"get-token",&lt;/span&gt;
          &lt;span class="s"&gt;"--login", "workloadidentity",&lt;/span&gt;
          &lt;span class="s"&gt;"--server-id", "6dae42f8-4368-4678-94ff-3960e28e3630"&lt;/span&gt;
        &lt;span class="s"&gt;],&lt;/span&gt;
        &lt;span class="s"&gt;"apiVersion": "client.authentication.k8s.io/v1beta1"&lt;/span&gt;
      &lt;span class="s"&gt;},&lt;/span&gt;
      &lt;span class="s"&gt;"tlsClientConfig": { "insecure": false, "caData": "&amp;lt;base64 cluster CA&amp;gt;" }&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full chain: create an Azure AD application + federated identity credential binding the hub's ArgoCD service account to it → grant that application a scoped AKS RBAC role on the spoke cluster → label the hub's ArgoCD service account for workload identity → apply the Secret → verify with &lt;code&gt;argocd cluster list&lt;/code&gt;. Auth failures here are almost always a &lt;code&gt;--subject&lt;/code&gt; mismatch in the federated credential or the workload identity label missing from the pod spec.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision Framework
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cluster count&lt;/th&gt;
&lt;th&gt;Compliance boundary&lt;/th&gt;
&lt;th&gt;Team topology&lt;/th&gt;
&lt;th&gt;Recommended pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Single platform team&lt;/td&gt;
&lt;td&gt;Hub-and-spoke&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3-5&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Single or lightly federated&lt;/td&gt;
&lt;td&gt;Hub-and-spoke with AppProjects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-10&lt;/td&gt;
&lt;td&gt;Some (staging vs. prod)&lt;/td&gt;
&lt;td&gt;Multiple product teams&lt;/td&gt;
&lt;td&gt;Hub-and-spoke, watch controller sharding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10-15&lt;/td&gt;
&lt;td&gt;Regulatory/contractual isolation on specific clusters&lt;/td&gt;
&lt;td&gt;Multiple teams, some regulated&lt;/td&gt;
&lt;td&gt;Hybrid — hub for general fleet, per-cluster for isolated outliers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;Air-gapped / no viable hub network path&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;ArgoCD-per-cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The hybrid row in practice: a platform team running 13 clusters — 10 standard clusters registering against the hub via IRSA/workload identity, plus 3 PCI-scoped clusters each running their own ArgoCD with no network path back to the hub, syncing from a separate access-restricted Git repository. The platform team accepts fragmented visibility for those 3 clusters in exchange for not having to argue, in every audit cycle, that the hub's blast radius doesn't touch the PCI boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is Article 1 of the GitOps in Practice series. The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hub-and-spoke network reachability deep-dive for EKS (VPC peering, private API server endpoints, Transit Gateway) and AKS (VNet peering, Azure Private Link)&lt;/li&gt;
&lt;li&gt;Complete step-by-step EKS auth chain: IAM role creation, EKS access entry, ClusterRoleBinding, hub-side IRSA policy&lt;/li&gt;
&lt;li&gt;Complete step-by-step AKS auth chain: Azure AD app, federated credential, AKS RBAC role assignment, workload identity label&lt;/li&gt;
&lt;li&gt;Controller sharding mechanics and Redis HA requirements for fleets past 10-15 clusters&lt;/li&gt;
&lt;li&gt;The trust-boundary thinking connecting IRSA/Workload Identity to ArgoCD's cluster auth model&lt;/li&gt;
&lt;li&gt;What's coming in Article 2: repo structure, App-of-Apps, ApplicationSets, and AppProjects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/multi-cluster-argocd-architecture/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=multi-cluster-argocd-architecture" rel="noopener noreferrer"&gt;Multi-Cluster ArgoCD Architecture — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>devops</category>
      <category>argocd</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>GitHub Actions OIDC: Eliminating Long-Lived Credentials from Your CI/CD Pipeline</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Fri, 07 Aug 2026 04:49:30 +0000</pubDate>
      <link>https://dev.to/aloknecessary/github-actions-oidc-eliminating-long-lived-credentials-from-your-cicd-pipeline-gmg</link>
      <guid>https://dev.to/aloknecessary/github-actions-oidc-eliminating-long-lived-credentials-from-your-cicd-pipeline-gmg</guid>
      <description>&lt;p&gt;Every GitHub Actions workflow that deploys to AWS or Azure needs cloud credentials. The traditional answer — generate an IAM access key or Azure client secret, store it in GitHub secrets — works, but means you have a long-lived credential that's valid until you notice it leaked and manually revoke it.&lt;/p&gt;

&lt;p&gt;OpenID Connect eliminates this at the architectural level. Your workflow requests a short-lived token from GitHub's OIDC provider, exchanges it with AWS STS or Azure's token endpoint, and receives temporary credentials valid for the duration of the job. No secret to store. No credential to rotate. No static value to leak.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub Actions Job
    │  1. Requests OIDC token from GitHub
    ▼
GitHub OIDC Provider (token.actions.githubusercontent.com)
    │  2. Issues signed JWT (sub, repo, ref, environment, exp: 5min)
    ▼
AWS STS / Azure Token Endpoint
    │  3. Validates JWT, checks trust policy conditions
    │  4. Issues temporary credentials (15min–1hr)
    ▼
GitHub Actions Job (continues with scoped credentials)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sub&lt;/code&gt; claim encodes the repository, branch, and environment — every trust policy decision is a decision about which &lt;code&gt;sub&lt;/code&gt; values you trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trust Policy Scoping — The Critical Detail
&lt;/h2&gt;

&lt;p&gt;Most tutorials show the broadest condition that works. Production requires precision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;repo:org/repo:environment:production&lt;/code&gt;&lt;/strong&gt; — strongest for production; coupled to GitHub Environment protection rules (required reviewers, deployment gates)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;repo:org/repo:ref:refs/heads/main&lt;/code&gt;&lt;/strong&gt; — good for staging; only main branch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;repo:org/repo:*&lt;/code&gt;&lt;/strong&gt; — acceptable for dev/sandbox only&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;repo:org/*&lt;/code&gt;&lt;/strong&gt; — never use for anything with real permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The environment-scoped condition means an unapproved deployment cannot produce the token needed to assume the production role. The gate is enforced at the identity layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Per-Job Role Architecture
&lt;/h2&gt;

&lt;p&gt;Because each job gets its own fresh token, you can scope each job to exactly the permissions it needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plan job&lt;/strong&gt; → read-only role, branch-scoped trust&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build &amp;amp; push job&lt;/strong&gt; → ECR/ACR push permissions only, branch-scoped trust&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy job&lt;/strong&gt; → deployment permissions, environment-scoped trust with approval gate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One role per responsibility. Minimum permissions per role. The blast radius of any single compromised job is limited to its specific task.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Audit Trail Static Credentials Cannot Provide
&lt;/h2&gt;

&lt;p&gt;Every OIDC credential issuance produces a CloudTrail event with the full GitHub context — repository, branch, workflow run, commit. The &lt;code&gt;role-session-name&lt;/code&gt; encodes the GitHub run ID, so every subsequent API call is traceable to the exact workflow execution.&lt;/p&gt;

&lt;p&gt;With static access keys, you see the IAM user name — shared across all workflows, with no way to distinguish which run triggered each API call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Migration Path
&lt;/h2&gt;

&lt;p&gt;The sequence that eliminates risk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the IAM role / Azure federated credential with correct trust policy&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;id-token: write&lt;/code&gt; permission to the workflow job&lt;/li&gt;
&lt;li&gt;Add OIDC credential step — leave static credential commented but present&lt;/li&gt;
&lt;li&gt;Verify end-to-end on a branch&lt;/li&gt;
&lt;li&gt;Remove static credential step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete the credential from the cloud provider&lt;/strong&gt; — not just from GitHub secrets&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 6 is what most teams defer indefinitely. The credential still exists and could be used by anyone with direct knowledge of the key.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a condensed version. The full article includes complete, production-ready implementations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/github-actions-oidc/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=github-actions-oidc" rel="noopener noreferrer"&gt;GitHub Actions OIDC: Eliminating Long-Lived Credentials — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete AWS setup (OIDC provider + IAM role with Terraform)&lt;/li&gt;
&lt;li&gt;Complete Azure setup (Entra ID app registration + federated credentials)&lt;/li&gt;
&lt;li&gt;Full workflow files for AWS ECR+ECS and Azure ACR+AKS deployments&lt;/li&gt;
&lt;li&gt;Reusable workflow federation with &lt;code&gt;job_workflow_ref&lt;/code&gt; claim customisation&lt;/li&gt;
&lt;li&gt;Common failure modes and debug steps (token expiry, trust policy mismatches)&lt;/li&gt;
&lt;li&gt;Production checklist for retiring static credentials&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>Cloud Security Architecture: From Shared Responsibility to Zero Trust</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Fri, 31 Jul 2026 10:24:18 +0000</pubDate>
      <link>https://dev.to/aloknecessary/cloud-security-architecture-from-shared-responsibility-to-zero-trust-4jc7</link>
      <guid>https://dev.to/aloknecessary/cloud-security-architecture-from-shared-responsibility-to-zero-trust-4jc7</guid>
      <description>&lt;p&gt;Cloud security incidents that make news are rarely the result of a novel attack technique. They are the result of misconfiguration, over-permissioned identities, and static credentials left in places where attackers have learned to look automatically.&lt;/p&gt;

&lt;p&gt;This post covers the architectural decisions that prevent those incidents — made early, before the first breach, rather than in response to one.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Shared Responsibility Model — What You Actually Own
&lt;/h2&gt;

&lt;p&gt;The rows that never move to the provider regardless of service model: identity and access, application configuration, secrets management, and data encryption. Treating "we use managed Kubernetes" as implying "security is largely handled" is the category error that makes managed services into false comfort.&lt;/p&gt;

&lt;p&gt;Three items teams most commonly miscategorise as provider responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encryption at rest&lt;/strong&gt; — provider-managed keys mean the provider could theoretically decrypt your data. You own the key management decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network exposure&lt;/strong&gt; — a LoadBalancer service type provisions a public IP by default. Nothing prevents a developer from exposing an internal service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM overprivilege&lt;/strong&gt; — the provider supplies IAM. What role gets attached to which workload is entirely yours.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. IAM Least-Privilege at Scale
&lt;/h2&gt;

&lt;p&gt;IAM posture degrades monotonically — it gets worse over time, never better, unless you actively intervene. Three structural controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ABAC over RBAC&lt;/strong&gt; — evaluate permissions dynamically based on attributes rather than maintaining named roles that accumulate permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission boundaries&lt;/strong&gt; — set the maximum permissions a role can ever have, regardless of what policies are attached&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SCPs&lt;/strong&gt; — organisation-wide guardrails that cannot be overridden at the account level&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Secrets Management — No Static Credentials
&lt;/h2&gt;

&lt;p&gt;70% of leaked secrets remain active 2 years after exposure. The goal: eliminate long-lived static credentials entirely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IRSA / Workload Identity&lt;/strong&gt; — pods assume cloud IAM roles without possessing any credential file, via OIDC federation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSI driver mounts&lt;/strong&gt; — secrets mounted as files, refreshed on rotation without pod restart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The rule:&lt;/strong&gt; no secret should ever appear in a Docker image, Kubernetes manifest, GitHub repository, CI/CD log, or environment variable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Network Segmentation
&lt;/h2&gt;

&lt;p&gt;Network controls reduce blast radius when an identity is compromised. A well-segmented VPC separates traffic by function and trust level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnets (ALB/NLB only) → Private app subnets → Private data subnets&lt;/li&gt;
&lt;li&gt;VPC endpoints for all cloud services (S3, Secrets Manager, ECR, STS)&lt;/li&gt;
&lt;li&gt;No application or data tier resource has a public IP&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Zero Trust for Kubernetes
&lt;/h2&gt;

&lt;p&gt;Kubernetes ships open-by-default. Three gaps to close:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default-deny NetworkPolicy&lt;/strong&gt; in every namespace, with explicit allow policies for required communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pod Security Admission&lt;/strong&gt; — &lt;code&gt;baseline&lt;/code&gt; enforced on application namespaces, &lt;code&gt;restricted&lt;/code&gt; warned&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One ServiceAccount per workload&lt;/strong&gt; — &lt;code&gt;automountServiceAccountToken: false&lt;/code&gt; at SA level, opt-in per pod&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. CI/CD Pipeline Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OIDC authentication&lt;/strong&gt; — no long-lived credentials stored in GitHub secrets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image signing at build, verification at admission&lt;/strong&gt; — unsigned images rejected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerability scanning blocking&lt;/strong&gt; — high/critical CVEs fail the build&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret scanning on push&lt;/strong&gt; — any secret in source control treated as compromised&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Detection — What to Alert On
&lt;/h2&gt;

&lt;p&gt;High-signal events: root account login, IAM policy changes in production, security group rules allowing &lt;code&gt;0.0.0.0/0&lt;/code&gt;, CloudTrail disabled, &lt;code&gt;kubectl exec&lt;/code&gt; into production pods, secrets accessed from unexpected roles.&lt;/p&gt;

&lt;p&gt;Enable GuardDuty / Defender for Cloud before you need them — post-incident enablement loses the historical baseline.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of the fifth and final post in the Cloud Architecture series. The full article includes detailed IAM policy examples, IRSA/Workload Identity configuration, NetworkPolicy manifests, Pod Security Admission labels, GitHub Actions OIDC setup, and a comprehensive production-readiness checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/cloud-security-architecture/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=cloud-security-architecture" rel="noopener noreferrer"&gt;Cloud Security Architecture: From Shared Responsibility to Zero Trust — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared responsibility matrix across IaaS/CaaS/PaaS&lt;/li&gt;
&lt;li&gt;Permission boundary and SCP JSON examples&lt;/li&gt;
&lt;li&gt;IRSA and Workload Identity ServiceAccount configuration&lt;/li&gt;
&lt;li&gt;Secrets Manager CSI driver SecretProviderClass manifest&lt;/li&gt;
&lt;li&gt;Default-deny NetworkPolicy with explicit allow rules&lt;/li&gt;
&lt;li&gt;Pod Security Admission namespace labels&lt;/li&gt;
&lt;li&gt;GitHub Actions OIDC workflow with scoped trust policy&lt;/li&gt;
&lt;li&gt;Complete cloud security architecture checklist (25+ items)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>architecture</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Embedding Model Selection for Production: The Decision Nobody Documents</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Tue, 28 Jul 2026 08:16:17 +0000</pubDate>
      <link>https://dev.to/aloknecessary/embedding-model-selection-for-production-the-decision-nobody-documents-2o73</link>
      <guid>https://dev.to/aloknecessary/embedding-model-selection-for-production-the-decision-nobody-documents-2o73</guid>
      <description>&lt;p&gt;Every RAG architecture diagram has a box labeled "embed." Almost nobody documents how that box's contents got chosen, and almost everybody regrets the choice within eighteen months. Changing embedding models means re-embedding your entire corpus — vectors from different models are not compatible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Decision Matters
&lt;/h2&gt;

&lt;p&gt;Retrieval quality is bounded by embedding quality. A perfectly tuned chunking strategy, re-ranker, and hybrid pipeline cannot retrieve a document whose embedding never placed it near the query in vector space. And the cost of getting this wrong is not a quick fix — it's a migration project.&lt;/p&gt;




&lt;h2&gt;
  
  
  What MTEB Tells You (and Doesn't)
&lt;/h2&gt;

&lt;p&gt;MTEB is a reasonable first filter — it aggregates performance across retrieval, classification, and clustering tasks. What it does NOT tell you: how a model performs on &lt;em&gt;your&lt;/em&gt; documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical rule:&lt;/strong&gt; Use MTEB to build a shortlist of 3–5 candidates. Never to make the final decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark on Your Own Corpus
&lt;/h2&gt;

&lt;p&gt;The only benchmark that predicts production retrieval quality is one run against your own documents and representative queries. Build a golden set of 80–100+ query-to-relevant-document pairs, run each candidate through the same pipeline, measure Recall@K and MRR.&lt;/p&gt;

&lt;p&gt;The gap between MTEB rank and corpus-specific performance is frequently large enough to flip a recommendation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dimensionality and Matryoshka Trade-offs
&lt;/h2&gt;

&lt;p&gt;Matryoshka Representation Learning (supported by most 2026 providers) lets you truncate a 3072-dim vector to 512 or 256 dimensions post-hoc without re-running the model. This enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full dimensions for high-precision compliance search&lt;/li&gt;
&lt;li&gt;Truncated dimensions for low-latency autocomplete on the same corpus&lt;/li&gt;
&lt;li&gt;No separate embedding pass required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benchmark the quality drop at each truncation point before committing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost Modeling at Scale
&lt;/h2&gt;

&lt;p&gt;Two components that scale differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Indexing cost&lt;/strong&gt; — one-time, proportional to corpus size&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query cost&lt;/strong&gt; — ongoing, proportional to traffic volume&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model that looks cheap per-token can be expensive at your actual corpus size. Model cost at your real numbers, not the pricing page.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Re-Embedding Migration Problem
&lt;/h2&gt;

&lt;p&gt;Vectors from different models are not interchangeable. Switching providers means re-embedding the entire corpus. The mitigation is architectural:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design the re-indexing pipeline before you need it&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;dual_write&lt;/code&gt; strategy: write both old and new vectors during transition&lt;/li&gt;
&lt;li&gt;Benchmark new collection against golden set before atomic cutover&lt;/li&gt;
&lt;li&gt;Prefer self-hosted models when deprecation risk is the primary concern&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Fine-Tuned Embeddings Beat General-Purpose
&lt;/h2&gt;

&lt;p&gt;Fine-tuning reliably improves retrieval by 10–30% for genuinely specialized domains. But only move to fine-tuning if your corpus benchmark shows a real, sustained gap — not a hypothetical concern.&lt;/p&gt;

&lt;p&gt;Check whether a domain-specific model already exists (e.g., code-specific variants) before investing in custom fine-tuning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of the seventh post in the RAG and AI Engineering series. The full article includes complete benchmarking code, cost modeling functions, the re-indexing migration architecture, decision matrix, and production checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/embedding-model-selection/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=embedding-model-selection" rel="noopener noreferrer"&gt;Embedding Model Selection for Production — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python benchmarking code for corpus-specific Recall@K and MRR evaluation&lt;/li&gt;
&lt;li&gt;Matryoshka truncation implementation with re-normalization&lt;/li&gt;
&lt;li&gt;Cost modeling function at actual corpus and traffic scale&lt;/li&gt;
&lt;li&gt;Re-embedding migration architecture with dual-write cutover strategy&lt;/li&gt;
&lt;li&gt;Decision matrix by situation (multilingual, code, regulated, budget-constrained)&lt;/li&gt;
&lt;li&gt;Complete embedding selection checklist for production readiness&lt;/li&gt;
&lt;li&gt;When fine-tuned domain embeddings are justified vs premature&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>embeddings</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Cloud Cost Architecture: Engineering FinOps Into the System, Not Onto It</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Mon, 20 Jul 2026 09:30:40 +0000</pubDate>
      <link>https://dev.to/aloknecessary/cloud-cost-architecture-engineering-finops-into-the-system-not-onto-it-5362</link>
      <guid>https://dev.to/aloknecessary/cloud-cost-architecture-engineering-finops-into-the-system-not-onto-it-5362</guid>
      <description>&lt;p&gt;Cost is an architectural concern, not a finance concern. The decisions that determine your cloud bill are made in pull requests touching Terraform files and Kubernetes manifests — weeks before the invoice arrives. By the time finance highlights the line items, the spend has already happened.&lt;/p&gt;

&lt;p&gt;Cloud waste consumes 30–50% of cloud budgets. The bulk is not accidental extravagance — it is the accumulated result of architectural decisions made without cost visibility at the time they were made.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. FinOps Maturity — Where You Actually Are
&lt;/h2&gt;

&lt;p&gt;Most organisations overestimate their maturity by one stage. The diagnostic: can you tell, within five minutes, which team or service generated a specific line item on last month's bill? If not, you're in Crawl regardless of how sophisticated your dashboard looks.&lt;/p&gt;

&lt;p&gt;Most organisations see 15–20% waste reduction from showback alone — just making costs visible changes behaviour.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Commitment Tiers as Architecture Decisions
&lt;/h2&gt;

&lt;p&gt;The commitment model constrains the operational assumptions your workload can make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On-Demand&lt;/strong&gt; — unpredictable burst, new workloads not yet baselined&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Savings Plans&lt;/strong&gt; — 20–66% discount, flexible across instance types&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserved Instances&lt;/strong&gt; — 40–72% discount, locked to specific instance family&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot/Preemptible&lt;/strong&gt; — up to 90% discount, two-minute eviction notice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule: baseline on on-demand for 2–4 weeks before committing. Savings Plans before Reserved Instances for flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Cost Allocation Tagging
&lt;/h2&gt;

&lt;p&gt;Only 22% of companies have allocated 75%+ of their cloud costs. The gap is almost always a tagging gap.&lt;/p&gt;

&lt;p&gt;Four mandatory tags enforced at provisioning time: &lt;code&gt;team&lt;/code&gt;, &lt;code&gt;environment&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, &lt;code&gt;cost-centre&lt;/code&gt;. Resources without them are rejected at creation — not documented for later.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Showback Before Chargeback
&lt;/h2&gt;

&lt;p&gt;Chargeback requires teams to trust the attribution model. That trust requires correct tags, understood allocation logic, and fair shared-cost treatment. None of that exists at the Crawl stage.&lt;/p&gt;

&lt;p&gt;Introduce showback first, run it for a full quarter, fix attribution disputes, then move to chargeback.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Kubernetes Cost Attribution
&lt;/h2&gt;

&lt;p&gt;When 50 services share a node pool, standard billing reports are useless. OpenCost (CNCF) and Kubecost provide per-pod and per-namespace cost breakdowns based on actual utilisation relative to node cost.&lt;/p&gt;

&lt;p&gt;ResourceQuotas are the Kubernetes-native cost governance primitive — apply one to every tenant namespace.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Pipeline Cost Gates
&lt;/h2&gt;

&lt;p&gt;The highest-leverage FinOps capability: a cost gate in CI/CD that shows projected cost impact before merge. Infracost analyses Terraform plans and returns a monthly dollar diff in the pull request.&lt;/p&gt;

&lt;p&gt;If the projected increase exceeds a threshold, the check fails and the PR cannot merge without explicit override.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Guardrails That Block, Not Just Alert
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instance type restrictions&lt;/strong&gt; — SCPs/Azure Policy restrict GPU and large families in non-production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle resource cleanup&lt;/strong&gt; — unattached volumes, orphaned IPs detected and remediated by policy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev environment cost caps&lt;/strong&gt; — CronJobs scale non-production to zero outside business hours&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. Structural Wastes to Eliminate First
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Egress cost from co-located-on-prem services now crossing AZs&lt;/li&gt;
&lt;li&gt;Overprovisioned node pools with untuned autoscaler scale-down&lt;/li&gt;
&lt;li&gt;Cross-region data transfer not modelled before architecture decisions&lt;/li&gt;
&lt;li&gt;Unused reserved capacity below 70% utilisation&lt;/li&gt;
&lt;li&gt;Storage in standard tiers that should be in lifecycle-managed cold storage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of the fourth post in the Cloud Architecture series. The full article includes Infracost GitHub Actions workflow, Azure Policy JSON for tag enforcement, Kubernetes ResourceQuota and CronJob manifests, commitment tier decision matrix, and a comprehensive cost architecture checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/cloud-cost-architecture/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=cloud-cost-architecture" rel="noopener noreferrer"&gt;Cloud Cost Architecture: Engineering FinOps Into the System, Not Onto It — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FinOps Crawl/Walk/Run maturity assessment with next actions per stage&lt;/li&gt;
&lt;li&gt;Commitment tier decision matrix with discount ranges and risk profiles&lt;/li&gt;
&lt;li&gt;Azure Policy JSON for mandatory tag enforcement at provisioning&lt;/li&gt;
&lt;li&gt;Kubernetes ResourceQuota manifest for namespace cost governance&lt;/li&gt;
&lt;li&gt;Infracost GitHub Actions workflow with threshold-based cost gate&lt;/li&gt;
&lt;li&gt;CronJob manifest for non-production scale-to-zero outside business hours&lt;/li&gt;
&lt;li&gt;Structural waste audit across egress, node pools, data transfer, reservations, and storage&lt;/li&gt;
&lt;li&gt;Complete cloud cost architecture checklist (15 items)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>architecture</category>
      <category>finops</category>
      <category>devops</category>
    </item>
    <item>
      <title>I Almost Lost an Entire Blog with git reset --hard (And Git Saved Me)</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Wed, 15 Jul 2026 11:24:26 +0000</pubDate>
      <link>https://dev.to/aloknecessary/i-almost-lost-an-entire-blog-with-git-reset-hard-and-git-saved-me-do6</link>
      <guid>https://dev.to/aloknecessary/i-almost-lost-an-entire-blog-with-git-reset-hard-and-git-saved-me-do6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;What started as a routine cleanup became a lesson in Git's resilience — and a reminder that understanding the model matters more than memorizing commands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Moment Everything Disappeared
&lt;/h2&gt;

&lt;p&gt;I had a feature branch with a freshly committed blog post. I was tidying up my local repository — something I'd done a hundred times before. Then, almost on autopilot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout blogs/microservices-by-def
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; 65515962bc35fe08514f0b1dcad58cb89773bd2d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The terminal didn't flinch. No warning. No confirmation prompt.&lt;/p&gt;

&lt;p&gt;My article was gone. Hours of writing — vanished in under a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Happened
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:   A ── B ── C ── D  ← my blog commit
After:    A ── B ── C  ← pointer moved here (D still exists, orphaned)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git didn't &lt;em&gt;delete&lt;/em&gt; my commit. It just moved the branch pointer. The commit was still there — floating, unreachable, but alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mental Model That Changes Everything
&lt;/h2&gt;

&lt;p&gt;Git doesn't store files. It stores &lt;strong&gt;snapshots&lt;/strong&gt;. A branch is just a pointer. &lt;code&gt;git reset&lt;/code&gt; relocates that pointer — it doesn't destroy history.&lt;/p&gt;

&lt;p&gt;The commit persists until garbage collection prunes unreachable objects (which doesn't happen immediately).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Recovery: &lt;code&gt;git reflog&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reflog show blogs/microservices-by-def
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;6551596 reset: moving to 65515962bc35...
0434e98 commit: added blog on Microservices by Default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recovery took one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; 0434e98
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything came back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Reset Modes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Working Tree&lt;/th&gt;
&lt;th&gt;Index&lt;/th&gt;
&lt;th&gt;HEAD&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git reset --soft&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git reset --mixed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git reset --hard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;--hard&lt;/code&gt; rewrites all three areas. That's why my files disappeared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Decision Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;I want to...&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Undo a local commit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo a pushed commit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git revert&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recover lost work&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git reflog&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save work temporarily&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restore a single file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git restore&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clean up commit history&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git rebase -i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Commit early, commit often.&lt;/strong&gt; Small commits are cheap insurance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push important milestones.&lt;/strong&gt; Remote refs survive local disasters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn &lt;code&gt;reflog&lt;/code&gt; before you need it.&lt;/strong&gt; In a panic, you won't have time to read docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never panic after a bad Git command.&lt;/strong&gt; Most mistakes are recoverable.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The full post covers merge vs rebase, interactive rebase, reword, cherry-pick, stash, &lt;code&gt;git fsck&lt;/code&gt;, and why linear history matters for CI/CD.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://aloknecessary.in/blogs/i-almost-lost-an-entire-blog-with-git-reset-hard/?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=git-reset-hard" rel="noopener noreferrer"&gt;Read the complete guide on my blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>programming</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Multi-AZ by Default: When High Availability Costs More Than the Downtime It Prevents</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Mon, 13 Jul 2026 06:54:00 +0000</pubDate>
      <link>https://dev.to/aloknecessary/multi-az-by-default-when-high-availability-costs-more-than-the-downtime-it-prevents-1inc</link>
      <guid>https://dev.to/aloknecessary/multi-az-by-default-when-high-availability-costs-more-than-the-downtime-it-prevents-1inc</guid>
      <description>&lt;p&gt;"Enable Multi-AZ for all production databases." It appears in every best-practice guide. Like "make everything private," it sounds unambiguously correct. More availability is better.&lt;/p&gt;

&lt;p&gt;Multi-AZ for RDS doubles your database instance cost. Exactly doubles. A &lt;code&gt;db.r8g.2xlarge&lt;/code&gt; at $700/month becomes $1,401/month. Ten such instances: $84,100/year in availability premium. That number needs a business case before it's treated as a default.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Multi-AZ Actually Provides (and Doesn't)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Provides:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synchronous standby in a different AZ (same region)&lt;/li&gt;
&lt;li&gt;Automatic failover in 35–60 seconds&lt;/li&gt;
&lt;li&gt;Zero data loss (RPO = 0)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Does NOT provide:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protection against regional outages (standby is same region)&lt;/li&gt;
&lt;li&gt;Read scalability (standard standby is not readable — sits idle)&lt;/li&gt;
&lt;li&gt;Protection against data corruption or accidental deletion (replicated instantly)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Multi-AZ Is Unnecessary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev/staging/QA&lt;/strong&gt; — protecting against a problem that doesn't exist. No user impact from staging downtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal tooling&lt;/strong&gt; — 50 users, business hours only. 30-minute restore is acceptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch processing&lt;/strong&gt; — re-run the job when the database recovers. Retry logic is cheaper than 2x cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateless app tiers on Kubernetes&lt;/strong&gt; — topology spread constraints provide multi-AZ resilience at zero cost.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Multi-AZ IS Worth It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Customer-facing, revenue-generating workloads ($50K/hour revenue loss justifies the premium instantly)&lt;/li&gt;
&lt;li&gt;Contractual SLA commitments (99.9%+ uptime)&lt;/li&gt;
&lt;li&gt;Regulated industries (HIPAA, PCI-DSS, SOC 2)&lt;/li&gt;
&lt;li&gt;Large databases with slow restore (5TB snapshot restore exceeds acceptable RTO)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Decision Framework
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: What is the business cost of 1 hour of downtime?
Step 2: Multi-AZ annual premium vs expected annual downtime cost
Step 3: Can snapshot restore meet your RTO?
Step 4: Environment rule — dev/staging/QA = Single-AZ, always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the Multi-AZ premium exceeds the expected annual cost of downtime, Single-AZ with a tested restore procedure is the right answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Environment Rule (No Exceptions)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Production, customer-facing:   Evaluate with framework
Production, internal tooling:  Single-AZ unless justified
Staging:                       Single-AZ, always
Development:                   Single-AZ, always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disabling Multi-AZ on non-production environments alone saves $3,118/year per database.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of the second post in the Cloud Defaults Reconsidered series. The full article includes detailed cost breakdowns, cross-AZ transfer calculations, Aurora comparison, automated restore alternatives, and a complete decision framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/multi-az-by-default/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=multi-az-by-default" rel="noopener noreferrer"&gt;Multi-AZ by Default — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact RDS pricing comparison across instance types (Single-AZ vs Multi-AZ)&lt;/li&gt;
&lt;li&gt;Cross-AZ data transfer cost calculations&lt;/li&gt;
&lt;li&gt;Non-production environment savings breakdown&lt;/li&gt;
&lt;li&gt;Common misconceptions debunked (99.99% uptime, data loss protection, backups)&lt;/li&gt;
&lt;li&gt;Kubernetes topology spread constraint manifest for free multi-AZ resilience&lt;/li&gt;
&lt;li&gt;Aurora vs RDS Multi-AZ cost comparison&lt;/li&gt;
&lt;li&gt;Break-even calculation template&lt;/li&gt;
&lt;li&gt;Practical recommendations table by workload type&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>aws</category>
      <category>architecture</category>
      <category>devops</category>
    </item>
    <item>
      <title>Modernising the Lifted Workload: The Architectural Decisions That Separate Cloud-Native from Cloud-Hosted</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Thu, 09 Jul 2026 09:21:26 +0000</pubDate>
      <link>https://dev.to/aloknecessary/modernising-the-lifted-workload-the-architectural-decisions-that-separate-cloud-native-from-2omp</link>
      <guid>https://dev.to/aloknecessary/modernising-the-lifted-workload-the-architectural-decisions-that-separate-cloud-native-from-2omp</guid>
      <description>&lt;p&gt;Kubernetes does not make your architecture better automatically. Moving a lifted workload into a Deployment manifest without addressing stateful assumptions, chatty patterns, and observability voids is lift-and-shift at the container level.&lt;/p&gt;

&lt;p&gt;This post covers the graduation path from "it's running on VMs" to genuinely cloud-native.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Workload Assessment — Four Categories, Four Paths
&lt;/h2&gt;

&lt;p&gt;Not all lifted workloads have the same modernisation path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stateless, well-behaved&lt;/strong&gt; → containerise directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateful, extractable&lt;/strong&gt; → externalise state first, then containerise&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tightly coupled monolith&lt;/strong&gt; → strangler fig pattern&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low-ROI legacy&lt;/strong&gt; → managed service substitution or decommission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key diagnostic: if we modernise this, what specifically becomes easier to operate, scale, or change? If the answer is "nothing in particular," don't containerise it.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Managed Service Substitution
&lt;/h2&gt;

&lt;p&gt;Before containerising anything: does this workload need to run as a custom-deployed service at all?&lt;/p&gt;

&lt;p&gt;A self-hosted RabbitMQ cluster in Kubernetes requires provisioning, PV management, PDB configuration, Helm upgrades, TLS rotation, and on-call coverage. SQS or Azure Service Bus handles all of that for you.&lt;/p&gt;

&lt;p&gt;The rule: managed services transfer operational complexity to the provider in exchange for reduced control. That trade is almost always worth it for infrastructure that is not a source of competitive differentiation.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Stateless Redesign — The Non-Negotiable First Step
&lt;/h2&gt;

&lt;p&gt;Kubernetes's core model depends on pods being disposable. Three standard moves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Externalise session state&lt;/strong&gt; — replace in-process stores with Redis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Externalise file storage&lt;/strong&gt; — replace local filesystem writes with object storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Externalise scheduled jobs&lt;/strong&gt; — replace in-process timers with CronJobs (&lt;code&gt;concurrencyPolicy: Forbid&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An application that holds state in process memory will behave incorrectly in Kubernetes in ways that are hard to reproduce in staging.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Strangler Fig Pattern
&lt;/h2&gt;

&lt;p&gt;The only widely proven technique for decomposing a monolith without a big-bang rewrite:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Place a routing layer in front of the monolith&lt;/li&gt;
&lt;li&gt;Extract one bounded context at a time&lt;/li&gt;
&lt;li&gt;Route that context's traffic to the new service&lt;/li&gt;
&lt;li&gt;Validate under production traffic&lt;/li&gt;
&lt;li&gt;Repeat until the monolith handles nothing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three rules: start with the least risky extraction (not the most valuable), never share a database between monolith and extracted service, validate under real traffic before decommissioning the old code path.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Kubernetes Readiness Criteria
&lt;/h2&gt;

&lt;p&gt;Before containerising:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Health probes are meaningful&lt;/strong&gt; — readiness checks actual application state, liveness checks only process health (never external dependencies in liveness)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource requests and limits measured&lt;/strong&gt; — from real profiling, not guesses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful shutdown implemented&lt;/strong&gt; — SIGTERM handled, in-flight requests complete before pod exits&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Autoscaling That Reflects Real Load
&lt;/h2&gt;

&lt;p&gt;CPU is a poor proxy for load in most lifted workloads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU-based HPA&lt;/strong&gt; — only for compute-bound workloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom metrics HPA&lt;/strong&gt; — for request-rate-driven services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KEDA&lt;/strong&gt; — for queue consumers and event processors; scales to zero when idle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;minReplicaCount: 0&lt;/code&gt; in non-production environments means queue consumers cost nothing when idle.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. The Modernisation Sequencing
&lt;/h2&gt;

&lt;p&gt;Never stop shipping. Allocate 20–30% of each sprint to modernisation. The order that works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stateless redesign&lt;/li&gt;
&lt;li&gt;Observability pipeline&lt;/li&gt;
&lt;li&gt;Managed service substitutions&lt;/li&gt;
&lt;li&gt;Routing layer&lt;/li&gt;
&lt;li&gt;First bounded context extraction&lt;/li&gt;
&lt;li&gt;Progressive extraction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Observability comes second, not last — you cannot safely extract services you cannot observe.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of the third post in the Cloud Architecture series. The full article includes workload assessment matrices, managed service substitution tables, strangler fig architecture diagrams, Kubernetes probe configuration, KEDA ScaledObject manifests, and a comprehensive modernisation readiness checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/modernising-the-lifted-workload/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=modernising-the-lifted-workload" rel="noopener noreferrer"&gt;Modernising the Lifted Workload — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Four-category workload assessment with recommended paths&lt;/li&gt;
&lt;li&gt;Managed service substitution table (message brokers, caches, search, schedulers, secrets)&lt;/li&gt;
&lt;li&gt;Stateless redesign patterns with CronJob manifest (concurrencyPolicy: Forbid)&lt;/li&gt;
&lt;li&gt;Strangler fig pattern with five-phase ASCII architecture diagram&lt;/li&gt;
&lt;li&gt;Kubernetes readiness/liveness probe configuration with anti-patterns&lt;/li&gt;
&lt;li&gt;KEDA ScaledObject for SQS-driven autoscaling with scale-to-zero&lt;/li&gt;
&lt;li&gt;Modernisation sequencing order with sprint allocation guidance&lt;/li&gt;
&lt;li&gt;Complete modernisation readiness checklist (13 items)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>devops</category>
      <category>architecture</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>GraphRAG vs. RAG: When Knowledge Graphs Earn Their Complexity</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Thu, 02 Jul 2026 04:55:57 +0000</pubDate>
      <link>https://dev.to/aloknecessary/graphrag-vs-rag-when-knowledge-graphs-earn-their-complexity-3j0j</link>
      <guid>https://dev.to/aloknecessary/graphrag-vs-rag-when-knowledge-graphs-earn-their-complexity-3j0j</guid>
      <description>&lt;p&gt;Vector search tells you which chunks are similar to your query. GraphRAG tells you how entities in your corpus relate to each other. Those are different questions — and most teams reach for the graph before confirming they're actually asking the second one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Flat Retrieval Can't Solve
&lt;/h2&gt;

&lt;p&gt;"Which suppliers does our highest-risk vendor share ownership with?" "What's the chain of approvals that led to this incident?" These queries aren't well-served by top-K similar chunks — the answer isn't &lt;em&gt;in&lt;/em&gt; any single chunk. It exists in the structure connecting multiple entities across the corpus.&lt;/p&gt;

&lt;p&gt;GraphRAG replaces or augments chunk-based retrieval with a knowledge graph — entities as nodes, relationships as edges — that the system can traverse to answer structural questions similarity search cannot.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark Reality
&lt;/h2&gt;

&lt;p&gt;GraphRAG's advantage is concentrated in multi-hop and relational query classes. On single-fact lookups, it's close to nonexistent — sometimes negative once you account for extraction cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before building anything:&lt;/strong&gt; classify 200+ real production queries as "relational" vs "single-fact." If relational queries are under 15% of traffic, GraphRAG's benchmark gains won't materialize at your actual query mix — but extraction cost still applies to 100% of documents.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cost Problem (and How It Got Solved)
&lt;/h2&gt;

&lt;p&gt;Microsoft's 2024 implementation: $33K indexing cost for large datasets. The fix in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Selective extraction&lt;/strong&gt; — only documents likely to contain relational content go through the expensive LLM pass&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheap-model-first&lt;/strong&gt; — lightweight model for bulk extraction, expensive model for ambiguous cases only&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid classical NLP + LLM&lt;/strong&gt; — named-entity recognition handles entity identification, LLM reserved for relationship typing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relation-free construction&lt;/strong&gt; — build entity co-occurrence structure first, type relationships only when queries need them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combined: 10-90% cost reduction depending on corpus characteristics.&lt;/p&gt;




&lt;h2&gt;
  
  
  GraphRAG vs. Agentic Multi-Hop Retrieval
&lt;/h2&gt;

&lt;p&gt;Both solve multi-hop questions. Different trade-offs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic retrieval&lt;/strong&gt; — pays cost at query time, only for queries that need it. No corpus-wide preprocessing. But reasoning paths are probabilistic — two runs can take different paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphRAG&lt;/strong&gt; — pays cost at ingestion time, once. Gets deterministic traversal: same query, same path, same answer, every time. Critical for compliance, audit, and risk contexts where "the system gave a different answer last time" is itself a problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision rule:&lt;/strong&gt; occasional, varied relational queries → agentic retrieval. Frequent, recurring relational patterns needing consistent answers → graph.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hybrid Architecture
&lt;/h2&gt;

&lt;p&gt;In production, GraphRAG is a third retrieval tool alongside vector and BM25, not a replacement. Route per query:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Graph-only&lt;/strong&gt;: purely relational ("who is connected to X")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector-only&lt;/strong&gt;: content-similarity ("explain concept Y")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid&lt;/strong&gt;: use graph to narrow the search space to a relevant neighborhood, then vector-search within it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Key Insight
&lt;/h2&gt;

&lt;p&gt;GraphRAG is not "RAG, but better." It's a different retrieval primitive — applicable when queries are about relationships rather than content. The graph is a cost center until your query distribution proves otherwise.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Audit the query distribution first. If relational share is small, agentic multi-hop gets most of the benefit at a fraction of the commitment.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of my deep dive into GraphRAG architecture. The full article covers the complete evaluation and implementation guide:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/graph-rag-vs-rag/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=graphrag-vs-rag" rel="noopener noreferrer"&gt;GraphRAG vs. RAG: When Knowledge Graphs Earn Their Complexity — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What a knowledge graph actually adds (and what it doesn't)&lt;/li&gt;
&lt;li&gt;Benchmark evidence breakdown — when GraphRAG helps and when it hurts&lt;/li&gt;
&lt;li&gt;Graph construction cost anatomy (extraction + community summarization)&lt;/li&gt;
&lt;li&gt;Four techniques that cut the 2024 cost problem (selective extraction, cheap-model-first, hybrid NLP, relation-free construction)&lt;/li&gt;
&lt;li&gt;Three graph traversal patterns (local, global, multi-hop path)&lt;/li&gt;
&lt;li&gt;GraphRAG vs agentic multi-hop retrieval — direct comparison with decision rule&lt;/li&gt;
&lt;li&gt;Hybrid architecture with routing (graph + vector together)&lt;/li&gt;
&lt;li&gt;Production failure modes specific to graphs (entity resolution drift, stale edges, community cascade)&lt;/li&gt;
&lt;li&gt;Decision checklist for committing to graph infrastructure&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>database</category>
    </item>
    <item>
      <title>Context Engineering: The Discipline That Determines What Your LLM Actually Sees</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Mon, 29 Jun 2026 08:11:02 +0000</pubDate>
      <link>https://dev.to/aloknecessary/context-engineering-the-discipline-that-determines-what-your-llm-actually-sees-569g</link>
      <guid>https://dev.to/aloknecessary/context-engineering-the-discipline-that-determines-what-your-llm-actually-sees-569g</guid>
      <description>&lt;p&gt;Prompt engineering asks: how do I phrase this instruction? Context engineering asks: what information does the model need, in what form, in what order, and how much of it — to produce a correct answer?&lt;/p&gt;

&lt;p&gt;For a long time, the implicit mental model was: give the LLM more context and it performs better. This is wrong. A 20,000-token window stuffed with weakly relevant content produces worse answers than a 4,000-token window with precisely curated information. Larger windows do not eliminate context quality problems — they amplify them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Context Window Is a Budget
&lt;/h2&gt;

&lt;p&gt;Treat it as a budget with competing line items, not a container you fill. Start with the total window, subtract fixed allocations (system prompt, output reserve, safety margin), and what remains is your dynamic budget split across retrieved chunks, conversation history, and memory.&lt;/p&gt;

&lt;p&gt;The first question should always be: "can we get better at selecting less, rather than including more?"&lt;/p&gt;




&lt;h2&gt;
  
  
  Four Memory Types, Four Purposes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Episodic&lt;/strong&gt; — conversation history. Highest priority for continuity. Grows unbounded — needs compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic&lt;/strong&gt; — durable facts about the user (role, team, preferences). Compact, injected in system prompt before retrieved content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedural&lt;/strong&gt; — reusable workflows and SOPs. Retrieved selectively when the query type matches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working&lt;/strong&gt; — intermediate results within a single request (agentic loop output). Ephemeral, request-scoped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each type has different durability, update frequency, and token cost. Conflating them into a single undifferentiated store is the most common memory architecture mistake.&lt;/p&gt;




&lt;h2&gt;
  
  
  Structured Injection Patterns
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;XML tags&lt;/strong&gt; for section boundaries (&lt;code&gt;&amp;lt;documents&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;user_context&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;instructions&amp;gt;&lt;/code&gt;) — gives the model clear anchors for where information types begin and end&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexed documents&lt;/strong&gt; — label chunks with indices so citations can be traced&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering matters&lt;/strong&gt; — most relevant content first (primacy effect), user query last (recency effect)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grounding instruction is not optional&lt;/strong&gt; — explicit instruction to use only provided context and signal when insufficient&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lost-in-the-Middle
&lt;/h2&gt;

&lt;p&gt;Models attend more strongly to content near the beginning and end of the context window. Information buried in the middle receives less attention. Mitigations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Relevance-ordered injection (highest score first)&lt;/li&gt;
&lt;li&gt;Sandwich pattern (critical content at both start and end)&lt;/li&gt;
&lt;li&gt;Active relevance filtering (exclude low-scoring chunks even if they fit)&lt;/li&gt;
&lt;li&gt;Smaller, tighter windows (fewer high-quality chunks &amp;gt; more mediocre chunks)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conversation Compression
&lt;/h2&gt;

&lt;p&gt;A 100-turn conversation consumes your entire retrieved context budget. Naive truncation loses critical early constraints. Solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sliding window with pinned turns&lt;/strong&gt; — critical turns (user constraints, decisions) never truncated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive summarization&lt;/strong&gt; — compress old segments into 3-5 sentence summaries using Haiku (cheap, mechanical task)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Context Assembly Is Testable
&lt;/h2&gt;

&lt;p&gt;Unit test your assembly layer: budget compliance, ordering preserved, critical turns survive truncation, no mid-chunk truncation. Every assembly failure produces a predictable RAGAS metric signature — context precision drops point to noisy inclusion, faithfulness drops point to contradictions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of my deep dive into context engineering. The full article covers the complete discipline with production implementations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/discipline-that-determines-what-your-llm-actually-sees/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=context-engineering" rel="noopener noreferrer"&gt;Context Engineering: The Discipline That Determines What Your LLM Actually Sees — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context window budget accounting with Python dataclasses&lt;/li&gt;
&lt;li&gt;Four memory types with implementation patterns (episodic, semantic, procedural, working)&lt;/li&gt;
&lt;li&gt;Working memory bridge from agentic retrieval loops&lt;/li&gt;
&lt;li&gt;XML-structured injection with document indexing&lt;/li&gt;
&lt;li&gt;Primacy/recency ordering strategy&lt;/li&gt;
&lt;li&gt;Progressive summarization with critical turn pinning&lt;/li&gt;
&lt;li&gt;Lost-in-the-middle mitigation (4 strategies with code)&lt;/li&gt;
&lt;li&gt;Contradiction detection and resolution&lt;/li&gt;
&lt;li&gt;Noise taxonomy (stale, tangential, redundant, over-retrieved)&lt;/li&gt;
&lt;li&gt;Unit testing context assembly&lt;/li&gt;
&lt;li&gt;AssemblyMetadata integration with RAGAS eval pipeline&lt;/li&gt;
&lt;li&gt;RAGAS metric → assembly failure mapping table&lt;/li&gt;
&lt;li&gt;Production checklist (19 items)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>Agentic RAG: Designing Self-Correcting Retrieval Loops for Production</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Mon, 22 Jun 2026 05:59:20 +0000</pubDate>
      <link>https://dev.to/aloknecessary/agentic-rag-designing-self-correcting-retrieval-loops-for-production-2lbg</link>
      <guid>https://dev.to/aloknecessary/agentic-rag-designing-self-correcting-retrieval-loops-for-production-2lbg</guid>
      <description>&lt;p&gt;Standard RAG retrieves once and hopes for the best. Agentic RAG retrieves, reflects, decides it was wrong, and tries again — without being told to.&lt;/p&gt;

&lt;p&gt;Single-pass RAG has a fundamental flaw: it commits to its first retrieval attempt and generates forward regardless. It has no mechanism to check whether the retrieved chunks actually contain the answer. This works for simple factual queries. It breaks on multi-hop questions, ambiguous intent, and analytical queries requiring sequenced lookups.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;An agentic RAG system treats retrieval as a tool available to a reasoning loop. The LLM decides what to retrieve, evaluates what came back, and determines when to stop.&lt;/p&gt;

&lt;p&gt;The key component: a &lt;strong&gt;reflection agent&lt;/strong&gt; sits between retrieval and generation. It evaluates the quality and sufficiency of accumulated context and either terminates the loop or sends it back with a refined query.&lt;/p&gt;

&lt;p&gt;Three patterns in increasing complexity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Iterative Query Refinement&lt;/strong&gt; — single tool, query rewritten per pass&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Tool Orchestration&lt;/strong&gt; — agent selects between keyword, semantic, hybrid, and filtered search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical Decomposition&lt;/strong&gt; — planner splits multi-hop queries into dependent sub-queries&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Routing: The Most Important Decision
&lt;/h2&gt;

&lt;p&gt;Sending every query through the agentic path is the most common mistake. Agentic retrieval adds 2-8s latency and 4-12x cost. Simple factual queries (60-75% of typical traffic) get no quality improvement from it.&lt;/p&gt;

&lt;p&gt;Use a hybrid router: deterministic rules first (regex patterns, length heuristics, keyword signals), LLM classification only for ambiguous cases. Use Haiku for routing — it's a classification task, not a reasoning task.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reflection Agent: Deciding When to Stop
&lt;/h2&gt;

&lt;p&gt;The reflection agent's judgment quality determines the entire system's utility. Calibrate it against real queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Iteration 1:&lt;/strong&gt; 65-75% of queries should terminate (simple queries succeeding on first pass)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration 2:&lt;/strong&gt; 15-20% (needed one refinement)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration 3:&lt;/strong&gt; 5-10% (multi-hop or genuinely ambiguous)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iteration 4+:&lt;/strong&gt; &amp;lt;5% (forced termination — investigate these)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If significant traffic hits max iterations, either routing is broken or your corpus has coverage gaps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure Isolation and Loop Bounding
&lt;/h2&gt;

&lt;p&gt;Without explicit bounding, misbehaving loops drive latency and cost to unacceptable levels. Non-negotiable limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;max_iterations: 4&lt;/strong&gt; — never exceed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;timeout: 12s&lt;/strong&gt; — wall-clock for entire loop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;min_new_chunks_per_iteration: 1&lt;/strong&gt; — if retrieval returns nothing new, break immediately&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;context token budget&lt;/strong&gt; — stop accepting chunks beyond the budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On timeout or max iterations: generate with accumulated context + caveat, never return a 500 error.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost Reality
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Single-pass RAG:     ~$0.003/request
Agentic (2 iter):    ~$0.006/request  (2x)
Agentic (4 iter):    ~$0.010/request  (3-4x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If 25% of traffic goes agentic at 2.5x cost → 37% total increase (acceptable). If 75% goes agentic → costs triple (likely unacceptable). The router controls your bill.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Key Insight
&lt;/h2&gt;

&lt;p&gt;An agentic system with no observability is not an improvement over single-pass — it's a more expensive pipeline that's harder to debug. The loop delivers quality improvement only when it is instrumented, bounded, and its behavior is understood at the query level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agency without accountability is just unpredictability.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of my deep dive into agentic RAG architecture. The full article covers the complete system with production implementations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/designing-self-correcting-retrieval-loops-for-production/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=agentic-rag-self-correcting-retrieval" rel="noopener noreferrer"&gt;Designing Self-Correcting Retrieval Loops for Production — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full agentic RAG architecture diagram (router → planner → loop → generation)&lt;/li&gt;
&lt;li&gt;Query planner implementation with multi-hop decomposition (Python/Anthropic)&lt;/li&gt;
&lt;li&gt;Iterative retrieval loop with async timeout and dedup&lt;/li&gt;
&lt;li&gt;Reflection agent prompt and calibration patterns&lt;/li&gt;
&lt;li&gt;Multi-tool orchestration with Claude tool-use API&lt;/li&gt;
&lt;li&gt;Hybrid router (rules-first + LLM fallback)&lt;/li&gt;
&lt;li&gt;Loop bounding with five hard limits&lt;/li&gt;
&lt;li&gt;Graceful degradation with context caveats&lt;/li&gt;
&lt;li&gt;Per-request cost model (single-pass vs 2-iter vs 4-iter)&lt;/li&gt;
&lt;li&gt;Latency budget breakdown and streaming response pattern&lt;/li&gt;
&lt;li&gt;Structured loop telemetry with structlog&lt;/li&gt;
&lt;li&gt;Alerting metrics for agentic systems&lt;/li&gt;
&lt;li&gt;Production deployment checklist&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>LLM Evaluation in Production: Building the Eval Pipeline That Runs on Every Deploy</title>
      <dc:creator>Alok Ranjan Daftuar</dc:creator>
      <pubDate>Wed, 17 Jun 2026 13:22:36 +0000</pubDate>
      <link>https://dev.to/aloknecessary/llm-evaluation-in-production-building-the-eval-pipeline-that-runs-on-every-deploy-5eki</link>
      <guid>https://dev.to/aloknecessary/llm-evaluation-in-production-building-the-eval-pipeline-that-runs-on-every-deploy-5eki</guid>
      <description>&lt;p&gt;Everyone ships the RAG system. Almost nobody ships the eval system that tells them when the RAG system starts lying.&lt;/p&gt;

&lt;p&gt;You updated the embedding model. Tweaked the system prompt. Swapped the re-ranker. Metrics look fine. Three weeks later, support tickets arrive — the system is drawing inferences the source documents never made. No alarm fired. No test failed. The system drifted silently.&lt;/p&gt;

&lt;p&gt;This is not a model quality problem. It is an evaluation infrastructure problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Metrics That Matter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Faithfulness&lt;/strong&gt; — of the claims in the response, what fraction are directly supported by the retrieved context? Your primary hallucination guard. Does not require ground truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer Relevance&lt;/strong&gt; — how directly does the response address the user's question? Catches the "technically correct but useless" failure mode. Does not require ground truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context Precision&lt;/strong&gt; — of the retrieved chunks, what fraction were actually relevant? Requires ground truth. Belongs in offline CI eval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer Correctness&lt;/strong&gt; — how factually accurate vs the reference answer? Most expensive, requires curated ground truth. Pre-deploy regression suite only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational rule:&lt;/strong&gt; Faithfulness and Answer Relevance run on every deploy and on sampled production traffic. Context Precision and Answer Correctness run in CI against the golden dataset.&lt;/p&gt;




&lt;h2&gt;
  
  
  LLM-as-Judge: The Pattern and Pitfalls
&lt;/h2&gt;

&lt;p&gt;RAGAS uses an LLM to evaluate LLM output — the only practical way to evaluate semantic quality at scale.&lt;/p&gt;

&lt;p&gt;Pitfalls to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Positional bias&lt;/strong&gt; — randomize order in pairwise comparisons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verbosity bias&lt;/strong&gt; — judge rates longer answers higher even when less accurate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-preference&lt;/strong&gt; — use a different model family as judge than the one generating answers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calibration drift&lt;/strong&gt; — pin judge model to a specific version; treat upgrades as baseline resets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Calibrate against human labels using Cohen's Kappa on 50-100 examples. Below 0.4 means your judge prompt needs revision.&lt;/p&gt;




&lt;h2&gt;
  
  
  CI/CD Integration
&lt;/h2&gt;

&lt;p&gt;The eval pipeline triggers on every PR touching RAG code, prompts, or model configuration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run RAG pipeline against golden dataset (100+ curated questions)&lt;/li&gt;
&lt;li&gt;Score with RAGAS (faithfulness, relevance, precision, correctness)&lt;/li&gt;
&lt;li&gt;Compare against baseline — block deploy if regression exceeds threshold&lt;/li&gt;
&lt;li&gt;Post results as PR comment with per-metric scores and pass/fail status&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cost: ~$0.50-$2.00 per full eval run at Claude Sonnet pricing. On PRs, run only faithfulness + relevance (cheapest). Full suite runs nightly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production Sampling
&lt;/h2&gt;

&lt;p&gt;CI catches regressions from code changes. Production sampling catches drift from corpus staleness, query distribution shift, and model behavior changes.&lt;/p&gt;

&lt;p&gt;Sample 5% of live traffic for async evaluation. Never evaluate synchronously — judge calls add 2-5s per request. Track 7-day rolling faithfulness and answer relevance. Alert when they drop &amp;gt;0.05 from monthly baseline.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Key Insight
&lt;/h2&gt;

&lt;p&gt;LLM systems do not have stable, deterministic behavior. They drift through corpus changes, model updates, prompt evolution, and query distribution shift. Evaluation is not a checkpoint — it is continuous infrastructure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build the eval system before you need it. By the time you need it, it is already too late — you will be debugging a production quality regression with no historical baseline and no automated detection.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Read the Full Article
&lt;/h2&gt;

&lt;p&gt;This is a summary of my deep dive into LLM evaluation infrastructure. The full article covers the complete eval stack with implementation examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://aloknecessary.in/blogs/llm-evaluation-in-production/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=blog_syndication&amp;amp;utm_content=llm-evaluation-in-production" rel="noopener noreferrer"&gt;LLM Evaluation in Production — Full Article&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full article includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evaluation stack architecture (retrieval layer vs generation layer)&lt;/li&gt;
&lt;li&gt;Four metrics with RAGAS Python implementations&lt;/li&gt;
&lt;li&gt;LLM-as-Judge faithfulness prompt with claim-level scoring&lt;/li&gt;
&lt;li&gt;Judge calibration against human labels (Cohen's Kappa)&lt;/li&gt;
&lt;li&gt;RAGAS configuration with Claude as judge model&lt;/li&gt;
&lt;li&gt;Regression threshold framework (absolute + delta from baseline)&lt;/li&gt;
&lt;li&gt;Golden dataset generation, versioning, and holdout partitions&lt;/li&gt;
&lt;li&gt;Full GitHub Actions eval pipeline (YAML + runner scripts)&lt;/li&gt;
&lt;li&gt;Production sampling with async eval queue worker&lt;/li&gt;
&lt;li&gt;Eval observability dashboard schema (PostgreSQL)&lt;/li&gt;
&lt;li&gt;Eight failure modes in eval systems and mitigations&lt;/li&gt;
&lt;li&gt;Production deployment checklist&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>devops</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
