<?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: Maksym Kuzmitskyi (MaximusFT)</title>
    <description>The latest articles on DEV Community by Maksym Kuzmitskyi (MaximusFT) (@maximusft).</description>
    <link>https://dev.to/maximusft</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%2F1819104%2Fd158bf22-3ff5-498a-bab8-91ce4b684bc1.jpg</url>
      <title>DEV Community: Maksym Kuzmitskyi (MaximusFT)</title>
      <link>https://dev.to/maximusft</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maximusft"/>
    <language>en</language>
    <item>
      <title>Freelance Architect or Agency: Who Keeps the Decisions?</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Sun, 18 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/freelance-architect-or-agency-who-keeps-the-decisions-454m</link>
      <guid>https://dev.to/maximusft/freelance-architect-or-agency-who-keeps-the-decisions-454m</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%2F9wefu3zufkrbd89usqua.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9wefu3zufkrbd89usqua.png" alt="Freelance Architect or Agency: Who Keeps the Decisions?" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A team asks for an architect, but the work waiting for them is a backlog of implementation tickets.&lt;/p&gt;

&lt;p&gt;Another asks an agency to build a feature, while every consequential decision still needs approval from an internal team that has no time to review it.&lt;/p&gt;

&lt;p&gt;Neither arrangement is necessarily wrong. They are simply describing a different purchase from the one in the proposal.&lt;/p&gt;

&lt;p&gt;When choosing between an independent engineer and an agency, I would spend less time comparing job titles and more time describing who owns the decisions while the work is happening. That tends to matter after the first few meetings, when everyone has access and the easy questions have been answered.&lt;/p&gt;

&lt;p&gt;This is a way to evaluate an engagement, not a claim about particular suppliers, prices, or a universal ranking of one model over the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  First separate diagnosis from capacity
&lt;/h2&gt;

&lt;p&gt;Sometimes the team knows what it needs to build and lacks enough delivery capacity. Sometimes it has plenty of developers but cannot explain why every change crosses five modules. Sometimes a deadline exposes both problems at once.&lt;/p&gt;

&lt;p&gt;An architecture-focused independent engagement can make sense when the central work is concentrated judgement: inspect a system, identify boundaries, work with the internal team, and make a few consequential changes.&lt;/p&gt;

&lt;p&gt;An agency can make sense when the work needs a coordinated mix of implementation, testing, design, delivery management, and continuity across several people.&lt;/p&gt;

&lt;p&gt;Those are tendencies, not guarantees. An independent engineer may deliver a complete feature; an agency may provide one specialist. The actual assigned people and operating agreement matter more than the supplier category.&lt;/p&gt;

&lt;p&gt;I would write the first outcome in plain terms. "Reduce the number of modules needed to change policy validation" is more testable than "improve architecture." "Own delivery of this workflow through acceptance and handover" is clearer than "provide a frontend team."&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsibility needs corresponding authority
&lt;/h2&gt;

&lt;p&gt;If an external architect is responsible for quality but cannot change boundaries, influence sequencing, or obtain review decisions, the responsibility is mostly ceremonial.&lt;/p&gt;

&lt;p&gt;The opposite arrangement is also uncomfortable: an external team makes choices that the internal owners must maintain, without involving them until handover.&lt;/p&gt;

&lt;p&gt;For decisions with lasting consequences, agree who proposes, who approves, and who maintains. This does not need an elaborate governance document. A small record can be enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Decision: separate payment validation from page orchestration
Proposed by: external engineer
Approved by: internal payments owner
Maintained by: payments team
Evidence: two representative flows and regression tests
Fallback: keep the old adapter during migration

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example is hypothetical. Its useful property is that someone still owns the result after the external person's last invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review availability limits delivery
&lt;/h2&gt;

&lt;p&gt;Adding implementation capacity does not increase the internal team's review or decision capacity automatically.&lt;/p&gt;

&lt;p&gt;If an agency submits ten pull requests a week and the internal team can carefully review three, work accumulates at the boundary. More developers may increase that queue rather than shorten the release.&lt;/p&gt;

&lt;p&gt;An independent engineer working on a difficult architectural change can encounter the same problem. One large refactor waiting for a busy owner is not inherently easier to absorb than several ordinary features.&lt;/p&gt;

&lt;p&gt;I would include reviewer availability in the plan: expected turnaround, who can make product decisions, when integration questions get resolved, and how work is split into changes the team can evaluate.&lt;/p&gt;

&lt;p&gt;This is particularly important when acceptance depends on integrations the supplier cannot access or change. A delivery date that assumes immediate internal answers is a date with an unstated dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefer demonstrated uncertainty over polished certainty
&lt;/h2&gt;

&lt;p&gt;Before a substantial commitment, a small paid diagnostic or bounded delivery slice can reveal the working relationship.&lt;/p&gt;

&lt;p&gt;Choose something representative rather than conveniently isolated: a flow with an awkward API contract, an existing shared component, a realistic test requirement, and an internal reviewer.&lt;/p&gt;

&lt;p&gt;The useful output includes what was discovered, what changed, what remains uncertain, and which assumptions affect the next estimate. An apparently slower answer that identifies a dependency may be worth more than a confident schedule built without examining it.&lt;/p&gt;

&lt;p&gt;I would also distinguish an estimate for implementation from the time waiting on decisions, environments, and approvals. They belong in the same delivery discussion, but they are not the same kind of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuity is a mechanism, not a headcount
&lt;/h2&gt;

&lt;p&gt;An independent engineer has a clear availability risk: one person may be absent or the engagement may end.&lt;/p&gt;

&lt;p&gt;An agency may offer replacement capacity. That does not guarantee the replacement already understands the system. A named specialist can leave; an account can be reassigned; context still has to transfer.&lt;/p&gt;

&lt;p&gt;Ask how continuity actually works. Which people have read the critical code? Where are decisions stored? Can another engineer deploy, reproduce an issue, and explain the outstanding risks without a private conversation with the original author?&lt;/p&gt;

&lt;p&gt;For both models, I would favor shared context in the client's systems, small decisions recorded near the code, and at least one internal engineer involved in consequential changes.&lt;/p&gt;

&lt;p&gt;Continuity becomes less fragile when it is exercised during delivery rather than promised in a final document.&lt;/p&gt;

&lt;h2&gt;
  
  
  The work should remain inside the client's control
&lt;/h2&gt;

&lt;p&gt;Source repositories, deployment accounts, domains, package ownership, and design assets need deliberate ownership. An engagement can finish with working software and still leave the client dependent on credentials or infrastructure controlled by the supplier.&lt;/p&gt;

&lt;p&gt;Use client-controlled repositories and appropriately scoped access where possible. Name any exception and the transfer procedure before it becomes necessary.&lt;/p&gt;

&lt;p&gt;The same applies to automation. If a supplier uses AI-assisted tooling, clarify permitted data handling, review expectations, generated-code responsibility, and what configuration belongs to the client. Faster implementation does not change who must verify the result or who may access private source and customer information.&lt;/p&gt;

&lt;p&gt;I would not equate a supplier's preferred toolchain with a requirement for the client to adopt it permanently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid a handover that only describes files
&lt;/h2&gt;

&lt;p&gt;A directory tour helps. It does not answer why a boundary exists, which alternatives were rejected, or what would break if the API changes.&lt;/p&gt;

&lt;p&gt;A useful handover includes the important decisions, reproducible checks, release and rollback steps, known limitations, and the first likely maintenance changes. Keep it proportionate; six understandable notes are better than a large template nobody can navigate.&lt;/p&gt;

&lt;p&gt;Have an internal engineer perform one change and one deployment before the engagement ends. The external person can assist, but should not quietly do every step that the exercise is intended to transfer.&lt;/p&gt;

&lt;p&gt;That is a more convincing ownership test than asking whether everyone has read the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture needs an implementation consequence
&lt;/h2&gt;

&lt;p&gt;If the engagement is mostly architecture, the deliverables should still meet the code at some point.&lt;/p&gt;

&lt;p&gt;A dependency diagram can identify a problem. A bounded migration, representative slice, or working contract test shows whether the proposed boundary is usable. Without that contact, the design may be elegant while the team's practical cost remains unknown.&lt;/p&gt;

&lt;p&gt;Conversely, measuring only shipped tickets can discourage the diagnostic work needed to prevent the next expensive change. Agree which technical outcomes matter: fewer coupled changes, faster verification, clearer ownership, or an integration that no longer needs several teams to coordinate every edit.&lt;/p&gt;

&lt;p&gt;I would avoid treating diagrams and implementation as competing definitions of productive work. They should inform each other, with evidence appropriate to the risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the arrangement that can leave well
&lt;/h2&gt;

&lt;p&gt;For a focused diagnosis with a capable internal team, I would often consider an independent senior engineer or architect. For a delivery stream needing several disciplines and coordinated capacity, I would consider an agency with named people and explicit ownership.&lt;/p&gt;

&lt;p&gt;If the organization has nobody available to own decisions, review changes, or maintain the result, neither category solves that absence by itself. The operating model needs attention before more external capacity arrives.&lt;/p&gt;

&lt;p&gt;The end of the engagement is a useful design constraint from the beginning. What should the internal team be able to do without asking the supplier? Which promises must remain true when a person changes?&lt;/p&gt;

&lt;p&gt;I would rather make those questions slightly awkward during selection than leave them until the final week. By then the software may be complete, and the ownership may still be under construction.&lt;/p&gt;

&lt;p&gt;If you're deciding between these arrangements, tell me which decision or delivery responsibility is currently unowned. That detail makes the comparison much more useful than the labels on the proposals.&lt;/p&gt;

</description>
      <category>engineeringleadershi</category>
      <category>architecture</category>
      <category>delivery</category>
      <category>workingwithteams</category>
    </item>
    <item>
      <title>What a Skill Changed, and What It Didn't</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Sat, 17 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/what-a-skill-changed-and-what-it-didnt-4ehe</link>
      <guid>https://dev.to/maximusft/what-a-skill-changed-and-what-it-didnt-4ehe</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%2F9ectkwzand6jta6d4ihc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ectkwzand6jta6d4ihc.png" alt="What a Skill Changed, and What It Didn't" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A task went well with a reusable skill enabled.&lt;/p&gt;

&lt;p&gt;It also had clear requirements, repository instructions, connected tools, a useful test, and an engineer who corrected an early assumption.&lt;/p&gt;

&lt;p&gt;Which part made the result better?&lt;/p&gt;

&lt;p&gt;I would not answer that from the final diff alone. The diff can establish what changed. It cannot, by itself, tell us which part of the workflow caused the change to be correct.&lt;/p&gt;

&lt;p&gt;I participate in evaluating reusable agent skills and refining how they are applied to ordinary engineering work. The interesting question is not whether the process produced a polished artifact. It is what observable contribution the skill made, what it cost, and what remains unknown.&lt;/p&gt;

&lt;p&gt;This article describes an evaluation approach. It does not report internal programme results, measurements, or a controlled comparison that has established a productivity gain.&lt;/p&gt;

&lt;h2&gt;
  
  
  A skill is one input among several
&lt;/h2&gt;

&lt;p&gt;A reusable skill packages instructions or a workflow. It may help discover context, plan a change, validate it, or handle review. It is not a separately trained model or an autonomous employee.&lt;/p&gt;

&lt;p&gt;Its contribution depends on what was already present.&lt;/p&gt;

&lt;p&gt;If repository rules already require a focused check immediately after an edit, a skill that repeats that instruction may add consistency, but it is not evidence that the check originated with the skill. If a connected tool supplies current requirements, the tool can explain why the agent avoided a stale assumption.&lt;/p&gt;

&lt;p&gt;The engineer's domain knowledge matters too. A person may notice that two services disagree, narrow the investigation, or reject an obsolete proposal. Leaving that correction out makes the skill look more independent than it was.&lt;/p&gt;

&lt;p&gt;I want the record to include those existing controls. Otherwise we are comparing a named framework with an imaginary workflow that has no useful practices of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observe behavior before assigning credit
&lt;/h2&gt;

&lt;p&gt;The earlier &lt;a href="https://ma-x.im/blog/agent-playbook-evaluation-is-the-missing-loop" rel="noopener noreferrer"&gt;evaluation article&lt;/a&gt; discusses what to measure. Here the narrower question is which explanation the observations support.&lt;/p&gt;

&lt;p&gt;Use a deliberately illustrative record, not a real reporting form or an internal task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Task:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;without&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;changing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;its&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;callers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Observed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;behavior:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;checked&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;contract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;editing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Existing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;control:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;repository&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;instructions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;also&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;check&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Correction:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;engineer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;identified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stale&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;source&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Verified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;outcome:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;retained&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;passes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;relevant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gates&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Skill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;contribution:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;have&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;reinforced&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;discovery;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;attribution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unresolved&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Residual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;risk:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;deployment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;compatibility&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;needs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;separate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;decision&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The conclusion is modest because the evidence is modest. That is not a failed evaluation. It is an evaluation that did not replace uncertainty with enthusiasm.&lt;/p&gt;

&lt;p&gt;If the skill visibly introduced a previously missing check, say so. If the task does not distinguish its effect from existing instructions, say that instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful outcome is not always delivered code
&lt;/h2&gt;

&lt;p&gt;A cross-repository investigation can end with an obsolete PR being closed. An architecture task can produce a proposal with explicit assumptions for discussion. A session-handoff change can produce a clearer continuation scheme.&lt;/p&gt;

&lt;p&gt;Those outcomes have value. They are not interchangeable with a merged feature, an approved architecture, or guaranteed reproducibility.&lt;/p&gt;

&lt;p&gt;Describe the actual artifact and its decision state. A reviewable proposal is ready to evaluate; it is not production rollout. A documented handoff reduces reliance on conversation history; it does not establish identical behavior across models and people.&lt;/p&gt;

&lt;p&gt;In the supplied generalized experiences behind this series, recovery and refinement are part of the work. I would not remove the initial incomplete diagnosis simply because the final action was sensible.&lt;/p&gt;

&lt;p&gt;The sequence explains what the process learned. A cleaned-up success story explains much less.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate work from overhead without pretending overhead is worthless
&lt;/h2&gt;

&lt;p&gt;Implementation, framework setup, planning, repeated approvals, and reporting take different kinds of effort.&lt;/p&gt;

&lt;p&gt;A specification can prevent an expensive mistake. It can also repeat a small task's already clear requirements. Reporting can support honest evaluation. It can also consume time that should be counted rather than hidden.&lt;/p&gt;

&lt;p&gt;Keep normal engineering effort, framework overhead, and reporting effort distinguishable. Do not turn them into a single impressive number before understanding what each category contains.&lt;/p&gt;

&lt;p&gt;The classification will sometimes require judgement. A discussion that clarifies an ambiguous requirement is engineering work even if a framework prompted it. A template completed only to satisfy the framework is a different contribution.&lt;/p&gt;

&lt;p&gt;I would make that distinction visible rather than use it to prejudge whether the framework is good or bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tiny tasks do not need a retrospective specification
&lt;/h2&gt;

&lt;p&gt;For a small, clear change, the ticket and nearby contract may already be an adequate written requirement. A long specification can create another artifact to review without resolving a real uncertainty.&lt;/p&gt;

&lt;p&gt;For ambiguous, risky, or multi-session work, a plan and checkpoints before implementation can be useful. They capture assumptions while there is still time for them to guide the work.&lt;/p&gt;

&lt;p&gt;Do not write a specification afterwards and present it as evidence that the task followed specification-driven development. A retrospective note can explain the result, but it did not shape decisions that happened before it existed.&lt;/p&gt;

&lt;p&gt;This is a simple chronology rule. It prevents polished documentation from making the process look more formal than it actually was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not using a skill can be the proportionate choice
&lt;/h2&gt;

&lt;p&gt;An evaluation can tempt people to apply every available skill to every task so the record has plenty to discuss.&lt;/p&gt;

&lt;p&gt;That changes the thing being evaluated. We are no longer observing useful selection; we are imposing ceremony for evidence collection.&lt;/p&gt;

&lt;p&gt;Use a skill when it helps the task's current stage and risk. Record when a tiny or non-coding task offers limited evidence. Do not manufacture a repository-wide plan or another planning file after the fact to fill a reporting category.&lt;/p&gt;

&lt;p&gt;A good workflow should be able to say "not needed here" without that becoming an admission that the whole framework failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeated success still has confounders
&lt;/h2&gt;

&lt;p&gt;Several tasks going well can suggest a useful pattern. It does not automatically establish a causal productivity improvement.&lt;/p&gt;

&lt;p&gt;Tasks differ in difficulty, familiarity, requirements, code quality, tools, models, and human involvement. An experienced engineer may become better at the domain during the same period the skills are introduced.&lt;/p&gt;

&lt;p&gt;Without an appropriate baseline and comparison, avoid percentages, cost savings, or defect-rate reductions. Task counts and green checks are observations, not impact metrics by themselves.&lt;/p&gt;

&lt;p&gt;Qualitative findings remain worthwhile: a missing boundary became explicit, a handoff had a clearer source of current decisions, or the process detected an unrelated generated change before review.&lt;/p&gt;

&lt;p&gt;Name them as observations. They do not need a fabricated multiplier to be interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the evaluation record separate from public storytelling
&lt;/h2&gt;

&lt;p&gt;An internal assessment may need task-level evidence, correction history, and reporting detail. A public article does not need to reproduce those artifacts.&lt;/p&gt;

&lt;p&gt;Use generalized, explicitly labelled composite examples. Remove internal identities, programme details, source snippets, links, counts and model policy. Do not attach an employer's name to an anonymized case merely because the employment record is already public.&lt;/p&gt;

&lt;p&gt;Even a collection of individually harmless details can make an episode identifiable. Preserve the engineering mechanism while changing or omitting unnecessary specifics.&lt;/p&gt;

&lt;p&gt;The public claim should be something the available evidence can support without inviting the reader to inspect a closed system. "I evaluated and refined workflows" is a different claim from "this programme improved company delivery."&lt;/p&gt;

&lt;h2&gt;
  
  
  Feed the result back into the right layer
&lt;/h2&gt;

&lt;p&gt;When an error repeats, decide which control should change.&lt;/p&gt;

&lt;p&gt;An outdated repository convention belongs in repository context. A general validation habit may belong in a reusable workflow. A missing permission boundary may require tool access to change, not another paragraph in the prompt.&lt;/p&gt;

&lt;p&gt;If the failure came from stale task evidence, repair the handoff or current-state check. If the skill added unnecessary steps, narrow when it applies. If the result remains ambiguous, keep the ambiguity in the record rather than forcing a favorable or unfavorable rating.&lt;/p&gt;

&lt;p&gt;This is where evaluation becomes engineering work. The record is not the final product; the corrected operating arrangement is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Useful attribution is specific enough to change the next task and modest enough not to invent a cause.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A smaller conclusion can be more reusable
&lt;/h2&gt;

&lt;p&gt;I do not need every evaluation to end with a winner. I need to know which practice helped under which conditions, what required correction, and what the evidence could not distinguish.&lt;/p&gt;

&lt;p&gt;That lets the next task inherit a more useful check or a simpler process instead of a larger claim.&lt;/p&gt;

&lt;p&gt;The five articles in this wave share that approach. Context needs freshness. Green checks need scope. Tool output needs inspection. Reviews need a revision. Skills need honest attribution. None of those mechanisms removes the need for engineering judgement; they give it better material to work with.&lt;/p&gt;

&lt;p&gt;That is the agentic engineering I want to describe: an environment that can learn from ordinary failures without pretending the agent was correct all along.&lt;/p&gt;

&lt;p&gt;If a skill helped your work, what changed in the actual sequence of decisions? I'd be interested in that observation, including what your existing tools or judgement contributed alongside it.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>agenticengineering</category>
      <category>evaluation</category>
      <category>engineeringworkflow</category>
    </item>
    <item>
      <title>The Backup Exists. The Restore Still Needs Work.</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Fri, 16 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/the-backup-exists-the-restore-still-needs-work-5hmf</link>
      <guid>https://dev.to/maximusft/the-backup-exists-the-restore-still-needs-work-5hmf</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%2Fonm1ngav648k3xgeanzw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fonm1ngav648k3xgeanzw.png" alt="The Backup Exists. The Restore Still Needs Work." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The database restores successfully to 10:42.&lt;/p&gt;

&lt;p&gt;The payment provider has transactions through 11:07. Object storage contains invoices created after the restore point. The queue still holds jobs referring to orders the restored database does not remember.&lt;/p&gt;

&lt;p&gt;The backup worked. We have not yet recovered the application.&lt;/p&gt;

&lt;p&gt;I think this is the useful distinction to make before an incident. Recovery is not one storage operation. It is deciding which facts remain authoritative after different parts of the system have moved to different points in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability and recovery solve different failures
&lt;/h2&gt;

&lt;p&gt;A replica can keep the service available after one machine fails. It may also faithfully replicate the accidental deletion we are trying to undo.&lt;/p&gt;

&lt;p&gt;A backup preserves another state. Point-in-time recovery can reconstruct a database using a base backup and subsequent transaction-log records, within the retained recovery window. Its value depends on those records being available and the restore procedure actually working.&lt;/p&gt;

&lt;p&gt;Neither mechanism automatically restores object storage, credentials, queue state, or external services.&lt;/p&gt;

&lt;p&gt;I would define the failure being covered: infrastructure loss, accidental deletion, corruption, an incompatible migration, or compromised access. A design that handles the first can still be inadequate for the others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put a business meaning behind RPO and RTO
&lt;/h2&gt;

&lt;p&gt;Recovery point objective describes acceptable data loss. Recovery time objective describes acceptable time to restore the required service.&lt;/p&gt;

&lt;p&gt;"Fifteen minutes" sounds specific. It still needs a meaning. Can fifteen minutes of submitted support forms disappear? Of inventory reservations? Of charged orders? Those are different promises.&lt;/p&gt;

&lt;p&gt;Some operations need reconciliation from another authoritative system even when the database recovery point is acceptable. A payment provider may tell us about a charge the restored database lost. We need a stable reference linking it back to the business operation.&lt;/p&gt;

&lt;p&gt;For recovery time, include more than restoring bytes: provisioning, access approval, decryption keys, application startup, verification, reconciliation, traffic switching, and safe resumption of workers.&lt;/p&gt;

&lt;p&gt;I would measure the whole exercise. A ten-minute restore inside a two-hour recovery procedure is not a ten-minute RTO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restore beside production, not blindly over it
&lt;/h2&gt;

&lt;p&gt;For a logical data mistake, restoring an isolated instance gives us room to inspect the recovered state and compare it with current production. We may be able to repair a specific set of rows instead of rewinding everything.&lt;/p&gt;

&lt;p&gt;Keep the recovery environment unable to send real emails, charge payments, consume production queues, or execute live webhooks. A copied database can contain pending work that application startup eagerly resumes.&lt;/p&gt;

&lt;p&gt;Use controlled configuration and network access, not merely a promise that nobody will click the dangerous button. Preserve the original state as evidence while deciding which changes to apply.&lt;/p&gt;

&lt;p&gt;Sometimes a full cutover is necessary. Even then, the new instance should be verified before traffic moves, with a deliberate plan for connections, endpoints, and old application instances.&lt;/p&gt;

&lt;p&gt;DNS changes have the &lt;a href="https://ma-x.im/blog/full-stack-domains-and-proxies" rel="noopener noreferrer"&gt;overlap behavior&lt;/a&gt; discussed earlier. Applications may also cache connection settings or continue using old pools. Changing a database endpoint is a release step, not a universal disconnect command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Match data with code and configuration
&lt;/h2&gt;

&lt;p&gt;A database restored to yesterday may have yesterday's schema. Today's application may require a column that did not exist then.&lt;/p&gt;

&lt;p&gt;Record the schema migration state alongside artifact and configuration revisions. Retain deployable artifacts, not just source code that could theoretically be rebuilt with today's package registry.&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://ma-x.im/blog/full-stack-zero-downtime-migrations" rel="noopener noreferrer"&gt;expand/contract migration&lt;/a&gt; gives recovery more options, but it does not remove the need to choose a compatible application version. Running every pending migration automatically against the restored instance may recreate the destructive change we were trying to investigate.&lt;/p&gt;

&lt;p&gt;Secrets matter too. A backup encrypted with an unavailable key is not useful. A restored application with revoked credentials cannot necessarily reach its dependencies. Back up and test the recovery of access paths without scattering secret values through documents or logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  External effects do not rewind with the database
&lt;/h2&gt;

&lt;p&gt;Consider an order that was paid at 10:55 and lost from a database restored to 10:42. Asking the customer to retry can charge them again unless the payment operation has a durable, stable identity.&lt;/p&gt;

&lt;p&gt;Reconcile against the provider using idempotency keys, merchant references, and the provider's authoritative transaction state. Do not infer a refund or charge from the absence of a local row alone.&lt;/p&gt;

&lt;p&gt;Email is another external effect. A replayed confirmation job may send a second message. An invoice number may already have been issued. A shipment may already be in transit.&lt;/p&gt;

&lt;p&gt;The recovery procedure should describe those consequences and the systems that settle them. We cannot restore the world to match a snapshot. We can reconstruct our records so they agree with the world that continued operating.&lt;/p&gt;

&lt;p&gt;This is where the identity choices from the &lt;a href="https://ma-x.im/blog/full-stack-api-contracts" rel="noopener noreferrer"&gt;API&lt;/a&gt; and &lt;a href="https://ma-x.im/blog/full-stack-background-jobs" rel="noopener noreferrer"&gt;queue&lt;/a&gt; articles become more than implementation conveniences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queues and caches need a recovery policy
&lt;/h2&gt;

&lt;p&gt;A restored outbox may contain events already published before the incident. A current queue may contain messages for records absent from the recovered database.&lt;/p&gt;

&lt;p&gt;Pause consumers while reconciling. Decide which messages to preserve, replay, quarantine, or discard. Idempotent consumers reduce the cost of duplicates, but they still need a coherent business state to operate on.&lt;/p&gt;

&lt;p&gt;Do not delete the queue simply to make its depth look tidy. It may contain the only remaining record of accepted work.&lt;/p&gt;

&lt;p&gt;Redis also needs role-specific handling. Rebuild a disposable product cache from the recovered source. For sessions, consider whether invalidating them is safer than restoring older authorization state. For locks or scheduler metadata, old values may be actively misleading.&lt;/p&gt;

&lt;p&gt;"Restore every dependency" is not always the right instruction. Some state should be restored, some reconciled, and some deliberately recreated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify meaning, not only row counts
&lt;/h2&gt;

&lt;p&gt;A database that starts and contains the expected number of rows is encouraging. It does not prove the checkout workflow is usable.&lt;/p&gt;

&lt;p&gt;Check relationships, critical constraints, recent business operations, object references, account permissions, and one controlled end-to-end flow. Compare representative records with external authoritative systems where necessary.&lt;/p&gt;

&lt;p&gt;Keep enough telemetry to tell when corrupted or missing data first appeared. Otherwise choosing a restore point becomes a sequence of guesses, each followed by another expensive restore.&lt;/p&gt;

&lt;p&gt;Data integrity checks and recovery logs should avoid publishing private customer content. The people conducting a recovery need controlled access, not an unrestricted data export pasted into the incident channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the access path that an incident will use
&lt;/h2&gt;

&lt;p&gt;A recovery exercise run by an administrator with every permission can conceal missing privileges in the actual emergency role. Test who can start the restore, decrypt it, deploy compatible code, change routing, and release the isolation controls.&lt;/p&gt;

&lt;p&gt;For compromise scenarios, consider independent backup protection: restricted deletion, retention controls, and appropriate account or region separation. If the same credential can destroy production and every backup, the copies share a rather important failure mode.&lt;/p&gt;

&lt;p&gt;There is no universal arrangement that makes all of this free. The choices should reflect the actual data, recovery promise, and threat model.&lt;/p&gt;

&lt;p&gt;Document who makes the cutover decision and who handles reconciliation. That is operational ownership, not an excuse to collect an impressive runbook nobody has tried.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful drill has an inconvenient detail
&lt;/h2&gt;

&lt;p&gt;Try restoring with an old schema, an unavailable primary region, a rotated credential, or a job already delivered once. Choose one complication rather than pretending the exercise must reproduce every disaster at once.&lt;/p&gt;

&lt;p&gt;Measure the result, record the steps that required undocumented knowledge, and repair those gaps. A failed rehearsal is useful when it changes the recovery path before the real incident.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A backup preserves data. A rehearsed recovery preserves the ability to use it safely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where I would end this field guide. The database, cache, queue, proxy, and application are not independent checkboxes. Their boundaries become visible when a request fails, a deployment overlaps, or one component returns to an earlier state.&lt;/p&gt;

&lt;p&gt;I would be satisfied with an ordinary system whose recovery procedure is unremarkable because it has been tested. That seems a more useful goal than another layer whose failure behavior we will learn later.&lt;/p&gt;

&lt;p&gt;If you've attempted a restore rehearsal, what took longer than the database restore itself? I'd be interested in the dependency or decision the backup dashboard could not account for.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>database</category>
      <category>recovery</category>
      <category>reliability</category>
    </item>
    <item>
      <title>A Review Belongs to a Commit</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Thu, 15 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/a-review-belongs-to-a-commit-2a5b</link>
      <guid>https://dev.to/maximusft/a-review-belongs-to-a-commit-2a5b</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%2Fs41vs3ga9lkuc8m1qhtb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs41vs3ga9lkuc8m1qhtb.png" alt="A Review Belongs to a Commit" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A reviewer sees a change and raises a useful concern. The author pushes another commit.&lt;/p&gt;

&lt;p&gt;The comment is still there. The code it described may not be.&lt;/p&gt;

&lt;p&gt;Human reviewers handle this imperfectly too. An automated reviewer makes the state-management problem easier to notice because it can repeat the same concern every time it runs, or confidently act on a conclusion from the previous revision.&lt;/p&gt;

&lt;p&gt;The earlier &lt;a href="https://ma-x.im/blog/github-ai-pr-reviewer" rel="noopener noreferrer"&gt;PR-reviewer article&lt;/a&gt; focused on useful language and visibility into a personal tool. This article is about a narrower engineering problem: what a finding, check, or review decision refers to as the code changes.&lt;/p&gt;

&lt;p&gt;I have developed commit-aware tracking, duplicate-finding safeguards, dry-run checks, and guarded actions in personal review tooling with AI assistance. That describes development of mechanisms, not current continuous operation, organization-wide adoption, or a replacement for human approval.&lt;/p&gt;

&lt;h2&gt;
  
  
  A PR number is not the reviewed object
&lt;/h2&gt;

&lt;p&gt;The PR is a container for an evolving proposal. The head commit identifies one version of that proposal. The base revision and comparison mode also affect what the reviewer sees.&lt;/p&gt;

&lt;p&gt;If an automated tool records only "PR reviewed," it cannot distinguish unchanged work from a new commit. If it records only head SHA, it may miss a changed base or integration result that matters to its conclusion.&lt;/p&gt;

&lt;p&gt;A useful record identifies what was reviewed and under which assumptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ReviewSnapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;headSha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;baseSha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;comparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pull-request-diff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;rulesRevision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;checkedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an illustrative type, not an internal implementation. The rules revision matters because the same code can be assessed differently after the checking policy changes.&lt;/p&gt;

&lt;p&gt;I would not let a convenient database row imply more history than it contains. "Reviewed" should be explainable as a particular observation, not a permanent property of the PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI has a revision too
&lt;/h2&gt;

&lt;p&gt;A green check from an earlier commit does not establish the state of the current one. A required integration check may run on a merge result rather than the branch head. Those are different artifacts.&lt;/p&gt;

&lt;p&gt;Before review actions, identify which checks are relevant, which revision they exercised, and whether they are finished. A skipped check or an optional success is not necessarily equivalent to every required gate passing.&lt;/p&gt;

&lt;p&gt;Even then, CI evidence has the scope limits discussed in Green Checks Only Cover What You Checked. It can support a reviewable state without proving the absence of semantic defects.&lt;/p&gt;

&lt;p&gt;I want a tool to report that distinction rather than promote "green CI" into "safe to approve."&lt;/p&gt;

&lt;h2&gt;
  
  
  A finding needs identity and evidence
&lt;/h2&gt;

&lt;p&gt;Line numbers are useful for placement. They are poor long-term finding identities.&lt;/p&gt;

&lt;p&gt;An author can move the same risky expression to another line. The finding remains relevant, but a line-based key changes and the bot may publish it again. Conversely, new code at the old line can have a different risk that a naive key suppresses.&lt;/p&gt;

&lt;p&gt;A more semantic identity can include the rule, affected symbol, risk category, and relevant normalized evidence. Keep the exact source revision alongside it.&lt;/p&gt;

&lt;p&gt;Normalization introduces its own trade-off. Strip too much context and different findings collapse into one fingerprint. Keep every character and harmless formatting changes produce duplicates.&lt;/p&gt;

&lt;p&gt;Treat a fingerprint as a useful matching mechanism, not proof that two concerns are identical. Re-evaluate the current evidence before deciding the old finding still applies or no new comment is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suppressed does not mean resolved
&lt;/h2&gt;

&lt;p&gt;A repeated finding can be current and intentionally not republished. A missing finding can mean it was fixed, became unobservable in the selected diff, or was skipped because the analysis failed.&lt;/p&gt;

&lt;p&gt;Those states need different names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;current:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;concern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;supported&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;evidence&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;unchanged:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;current,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;but&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;repeated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;needed&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;resolved:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;evidence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;supports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;concern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;longer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;applies&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;not-observed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;did&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;establish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;either&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;outcome&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;needs-human:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cannot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;question&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;safely&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact storage model can vary. The distinction keeps duplicate suppression from quietly becoming automatic resolution.&lt;/p&gt;

&lt;p&gt;An unresolved human thread is another state the tool should not overwrite simply because its own detector no longer sees the pattern. The thread may concern context or a decision that the detector never understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recheck state before publication
&lt;/h2&gt;

&lt;p&gt;Analysis can take time. While it runs, the author can push new code. A comment created from the original diff may now point to invalid lines or describe a risk that has already changed.&lt;/p&gt;

&lt;p&gt;Re-read the relevant state before publishing. If it no longer matches the reviewed snapshot, stop, discard the pending action, or schedule another review. Do not silently attach the finding to a different revision because that makes the API call easier.&lt;/p&gt;

&lt;p&gt;The same applies to stronger actions. A guarded action should carry the expected revision and use a platform-supported condition where available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GuardedReviewAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;expectedHeadSha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;snapshotId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;publish-review&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This type expresses the requirement; it does not implement an atomic guarantee. Reading head and then calling an API leaves a time-of-check/time-of-use interval. If the platform cannot condition the action atomically, handle that limitation explicitly and avoid unsupported claims about stale-action prevention.&lt;/p&gt;

&lt;p&gt;A fresh check reduces risk. It does not freeze another person's branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  A dry run has its own evidence boundary
&lt;/h2&gt;

&lt;p&gt;A dry run can show which findings and actions a tool would produce. It is useful for inspecting scope, tone, duplicates, and targeting without creating external effects.&lt;/p&gt;

&lt;p&gt;It does not prove that the later API call will be authorized, attach to the intended line, or observe the same PR state. Nor does a successful API call prove the review content was correct.&lt;/p&gt;

&lt;p&gt;Use the dry run to inspect proposed actions. Use publication checks to verify current state and delivery. Keep the two results separate in the control interface.&lt;/p&gt;

&lt;p&gt;If the inline attachment fails, a body-level review may preserve the concern, but should still identify the source revision. A fallback should not turn a precisely scoped observation into an unexplained general warning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human decisions need context, not silent reassignment
&lt;/h2&gt;

&lt;p&gt;A person may approve a particular revision. New code can change the basis for that decision. The tool should make that change visible and follow the platform's review policy rather than assume an earlier approval means the new code is accepted.&lt;/p&gt;

&lt;p&gt;Whether an approval is dismissed, still valid, or requires a new decision depends on the repository's settings and accountable reviewers. The automation should not invent its own release authority.&lt;/p&gt;

&lt;p&gt;Likewise, an AI suggestion that a dependency update appears routine is evidence, not permission to merge it. Any permitted automatic action needs its own narrowly defined authorization and technical controls. It should not be inferred from the absence of findings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A review result describes observed code. It does not transfer responsibility for whatever code arrives next.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Preserve enough history to explain the tool
&lt;/h2&gt;

&lt;p&gt;The control surface should answer ordinary questions: which revision was analyzed, what was published, what was suppressed, why a run stopped, and what remains undecided.&lt;/p&gt;

&lt;p&gt;Record identifiers and outcomes with appropriate retention. Avoid storing raw credentials, private payloads, or unnecessary code copies just to make a log feel complete.&lt;/p&gt;

&lt;p&gt;When the tool is wrong, the history should help reproduce the decision. Was the input stale? Did normalization merge two findings? Did a missing detector result get treated as resolution? Did the action target change between analysis and publication?&lt;/p&gt;

&lt;p&gt;Those are repairable mechanisms. Without the history, every correction becomes a guess about the model's intentions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quieter reviewer is not necessarily the better reviewer
&lt;/h2&gt;

&lt;p&gt;Duplicate suppression makes the conversation less noisy. That is useful. It can also hide an unresolved issue if the lifecycle is poorly modelled.&lt;/p&gt;

&lt;p&gt;I would evaluate the tool on the relevance and traceability of its findings, not merely on how few comments it emits. Check unchanged code, moved code, corrected code, a new risk at the old location, and a head update during analysis.&lt;/p&gt;

&lt;p&gt;Keep a human in charge of interpretation and approval. A review assistant should make that person's evidence easier to find, not create a reassuring status that no one can explain.&lt;/p&gt;

&lt;p&gt;The next article, &lt;a href="https://ma-x.im/blog/agent-playbook-what-a-skill-changed" rel="noopener noreferrer"&gt;What a Skill Changed, and What It Didn't&lt;/a&gt;, examines the same attribution problem at workflow level: what a reusable skill changed, and what it did not.&lt;/p&gt;

&lt;p&gt;If your review automation remembers that it saw a PR, what exactly does it remember about the code? That is a useful place to inspect before adding another action to it.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>codereview</category>
      <category>developertooling</category>
      <category>reliability</category>
    </item>
    <item>
      <title>The Dashboard Is Green. The Order Is Missing.</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Wed, 14 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/the-dashboard-is-green-the-order-is-missing-19ag</link>
      <guid>https://dev.to/maximusft/the-dashboard-is-green-the-order-is-missing-19ag</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%2Fig86qanpn9iexpzb5fqw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fig86qanpn9iexpzb5fqw.png" alt="The Dashboard Is Green. The Order Is Missing." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The API error rate is low. The workers are running. The browser reported no uncaught exception.&lt;/p&gt;

&lt;p&gt;A user says their order never appeared.&lt;/p&gt;

&lt;p&gt;All of those observations can be true. We measured the health of individual pieces, while the user described an outcome across several pieces. The missing part is the connection between them.&lt;/p&gt;

&lt;p&gt;I do not think the answer is simply to log more. A larger pile of unrelated events gives us more to read, which is not quite the same thing as giving us more to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the outcome we need to explain
&lt;/h2&gt;

&lt;p&gt;For checkout, I would distinguish browser intent, request acceptance, order persistence, payment confirmation, and follow-up work.&lt;/p&gt;

&lt;p&gt;These are not synonyms. A click event proves that someone activated a control. A 200 response proves that an HTTP exchange returned that status. A database record proves that an order was stored. A confirmation email proves another effect entirely.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ma-x.im/blog/react-playbook-analytics-as-a-layer" rel="noopener noreferrer"&gt;analytics layer&lt;/a&gt; and an operational trace also serve different purposes. Product analytics can describe behavior; operational telemetry needs enough context to reconstruct a specific failure without assuming every recorded click became a completed purchase.&lt;/p&gt;

&lt;p&gt;I would define the business success point explicitly, then work backwards to the evidence required at each boundary. Otherwise the most available metric quietly becomes the definition of success.&lt;/p&gt;

&lt;h2&gt;
  
  
  A request id is useful, but it is not the whole identity
&lt;/h2&gt;

&lt;p&gt;A request id correlates one HTTP attempt. An idempotency key identifies one intent across retries. An order id identifies durable business state. A trace context links spans across participating services.&lt;/p&gt;

&lt;p&gt;Keeping these separate is helpful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order.persisted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"request_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"req_9c7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operation_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkout_62a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"order_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order_18f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4bf92f3577b34da6a3ce929d0e0e4736"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkout-2026-10-14"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are synthetic identifiers. The record does not include a customer's name, email, address, token, or raw payment data.&lt;/p&gt;

&lt;p&gt;A retry gets a new request id but retains the operation identity. A background job can link to the operation after the original request has ended. Depending on timing and instrumentation, a span link may describe that relationship more honestly than an endlessly extended parent span.&lt;/p&gt;

&lt;p&gt;Use established trace propagation and instrumentation, such as OpenTelemetry, rather than inventing a collection of vaguely compatible headers. Still validate untrusted incoming context and keep authorization separate from any telemetry identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing data has several explanations
&lt;/h2&gt;

&lt;p&gt;If a trace is absent, the request may never have happened. It may also have been sampled out, rejected by a collector, dropped from a full buffer, or generated by an uninstrumented component.&lt;/p&gt;

&lt;p&gt;Head sampling decides early which traces to retain. It keeps costs bounded, but it cannot know at the start which request will fail late. Tail sampling can select after observing more of the trace, at the cost of buffering, coordination, and its own resource limits.&lt;/p&gt;

&lt;p&gt;Neither gives perfect evidence automatically. Keep critical outcome counters and durable business records independently of a sampling decision. Record the telemetry pipeline's own drops and health so absence is less ambiguous.&lt;/p&gt;

&lt;p&gt;For frontend error reporting, the same limitation applies. Browser extensions, network conditions, consent settings, and navigation can affect delivery. No recorded exception is not proof that no exception occurred.&lt;/p&gt;

&lt;h2&gt;
  
  
  Denominators need their own definition
&lt;/h2&gt;

&lt;p&gt;"Twenty failed orders" is difficult to interpret without knowing how many attempts occurred and which attempts count.&lt;/p&gt;

&lt;p&gt;Counting API requests exaggerates user intent when retries occur. Counting clicks includes actions rejected before a request. Counting created orders excludes failures before persistence.&lt;/p&gt;

&lt;p&gt;For an outcome metric, define both numerator and denominator around the promise being measured. For example: distinct accepted checkout operations that reach a confirmed or explicit terminal state within a chosen interval.&lt;/p&gt;

&lt;p&gt;Then describe exclusions: abandoned carts, expected validation failures, test traffic, and operations still inside their allowed processing window. An illustrative target is not a universal SLO.&lt;/p&gt;

&lt;p&gt;The arithmetic is usually easy. The difficult part is resisting a reassuring percentage with a poorly chosen population.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cardinality is a modelling choice
&lt;/h2&gt;

&lt;p&gt;Metrics work well with bounded dimensions such as route templates, status categories, region, and service.&lt;/p&gt;

&lt;p&gt;Attaching &lt;code&gt;order_id&lt;/code&gt;, raw URLs, or customer email to every metric label creates huge numbers of distinct time series. It also turns the monitoring system into a rather expensive and unsuitable customer index.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;/orders/:id&lt;/code&gt;, not every concrete order URL, as a metric dimension. Put specific identities in controlled logs or traces when needed, with retention and access appropriate to their sensitivity.&lt;/p&gt;

&lt;p&gt;Histograms deserve some care too. Percentiles computed independently by instances cannot generally be averaged into the fleet's percentile. Aggregate compatible histogram observations rather than averaging whichever p95 numbers happen to be on the screen.&lt;/p&gt;

&lt;p&gt;The goal is not to avoid detail. It is to put detail into the kind of evidence that can handle it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend context can make a backend trace usable
&lt;/h2&gt;

&lt;p&gt;A server sees requests. The browser knows which route, interaction, and release led to them.&lt;/p&gt;

&lt;p&gt;For an error-reporting tool such as Sentry, a release identifier and matching source maps can turn a minified stack into something useful. Upload source maps through controlled tooling; decide whether publicly serving source files is intended. A production error should identify the bundle that actually ran, not the latest source in main.&lt;/p&gt;

&lt;p&gt;Session replay can help explain interaction sequences, but I would not enable it broadly without reviewing masking, consent, sensitive fields, retention, and access. "It is an internal admin screen" is often a reason for more care, not less.&lt;/p&gt;

&lt;p&gt;Expected cancellation should not appear beside faults as though a user navigating away is a broken system. The &lt;a href="https://ma-x.im/blog/react-playbook-abort-controller" rel="noopener noreferrer"&gt;AbortController article&lt;/a&gt; covers that distinction at the interface boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  An alert should name a response
&lt;/h2&gt;

&lt;p&gt;High CPU may deserve investigation. Missing orders deserve investigation for a more direct reason.&lt;/p&gt;

&lt;p&gt;Prefer alerts connected to user-visible impact or exhausted safety margins: sustained error-budget consumption, queue age beyond the product allowance, connection-pool waits, failure to complete accepted operations, or a recovery dependency approaching expiry.&lt;/p&gt;

&lt;p&gt;The notification needs an owner, a scope, and a useful next action. A chart link is helpful. So are a recent deployment marker and a runbook that says which evidence separates an application failure from a shared-dependency failure.&lt;/p&gt;

&lt;p&gt;I would not page someone every time one instance reports a brief spike unless that spike calls for a meaningful intervention. Noise does not stay harmless; it changes what people notice later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telemetry is another dependency
&lt;/h2&gt;

&lt;p&gt;Exporters have buffers, network calls, timeouts, and shutdown behavior. A slow collector should not cause the checkout handler to wait indefinitely or allocate unbounded memory.&lt;/p&gt;

&lt;p&gt;Use bounded, asynchronous export appropriate to the instrumentation. Decide what can be dropped and what must be durably recorded elsewhere. Business events required for fulfilment belong in a durable mechanism such as the &lt;a href="https://ma-x.im/blog/full-stack-background-jobs" rel="noopener noreferrer"&gt;transactional outbox&lt;/a&gt;, not solely in a best-effort log stream.&lt;/p&gt;

&lt;p&gt;Also test redaction failures and collector outages. Observability should help us explain failure without becoming its next cause or a route for leaking data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A telemetry event is evidence with delivery conditions, not a second database transaction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reconstruct one unsuccessful operation
&lt;/h2&gt;

&lt;p&gt;I would exercise a deliberately failed checkout and try to follow it from browser intent to its final state. Can we distinguish a request that never arrived from an order that persisted but lost its response? Can we find the background job? Can we identify the release and a retry without counting them as two purchases?&lt;/p&gt;

&lt;p&gt;If those questions are difficult, another dashboard will not necessarily improve the situation. A better identity or an event at the missing boundary might.&lt;/p&gt;

&lt;p&gt;The green dashboard becomes useful when we know exactly what its green means. Until then, I would keep the user's missing order as the more interesting observation.&lt;/p&gt;

&lt;p&gt;The final part of this guide covers &lt;a href="https://ma-x.im/blog/full-stack-backups-and-recovery" rel="noopener noreferrer"&gt;backups and recovery&lt;/a&gt;: what happens when diagnosis is finished and some part of the system actually has to be rebuilt.&lt;/p&gt;

&lt;p&gt;Which production question still sends you comparing timestamps across three tools? I'd like to hear the missing connection, not just which monitoring product you use.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>observability</category>
      <category>reliability</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The Command Succeeded. The Scope Changed.</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Tue, 13 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/the-command-succeeded-the-scope-changed-5hd5</link>
      <guid>https://dev.to/maximusft/the-command-succeeded-the-scope-changed-5hd5</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%2Ff6v2av05rgjc3ize8kd1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff6v2av05rgjc3ize8kd1.png" alt="The Command Succeeded. The Scope Changed." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent inspects a small diff and runs the required command.&lt;/p&gt;

&lt;p&gt;The command succeeds. A hook also regenerates a contract file from a newer source, and the resulting commit contains a change nobody asked for.&lt;/p&gt;

&lt;p&gt;That is not a runaway agent. It is fairly normal repository automation doing what it was configured to do. The workflow still needs to decide whether the output belongs in this task.&lt;/p&gt;

&lt;p&gt;I have used this kind of scope drift to refine the checks around delegated work. Reviewing an initial diff is useful; reviewing the artifact after automation is also necessary. They are not always the same artifact.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example is deliberately synthetic
&lt;/h2&gt;

&lt;p&gt;Consider this illustrative composite, not a file tree from an actual company repository.&lt;/p&gt;

&lt;p&gt;A task updates one client dependency. Before the commit, the changes are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;package-lock.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A repository hook refreshes generated API code. The commit now also contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;generated&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;generated&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generator may be correct about the source it read. The new contract may be a legitimate change. Neither fact says it belongs in a dependency-only PR.&lt;/p&gt;

&lt;p&gt;It could need another owner, another compatibility check, another release sequence, or simply a separate explanation. A successful generator run does not provide those decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are several versions of the change
&lt;/h2&gt;

&lt;p&gt;A Git operation has more than one relevant state: working tree, index, commit tree, and the remote branch used by review.&lt;/p&gt;

&lt;p&gt;An agent can inspect the working tree, stage a subset, and then assume the commit contains that subset. A hook can change files or restage content between those steps. Later, a push hook or generated build output can leave additional local changes that are not committed at all.&lt;/p&gt;

&lt;p&gt;The useful question is "which artifact did we verify?"&lt;/p&gt;

&lt;p&gt;These generic inspection commands address different artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--name-status&lt;/span&gt;
git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--name-status&lt;/span&gt;
git show &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;--stat&lt;/span&gt; HEAD
git show &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; HEAD
git status &lt;span class="nt"&gt;--short&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first two compare working and staged changes. The next two inspect the actual commit. The final status shows what remains outside it. None, by itself, establishes whether the whole task is correctly scoped.&lt;/p&gt;

&lt;p&gt;I would inspect the post-hook commit before treating it as ready for review or push. If the repository runs consequential automation during push, inspect its effects too rather than assuming the operation left no new state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture the starting state
&lt;/h2&gt;

&lt;p&gt;Scope checks are less useful if the agent does not know which changes existed before it started.&lt;/p&gt;

&lt;p&gt;A working tree can already contain another person's edits. A generated file may have been dirty before the task. A script may update it again, mixing pre-existing content with the agent's output.&lt;/p&gt;

&lt;p&gt;Record the branch, base revision, and clean or dirty status before implementation. For relevant dirty files, understand the existing changes instead of treating everything outside the task as disposable.&lt;/p&gt;

&lt;p&gt;This is especially important when recovering from generated drift. "Remove unrelated files" is not permission to overwrite a colleague's uncommitted work.&lt;/p&gt;

&lt;p&gt;The safe recovery depends on provenance: which change was introduced by this operation, which was already present, and which now conflicts with the authorized work. If that cannot be established cheaply, stop and ask rather than manufacture a clean tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  A file allowlist helps, but it is not the contract
&lt;/h2&gt;

&lt;p&gt;For a bounded task, an expected file set can reveal surprises:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected: dependency manifest and lockfile
Observed: manifest, lockfile and generated service contract
Decision needed: does the contract change belong to this task?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes the right implementation legitimately needs another file. A test, a call site, or an adapter may be required to satisfy the original behavior. A strict allowlist should expose that question, not force an incomplete fix.&lt;/p&gt;

&lt;p&gt;The reverse is also true: changes inside an expected file can be unrelated. A lockfile may contain several package updates. One generated module can include multiple contract changes with different owners.&lt;/p&gt;

&lt;p&gt;Review semantics as well as filenames. The requested scope is an engineering constraint, not a glob pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generated does not mean low risk
&lt;/h2&gt;

&lt;p&gt;Generated artifacts can encode public APIs, schemas, route tables, database clients, or configuration. A small mechanical change there can affect more consumers than a large handwritten component edit.&lt;/p&gt;

&lt;p&gt;A tool may regenerate against a remote source whose revision is not recorded. Run it twice and it can produce two different outputs from the same local commit. The task has acquired an external input even though nobody edited an external file by hand.&lt;/p&gt;

&lt;p&gt;Where practical, pin and record the generator version and input revision, or preserve the relevant source snapshot. Keep generated output reproducible enough to explain a future diff.&lt;/p&gt;

&lt;p&gt;If a live input is intentional, review the new output with that knowledge. Do not present it as a consequence of the dependency change when it came from unrelated source drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not bypass the gate just to avoid its output
&lt;/h2&gt;

&lt;p&gt;The tempting response is to disable the hook and finish the small PR.&lt;/p&gt;

&lt;p&gt;That may discard a required repository control. It also avoids the useful question of why this hook introduces changes unrelated to the task.&lt;/p&gt;

&lt;p&gt;Follow the repository's supported procedure. It may allow a separate generated update, a pinned input, a check-only mode, or an explicitly approved exception. The agent should not invent an exemption because the hook is inconvenient.&lt;/p&gt;

&lt;p&gt;After separating unrelated drift, run the checks that matter for the retained change and inspect the final artifact again. A repaired scope still needs verification; the earlier green result may have observed a different set of files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool success is not scope approval
&lt;/h2&gt;

&lt;p&gt;An exit code tells us whether the tool considers its operation successful. It does not certify that the operation had the intended inputs or that every resulting change was authorized.&lt;/p&gt;

&lt;p&gt;This applies beyond Git hooks. A formatter can touch unrelated documents. A package manager can alter registry URLs or transitive versions. A code migration can rewrite more call sites than the agreed rollout intended.&lt;/p&gt;

&lt;p&gt;The agent's explanation should identify those effects, not compress them into "all commands passed."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The command's success belongs to the command. Approval of the resulting scope belongs to the task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction allows useful automation without pretending tools understand the whole purpose of a change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the check repeatable, not the incident immortal
&lt;/h2&gt;

&lt;p&gt;After a scope problem, I would refine the workflow around the failure condition: record the starting state, inspect after mutating automation, and verify the artifact that will actually be reviewed.&lt;/p&gt;

&lt;p&gt;I would not add a permanent paragraph describing every generated file from that one incident. Those details age quickly. The principle remains useful across different generators and repositories.&lt;/p&gt;

&lt;p&gt;The rule also needs proportion. A read-only test command does not need the same artifact accounting as a commit hook that regenerates contracts. Use the checks where state can change, and keep the explanation local enough that the agent can apply it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The final diff should be unsurprising for the right reason
&lt;/h2&gt;

&lt;p&gt;An agent can produce a neat initial patch and still need help with the effects of the surrounding toolchain. That is not a contradiction. The repository is part of the execution environment, and it can change the result.&lt;/p&gt;

&lt;p&gt;I want a reviewer to find the final scope unsurprising because the task explains every meaningful change, not because generated files were hidden from the description.&lt;/p&gt;

&lt;p&gt;The next article, &lt;a href="https://ma-x.im/blog/agent-playbook-review-belongs-to-commit" rel="noopener noreferrer"&gt;A Review Belongs to a Commit&lt;/a&gt;, follows that reviewed artifact as it changes again. A later commit can make yesterday's finding or decision stale.&lt;/p&gt;

&lt;p&gt;If a tool in your repository can change the artifact after its last inspection, where is the next inspection scheduled? That small gap is worth closing before adding more autonomy.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>agenticengineering</category>
      <category>git</category>
      <category>scopecontrol</category>
    </item>
    <item>
      <title>More Replicas, the Same Database</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/more-replicas-the-same-database-4jcm</link>
      <guid>https://dev.to/maximusft/more-replicas-the-same-database-4jcm</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%2F8jo9zuo2lxultisnt6m7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8jo9zuo2lxultisnt6m7.png" alt="More Replicas, the Same Database" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application is slow, so the autoscaler adds replicas.&lt;/p&gt;

&lt;p&gt;Each new replica opens its normal database connection pool. The database was already waiting on locks. Now it has more callers waiting on the same locks.&lt;/p&gt;

&lt;p&gt;CPU on the application instances improves. Checkout latency does not.&lt;/p&gt;

&lt;p&gt;Nothing in that sequence is especially exotic. We scaled the part that could multiply, without checking the capacity of the part all those copies still share. I find that a more useful starting point than the usual discussion of which load-balancing algorithm looks fairest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unit of scaling includes its dependencies
&lt;/h2&gt;

&lt;p&gt;An application replica is not just a process with some CPU. It is also a database pool, a set of cache connections, outbound calls, retry behavior, and startup work.&lt;/p&gt;

&lt;p&gt;Consider a simplified connection budget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;database limit: 200
reserved for administration: 20
workers and other services: 40
available to the web application: 140

8 replicas x 15 pool connections: 120
12 replicas x 15 connections: 180

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These numbers are illustrative. A pool maximum does not mean every process immediately opens every connection, but it is a capacity promise we need to bound. A rolling deployment can temporarily run both old and new replicas. The maximum deployment overlap belongs in the budget too.&lt;/p&gt;

&lt;p&gt;I would cap replica count and per-process concurrency together. A connection pooler may help, but it cannot make a transaction release its locks sooner or make a slow query cheaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queuing moves; it does not disappear
&lt;/h2&gt;

&lt;p&gt;If the application accepts work faster than it can finish, requests wait somewhere: at the proxy, inside the process, in the pool, or in the database.&lt;/p&gt;

&lt;p&gt;An unlimited internal queue can make an overloaded service look healthy until requests exceed every client timeout. By then the service may still be doing work for callers that already gave up.&lt;/p&gt;

&lt;p&gt;Explicit admission limits give the system a more useful response. Bound concurrency, reject excess work with a deliberate status, and decide whether a retry can safely occur. Do not spend thirty seconds doing an operation whose result the caller is no longer waiting for.&lt;/p&gt;

&lt;p&gt;Cancellation matters, but cancelling a browser request does not automatically cancel the database operation. Deadline propagation needs to reach the layers that support it, with transaction cleanup handled deliberately.&lt;/p&gt;

&lt;p&gt;I would prefer a small number of quick, understandable overload responses to a large number of ambiguous timeouts. That choice is less attractive on a throughput chart and more attractive during an incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries can manufacture the next spike
&lt;/h2&gt;

&lt;p&gt;A browser retries. The gateway retries. The application retries its upstream call. Three attempts at each layer can multiply rather than merely add.&lt;/p&gt;

&lt;p&gt;If the original work is slow because a shared dependency is saturated, retrying immediately adds more work to that dependency. The request deadline may also restart at each hop, extending the actual time spent far beyond what the caller expects.&lt;/p&gt;

&lt;p&gt;Assign retry ownership. Use a bounded budget, backoff, jitter, and idempotency for writes. Honor useful rate-limit guidance such as &lt;code&gt;Retry-After&lt;/code&gt; rather than asking every client to guess its own recovery rhythm.&lt;/p&gt;

&lt;p&gt;Retries are appropriate when another attempt has a reasonable chance of finding different conditions. They are not a substitute for an overload policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stateless does not mean there is no state
&lt;/h2&gt;

&lt;p&gt;The practical meaning is narrower: another instance can handle the next request without relying on unique state in the previous instance's memory.&lt;/p&gt;

&lt;p&gt;Sessions may live in a shared store. Uploaded files belong in durable object storage. Order state belongs in the database. Any replica can reconstruct what it needs.&lt;/p&gt;

&lt;p&gt;Local caches are still possible. So are in-memory counters and background bookkeeping, provided they are explicitly disposable and do not claim global correctness.&lt;/p&gt;

&lt;p&gt;Sticky sessions can keep a client on one instance, which may be useful for a specific workload. They do not make that instance durable. When it disappears, the unique state disappears too unless a recovery path exists.&lt;/p&gt;

&lt;p&gt;I would describe required affinity as a constraint rather than advertise a system as stateless while quietly depending on the load balancer to remember each user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health checks are routing policy
&lt;/h2&gt;

&lt;p&gt;A liveness check asks whether the process can continue. A readiness check asks whether it should receive new work. A synthetic business check asks whether a useful operation succeeds. They do not necessarily belong in the same endpoint.&lt;/p&gt;

&lt;p&gt;Suppose every instance's readiness check requires Redis to respond. Redis has a shared outage, so every instance becomes unready. Removing all instances may be correct for a session-only application that cannot authenticate anyone. It may be unnecessary for public product pages with a database fallback.&lt;/p&gt;

&lt;p&gt;Restarting all processes because a shared dependency is slow can also worsen recovery by creating connection and cache-warming bursts.&lt;/p&gt;

&lt;p&gt;There is a specific AWS detail worth knowing: &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html" rel="noopener noreferrer"&gt;ALB fails open when a target group has only unhealthy registered targets&lt;/a&gt;. It can route to those targets rather than treating health failure as a guarantee of no traffic.&lt;/p&gt;

&lt;p&gt;This is not a recommendation to return false health results. It is a reminder to understand the platform's actual response and keep application safeguards in place. The health check does not become a security boundary just because the dashboard colors it red.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling needs time to become useful
&lt;/h2&gt;

&lt;p&gt;A new instance may need to pull an image, initialize connections, load configuration, and warm required state before becoming ready. Autoscaling follows observations with a delay; it cannot instantly absorb a sudden spike.&lt;/p&gt;

&lt;p&gt;Keep enough baseline capacity for the workload that cannot wait, and choose signals that reflect the bottleneck. CPU can help for compute-heavy traffic. Queue age may better describe workers. Pool wait time or active-request concurrency may reveal pressure that average CPU hides.&lt;/p&gt;

&lt;p&gt;Avoid a warmup procedure that makes every new replica perform the same expensive full-cache refresh. The capacity meant to help the database can briefly become its largest customer.&lt;/p&gt;

&lt;p&gt;Scale-in is equally important. A quiet instance may still hold a long request or many WebSocket connections. Removing it is a lifecycle event, not just subtracting one from a counter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draining coordinates several timers
&lt;/h2&gt;

&lt;p&gt;The load balancer has a deregistration delay. The process has a shutdown grace period. Requests have deadlines. Connections have idle timeouts. These settings need to agree on how ongoing work ends.&lt;/p&gt;

&lt;p&gt;Stop admitting new requests, allow existing work a bounded interval, then shut down. If the platform kills the task before the drain interval finishes, the load balancer's generous delay does not help.&lt;/p&gt;

&lt;p&gt;For WebSockets, draining may require application messages and client reconnection. A reconnected client can land on another replica; events and subscriptions need shared or reconstructible state. The replacement must not assume the old connection's in-memory history is available.&lt;/p&gt;

&lt;p&gt;A slow deployment should not require every user to discover the reconnection policy through a frozen screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test a removal, not only an addition
&lt;/h2&gt;

&lt;p&gt;A useful scaling exercise removes an instance while traffic is active. It observes errors, latency, duplicate writes, session continuity, and long-lived connection recovery.&lt;/p&gt;

&lt;p&gt;Test mixed versions too. &lt;a href="https://ma-x.im/blog/full-stack-zero-downtime-migrations" rel="noopener noreferrer"&gt;Schema compatibility&lt;/a&gt; and old frontend bundles remain relevant while the load balancer serves both generations. Retain content-hashed assets long enough for active clients to finish or recover cleanly.&lt;/p&gt;

&lt;p&gt;These tests make capacity a statement about the whole service rather than a count of containers.&lt;/p&gt;

&lt;p&gt;I am comfortable with modest scale when the limits are known. I am less comfortable with an autoscaling policy whose only promise is that more processes will appear whenever something becomes slow.&lt;/p&gt;

&lt;p&gt;The shared database has not read that promise. It will keep accepting only the work it can actually perform.&lt;/p&gt;

&lt;p&gt;Next, the upcoming article on production observability looks at how to see these limits before an error report becomes the first measurement.&lt;/p&gt;

&lt;p&gt;When your replica count grows, which downstream quantity grows with it? I'd start a scaling review with that number, before choosing another autoscaling signal.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>scaling</category>
      <category>loadbalancing</category>
      <category>reliability</category>
    </item>
    <item>
      <title>Green Checks Only Cover What You Checked</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Sun, 11 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/green-checks-only-cover-what-you-checked-4n8c</link>
      <guid>https://dev.to/maximusft/green-checks-only-cover-what-you-checked-4n8c</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%2Fcfkd9hsppkxzhzjyr6y5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcfkd9hsppkxzhzjyr6y5.png" alt="Green Checks Only Cover What You Checked" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build passes. The tests pass. The dependency update is small.&lt;/p&gt;

&lt;p&gt;The integration check disagrees.&lt;/p&gt;

&lt;p&gt;I do not find that especially surprising. A local check and an integration check can ask different questions about the same change. The awkward part begins when the agent treats the first green result as evidence for a larger conclusion than the check supports.&lt;/p&gt;

&lt;p&gt;In The Work Around the Agent Is Engineering Work, I described the work around an agent as part of the engineering itself. One useful responsibility in that work is keeping the scope of evidence visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fictional contract makes the distinction easier to see
&lt;/h2&gt;

&lt;p&gt;The following is an illustrative composite. Names, fields and implementation details are invented; it is not a reconstruction of an identifiable system or an internal contract.&lt;/p&gt;

&lt;p&gt;A booking service consumes a delivery window from a planning service. The contract previously used an ISO timestamp. An updated client expects an integer timestamp in milliseconds.&lt;/p&gt;

&lt;p&gt;The booking service's local fixture is updated too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DeliveryWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;startsAtMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DeliveryWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;startsAtMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_800_000_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler accepts the fixture. The local tests confirm that the booking code handles that fixture correctly.&lt;/p&gt;

&lt;p&gt;Neither observation tells us which representation the deployed planning service actually returns. If it still returns the previous shape, the local result is not wrong. It is simply narrower than "these services remain compatible."&lt;/p&gt;

&lt;p&gt;This is one reason I would not call local validation a miniature version of the whole production system. Its exclusions are often exactly what lets it run quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence has a scope and a revision
&lt;/h2&gt;

&lt;p&gt;For each check, ask what it exercised and which code it observed.&lt;/p&gt;

&lt;p&gt;A test against a mock exercises the mock contract. A test against a generated client exercises the declaration and the path using it. An integration gate may inspect a combined contract or contact a real environment. A package's exported type can differ from its runtime behavior or from what another participant still expects.&lt;/p&gt;

&lt;p&gt;The checks have different value. They do not automatically inherit each other's coverage.&lt;/p&gt;

&lt;p&gt;I would keep a small evidence record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check: booking service unit tests
Observed revision: current task commit
Established: local handling of the declared delivery window
Not established: compatibility with the deployed planner

Check: shared integration contract gate
Observed inputs: declared participating revisions
Established: compatibility within that selected set
Not established: behavior of every deployed client

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a demand for a document after every test command. It is a way to make the distinction explicit when the check is being used to justify a consequential decision.&lt;/p&gt;

&lt;p&gt;A green integration result also needs an honest boundary. It can be based on a particular environment, selected revisions, or a contract model. It is stronger evidence for some questions, not proof of every runtime property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the package, not only its version label
&lt;/h2&gt;

&lt;p&gt;When a dependency change is involved, inspect what was installed: package metadata, declarations, runtime exports, and the relevant contract representation.&lt;/p&gt;

&lt;p&gt;A requested version in a manifest is not the full observation. The lockfile, registry artifact, workspace resolution and build output determine what code is actually used. A stale installation can make an agent diagnose a version that is not the one under test.&lt;/p&gt;

&lt;p&gt;This does not mean dumping the entire dependency tree into context. Start with the disputed boundary and follow the few inputs that decide it.&lt;/p&gt;

&lt;p&gt;I want the agent to compare evidence it can point to, rather than expand an explanation around a guessed package behavior. More confident prose does not resolve disagreement between an artifact and a declaration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Several repositories do not form one snapshot
&lt;/h2&gt;

&lt;p&gt;Giving an agent access to related repositories is helpful. It does not make their branches, local changes, and deployed versions coherent automatically.&lt;/p&gt;

&lt;p&gt;One repository may be on a current base. Another may have an old checkout. A third may contain a pending fix that already changed the intended migration path.&lt;/p&gt;

&lt;p&gt;Before reasoning across them, identify the revisions and the purpose of each source: current main, active task branch, proposed change, or deployed release. A locally visible implementation can be real without being the implementation production uses.&lt;/p&gt;

&lt;p&gt;Repository memory should help locate those questions, not answer them from an earlier session. The source of truth for current compatibility is the current relevant state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recheck the problem before repairing the diagnosis
&lt;/h2&gt;

&lt;p&gt;The composite continues. Further investigation finds a compatible change already delivered through another path. The original dependency update is now obsolete.&lt;/p&gt;

&lt;p&gt;There are two different next actions available: make the old proposal more elaborate, or stop pursuing it.&lt;/p&gt;

&lt;p&gt;An agent can be quite good at the first. It has a task, a branch and an explanation to complete. That momentum is useful when the task remains valid. It is not useful when the current system no longer needs the proposed work.&lt;/p&gt;

&lt;p&gt;The correct result can be closing the obsolete PR and recording why it was superseded. Do not describe that as delivering the other change. Do not rewrite the history so the incomplete initial diagnosis becomes a clean success.&lt;/p&gt;

&lt;p&gt;The useful outcome is a rejected unsuitable proposal and a better freshness check for the next task.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before asking whether the patch works, ask whether it is still the patch the system needs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is particularly valuable with agents because implementation is relatively easy to continue. Deciding not to continue still requires evidence and an accountable owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Correct the workflow at the missing boundary
&lt;/h2&gt;

&lt;p&gt;If the initial diagnosis relied on stale or incomplete sources, merely fixing the current diff leaves the same failure available next time.&lt;/p&gt;

&lt;p&gt;Move the relevant current-base or related-change check earlier. If a shared contract matters, make the integration gate part of the verification criteria. If the package contents were assumed, inspect the actual artifact before proposing a fix.&lt;/p&gt;

&lt;p&gt;Keep the correction proportional. One incident does not justify requiring every task to scan every repository. A small single-repository CSS change and a shared dependency migration do not need identical discovery work.&lt;/p&gt;

&lt;p&gt;The rule should describe the condition that makes the check useful: cross-service contracts, dependency behavior, version skew, or an active related change. Otherwise a lesson becomes another universal instruction the agent follows even when it has no bearing on the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate a failed assumption from a failed person
&lt;/h2&gt;

&lt;p&gt;An incomplete AI diagnosis deserves correction. It does not need a theatrical explanation about agents being incapable, nor a reassuring story in which the model secretly intended the right thing.&lt;/p&gt;

&lt;p&gt;Record the assumption, the contradicting evidence, the correction, and the remaining uncertainty. That is enough to learn from the task.&lt;/p&gt;

&lt;p&gt;It also gives credit accurately. A person may notice the stale base. CI may reject the shared contract. The agent may then help compare sources and prepare the explanation. Those contributions can all be real without being compressed into "AI solved it."&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep green useful by keeping it specific
&lt;/h2&gt;

&lt;p&gt;I want local checks to stay fast and valuable. Their usefulness does not depend on pretending they cover the whole system.&lt;/p&gt;

&lt;p&gt;A build confirms something about the selected sources and toolchain. A test confirms behavior under its chosen conditions. A related contract check adds another layer. Current-state investigation tells us whether the task itself still makes sense.&lt;/p&gt;

&lt;p&gt;The result is not certainty. It is a decision with evidence that matches its scope.&lt;/p&gt;

&lt;p&gt;I would rather close one well-explained obsolete proposal than merge an increasingly polished implementation of yesterday's requirement. There is less to show in the diff, but more of the system has been understood.&lt;/p&gt;

&lt;p&gt;The next article, The Command Succeeded. The Scope Changed., looks at another boundary green checks do not automatically cover: what automation changed after the initial edit.&lt;/p&gt;

&lt;p&gt;If a check in your workflow is routinely used to justify more than it tested, which claim gets attached to it? That gap is usually worth examining before adding another test suite.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>agenticengineering</category>
      <category>integration</category>
      <category>validation</category>
    </item>
    <item>
      <title>A Small AWS Deployment, With the Awkward Parts Included</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Sat, 10 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/a-small-aws-deployment-with-the-awkward-parts-included-gkc</link>
      <guid>https://dev.to/maximusft/a-small-aws-deployment-with-the-awkward-parts-included-gkc</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%2Fte3r6ec5o1wop21icojr.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fte3r6ec5o1wop21icojr.png" alt="A Small AWS Deployment, With the Awkward Parts Included" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A diagram with CloudFront, a load balancer, some containers, and a database is a reasonable start.&lt;/p&gt;

&lt;p&gt;It does not tell us whether the checkout page can cache someone else's order, whether the containers can download their image, or who is allowed to restore the database after a bad migration.&lt;/p&gt;

&lt;p&gt;Those details are where I would spend the second pass. The boxes are familiar enough. Their permissions and failure behavior deserve a little more attention.&lt;/p&gt;

&lt;p&gt;For this article, assume an illustrative React application with a Node backend, PostgreSQL, and a few background workers. This is a proposed deployment shape, not a claim about a system I have operated or a measured monthly bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each component a limited job
&lt;/h2&gt;

&lt;p&gt;One possible layout is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public DNS -&amp;gt; CloudFront
                -&amp;gt; static assets in S3
                -&amp;gt; application routes through ALB
                     -&amp;gt; ECS/Fargate application tasks
                          -&amp;gt; RDS PostgreSQL
                          -&amp;gt; optional ElastiCache

queue -&amp;gt; separate worker tasks

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CloudFront is the public edge. ALB distributes application traffic. ECS manages tasks; Fargate avoids operating the underlying servers directly. RDS runs the database. Redis is optional and should have the &lt;a href="https://ma-x.im/blog/full-stack-redis-without-magic" rel="noopener noreferrer"&gt;explicit job&lt;/a&gt; we discussed earlier.&lt;/p&gt;

&lt;p&gt;I would not add Redis simply to complete the diagram, or Kubernetes simply to make the deployment feel serious. A managed application platform may also be sufficient. The point of this layout is understanding responsibility, not demonstrating the largest collection of AWS abbreviations.&lt;/p&gt;

&lt;h2&gt;
  
  
  A cache policy is part of authorization safety
&lt;/h2&gt;

&lt;p&gt;Static, content-hashed assets are good candidates for long-lived caching. A signed-in customer's order page is not the same kind of object.&lt;/p&gt;

&lt;p&gt;CloudFront distinguishes which values form the cache key from which values are forwarded to the origin. Sending a session cookie to the backend does not, by itself, guarantee responses are isolated correctly in the cache.&lt;/p&gt;

&lt;p&gt;For private application responses, start with caching disabled and explicitly configure authentication forwarding. For public cacheable responses, include the dimensions that actually change the representation. Test with two separate users, not twice with the same session.&lt;/p&gt;

&lt;p&gt;There is a particularly useful detail in the &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesCacheBehavior.html" rel="noopener noreferrer"&gt;CloudFront cache behavior documentation&lt;/a&gt;: a minimum TTL above zero can force caching even when the origin sends &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;no-store&lt;/code&gt;, or &lt;code&gt;no-cache&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is not a theoretical distinction. The application and infrastructure can each look reasonable in isolation while their combined policy is wrong.&lt;/p&gt;

&lt;p&gt;Path-pattern ordering matters too. A broad public behavior matching before a narrower protected behavior can apply the wrong rule. I would review edge configuration like application code, including tests for authenticated and unauthenticated variants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Private does not mean disconnected
&lt;/h2&gt;

&lt;p&gt;Application tasks and databases should not be needlessly reachable from the public internet. But tasks still need outbound paths: pull images, obtain secrets, write logs, and contact payment or email providers.&lt;/p&gt;

&lt;p&gt;Putting a task in a private subnet without arranging those paths produces a deployment that cannot start or cannot finish its normal work.&lt;/p&gt;

&lt;p&gt;NAT provides general outbound connectivity. VPC endpoints can provide private access to supported AWS services. They have different setup, availability, and cost implications; neither is a universal instruction to copy without checking the task's actual dependencies.&lt;/p&gt;

&lt;p&gt;For a small deployment, NAT, load balancers, logs, and minimum database capacity can be a meaningful part of the bill even when application traffic is low. I would estimate those standing costs before optimizing the price of one container.&lt;/p&gt;

&lt;p&gt;Do not publish the database merely because it makes a first connectivity test easier. Use a controlled administrative path and keep the production network model intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security groups express specific relationships
&lt;/h2&gt;

&lt;p&gt;Rather than allowing the whole subnet to reach every component, define who needs to talk to whom.&lt;/p&gt;

&lt;p&gt;The application's security group can accept traffic from the ALB group on the application port. The database can accept its database port from the application and worker groups that need it. Other callers do not acquire access simply by sharing a VPC.&lt;/p&gt;

&lt;p&gt;Also consider origin bypass. If clients can call the public ALB directly, they may bypass restrictions applied only at CloudFront. Depending on the design, use a supported private-origin arrangement or restrict the public origin with appropriate network and request controls. The application must still enforce authentication and authorization itself.&lt;/p&gt;

&lt;p&gt;These controls compose. A hidden origin is not an authorization system, and an authenticated route is not a reason to leave every network port open.&lt;/p&gt;

&lt;h2&gt;
  
  
  The task has two different identities
&lt;/h2&gt;

&lt;p&gt;ECS distinguishes an execution role from a task role.&lt;/p&gt;

&lt;p&gt;The execution role supports platform work such as pulling images and delivering configured logs or secrets. The task role is the identity the application uses when calling AWS APIs.&lt;/p&gt;

&lt;p&gt;Giving the execution role permission to read an application bucket does not necessarily give the running code that access. Conversely, copying a broad deployment role into the task gives every application bug more authority than it needs.&lt;/p&gt;

&lt;p&gt;Keep the roles narrow and separate. Use workload credentials rather than embedding long-lived AWS keys in the image. When access fails, identify which role made the request before adding permissions until the error goes away.&lt;/p&gt;

&lt;p&gt;That last approach does work remarkably well at producing permissions nobody can later explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fargate tasks still need a resource budget
&lt;/h2&gt;

&lt;p&gt;Managed compute does not remove per-process connection pools or memory behavior. Two tasks with twenty PostgreSQL connections each are a different load from twenty tasks with the same setting.&lt;/p&gt;

&lt;p&gt;Deployment overlap counts too. New tasks start before old tasks drain. The database must tolerate that temporary peak, or the release can run out of connections while average CPU remains comfortable.&lt;/p&gt;

&lt;p&gt;RDS Proxy may help pool and manage connections, but it is not a cure for long transactions or unlimited concurrency. Application behavior still determines how long connections remain occupied.&lt;/p&gt;

&lt;p&gt;Set a maximum scale consistent with downstream capacity. Separate workers from HTTP tasks so increasing export throughput does not quietly change the web service's deployment and resource profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managed availability is not application continuity
&lt;/h2&gt;

&lt;p&gt;Multi-AZ database deployment can improve availability during infrastructure failure. A read replica addresses a different concern and may lag. Neither undoes an accidental deletion that the database correctly accepted.&lt;/p&gt;

&lt;p&gt;Redis failover also has semantics. If cached product descriptions disappear, the database can refill them. If sessions or coordination state disappear, the product consequence is different.&lt;/p&gt;

&lt;p&gt;I would name those outcomes before choosing service options. "Highly available" is a useful infrastructure property, but it does not mean an order can be repeated without duplication or that a replica provides the latest permission change.&lt;/p&gt;

&lt;p&gt;Backups and recovery get their own article, The Backup Exists. The Restore Still Needs Work. They belong in the initial infrastructure plan even if the first restore exercise comes later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy an artifact, not a moving tag
&lt;/h2&gt;

&lt;p&gt;A controlled release records an image digest, configuration revision, migration step, and deployment outcome. Infrastructure as code records the intended topology so another environment can reproduce it without reconstructing yesterday's dashboard clicks.&lt;/p&gt;

&lt;p&gt;Use an additive migration phase, deploy compatible tasks, observe health and business outcomes, then perform destructive cleanup in a later release. Give long-lived connections a drain policy and old browser assets a retention policy.&lt;/p&gt;

&lt;p&gt;A rollback should name which pieces return to their previous state. The database does not automatically move backwards because ECS deploys the previous image.&lt;/p&gt;

&lt;p&gt;Finally, add alarms with an owner: application error rate, latency, failed deployments, queue age, database saturation, and spend. Budgets are notifications unless explicit controls say otherwise; they are not a promise that AWS will stop the bill at an exact amount.&lt;/p&gt;

&lt;p&gt;I would rather deploy this modest layout with known limits than a more elaborate one nobody can safely change. The diagram can stay small. The operating agreement needs enough detail to survive the first inconvenient event.&lt;/p&gt;

&lt;p&gt;The next article examines &lt;a href="https://ma-x.im/blog/full-stack-load-balancing" rel="noopener noreferrer"&gt;load balancing and scaling&lt;/a&gt;, including why adding healthy replicas can make a shared database less healthy.&lt;/p&gt;

&lt;p&gt;When reviewing an AWS layout, which relationship takes the longest to explain: network access, IAM, cache policy, or recovery? That is usually a useful place for the next design conversation.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>aws</category>
      <category>deployment</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>The Work Around the Agent Is Engineering Work</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/the-work-around-the-agent-is-engineering-work-5f2p</link>
      <guid>https://dev.to/maximusft/the-work-around-the-agent-is-engineering-work-5f2p</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%2Fqi14g563vfpk0z5kahi4.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqi14g563vfpk0z5kahi4.png" alt="The Work Around the Agent Is Engineering Work" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A coding agent returns a plausible diff. The local tests pass. It has followed the requested format and written a sensible explanation.&lt;/p&gt;

&lt;p&gt;There is still a fairly ordinary question left: what does that evidence actually establish?&lt;/p&gt;

&lt;p&gt;Perhaps the tests cover only one service. Perhaps a hook added files after the diff was inspected. Perhaps another change already solved the problem, so the proposed update is now unnecessary. The output can be quite competent while the decision to ship it remains wrong.&lt;/p&gt;

&lt;p&gt;That is the part of working with agents that increasingly interests me. Not another way to phrase the request. The conditions around the request that make a result possible to check, continue, and sometimes reject.&lt;/p&gt;

&lt;p&gt;I have been designing and iteratively refining that environment as part of my engineering work. Repository instructions, connected tools, validation steps, review handling, and session handoffs became things to maintain rather than instructions to repeat in every conversation.&lt;/p&gt;

&lt;p&gt;I would describe this as agentic workflow engineering. It is still software engineering. The responsibilities have moved around a little; they have not disappeared.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diff is one artifact in a longer operation
&lt;/h2&gt;

&lt;p&gt;Here is a deliberately generalized composite, not a reconstruction of one identifiable project.&lt;/p&gt;

&lt;p&gt;Two services share a contract. An agent updates a dependency in one repository. The local build accepts the new types, and the tests confirm the behavior that repository knows about. A separate integration check finds that the other service still expects a different representation.&lt;/p&gt;

&lt;p&gt;The first diagnosis is incomplete. Before making another patch, the engineer checks the actual package contents, current contracts, base branch, and related changes. A compatible solution has already arrived through another change. Continuing the original update would now introduce a regression rather than finish the task.&lt;/p&gt;

&lt;p&gt;The useful result is to stop and close the obsolete proposal.&lt;/p&gt;

&lt;p&gt;There is no new feature to celebrate. There is a clearer account of the system and one unsuitable change that did not enter it. I think that is worth recognizing as an engineering outcome, without pretending it measures a productivity gain.&lt;/p&gt;

&lt;p&gt;The agent helped investigate. A person still had to decide what the evidence meant, correct the initial assumption, and change the workflow so freshness checks happened earlier next time.&lt;/p&gt;

&lt;h2&gt;
  
  
  My contribution is the operating arrangement
&lt;/h2&gt;

&lt;p&gt;There is an unhelpful choice in some descriptions of AI-assisted work: either the engineer wrote everything personally, or they merely asked a chatbot to do it.&lt;/p&gt;

&lt;p&gt;Neither explains what I am doing.&lt;/p&gt;

&lt;p&gt;My contribution includes defining the task, organizing access to relevant context, choosing constraints, examining decisions, interpreting failures, and refining the next attempt. The agent can inspect sources, propose changes, run checks, and prepare reviewable artifacts inside that arrangement.&lt;/p&gt;

&lt;p&gt;I do not need to claim manual authorship of every generated line to own those engineering decisions. Equally, a generated implementation does not make the environment around it automatically good.&lt;/p&gt;

&lt;p&gt;I have integrated existing tools rather than built every tool involved. MCP connections help bring requirements and documentation into reach. Git, CLI/API access, tests, type checks, builds, and browser verification contribute different kinds of evidence. Each needs a clear reason to participate in the task.&lt;/p&gt;

&lt;p&gt;The distinction matters when describing the work: integration, configuration, development, evaluation, and adoption are separate claims. I would rather use the smaller accurate verb than let a convenient headline imply the larger one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context needs authority and a lifetime
&lt;/h2&gt;

&lt;p&gt;Giving an agent more text is not necessarily giving it better context.&lt;/p&gt;

&lt;p&gt;Personal working preferences, shared engineering standards, repository rules, and task requirements answer different questions. A general suggestion should not override the API contract in the current code. A remembered convention should not defeat a test result observed now.&lt;/p&gt;

&lt;p&gt;I use saved context to reduce repeated explanation and support continuation. I still expect the agent to verify current sources. Memory can become stale, and instructions can preserve a decision after the reason for it has changed.&lt;/p&gt;

&lt;p&gt;For an active task, a compact continuation record might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal: accept the new response shape without changing existing callers
Current observation: one caller still consumes the previous field
Decision: retain the compatibility adapter for this release
Verified: caller inventory and focused adapter tests
Unverified: downstream deployment sequence
Next step: confirm the rollout contract before removal

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an illustrative record, not an internal artifact. It separates observations, decisions, checks, and uncertainty. A new session can challenge it against the repository instead of treating the summary as a complete memory of reality.&lt;/p&gt;

&lt;p&gt;I do not promise identical behavior across models or sessions. The more defensible promise is a documented place to resume and a way to notice when it no longer matches the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autonomy is partly a permissions problem
&lt;/h2&gt;

&lt;p&gt;Written boundaries are useful: which operations are allowed, when to ask, and what must not be disclosed. They are not enforcement by themselves.&lt;/p&gt;

&lt;p&gt;Tool credentials, available commands, environment isolation, branch protections, and executable gates also determine what can happen. A rule that says "do not release" is weaker than an environment where the agent cannot release without an accountable person's action.&lt;/p&gt;

&lt;p&gt;The design depends on the task. Low-risk investigation and focused checks can usually proceed without a sequence of tiny approvals. Business requirements, architectural commitments, sensitive actions, and release decisions need the appropriate owner.&lt;/p&gt;

&lt;p&gt;I want the agent to have enough room to work, not enough authority to settle every question it encounters.&lt;/p&gt;

&lt;p&gt;This also makes a stop meaningful. If acceptance criteria are unclear or current evidence contradicts the request, continuing to produce code is not necessarily progress. The next useful artifact may be a question or a bounded proposal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small change deserves a discriminating check
&lt;/h2&gt;

&lt;p&gt;Before the first edit, I ask the agent to locate the code that controls the behavior, state a local hypothesis, and choose a check that could disprove it.&lt;/p&gt;

&lt;p&gt;That is less impressive than a long repository survey, but often more useful. The goal is not to read every nearby file before acting. It is to know which assumption the next small edit will test.&lt;/p&gt;

&lt;p&gt;After that edit, run the focused check before expanding the change. If it fails, decide whether it exposed a local defect or showed that the hypothesis was wrong. Broader tests, lint, build, CI, and acceptance checks follow according to the risk and repository requirements.&lt;/p&gt;

&lt;p&gt;The focused check does not replace the broader gates. It keeps us from spending a large patch on an assumption we could have disproved cheaply.&lt;/p&gt;

&lt;p&gt;For a small, clear task, I do not need a specification document that repeats the ticket. For a risky or multi-session change, writing down assumptions and a plan before implementation can be valuable. The timing is part of the evidence: a plan written after the work cannot demonstrate that the work was specification-driven.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools have outputs that need their own review
&lt;/h2&gt;

&lt;p&gt;A command can succeed and still change more than the task authorized.&lt;/p&gt;

&lt;p&gt;Generators, package installation, hooks, formatting, and deployment tooling can all transform the artifact after the initial edit. The working diff we reviewed may not be the commit tree that a hook produced.&lt;/p&gt;

&lt;p&gt;I have used that kind of failure to refine the workflow: inspect the result after automation, separate unrelated generated drift, and verify what is actually being proposed.&lt;/p&gt;

&lt;p&gt;It is a fairly undramatic control. That is one of its useful qualities. It does not require the agent to recognize every possible reason a generator changed a file. It requires the scope of the result to be checked before it leaves the local operation.&lt;/p&gt;

&lt;p&gt;The next two articles, Green Checks Only Cover What You Checked and The Command Succeeded. The Scope Changed., examine those boundaries in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review is evidence attached to a changing object
&lt;/h2&gt;

&lt;p&gt;I have also developed personal PR-review tooling with AI assistance. The work includes tracking revisions, avoiding repeated unchanged findings, dry-run checks, and guarding actions against stale state.&lt;/p&gt;

&lt;p&gt;That is a statement about mechanisms I developed, not a claim that the tool is continuously operating today, deployed across a company, or safely replacing human approval.&lt;/p&gt;

&lt;p&gt;The engineering problem is interesting on its own. A finding can remain relevant while its line number changes. A new commit can remove the risk but leave an old comment. A review decision can become stale when the object it described changes.&lt;/p&gt;

&lt;p&gt;I want the automation to provide useful evidence without silently taking over accountability. A Review Belongs to a Commit follows that boundary, including the limitations of duplicate suppression and head checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improvements need careful attribution
&lt;/h2&gt;

&lt;p&gt;I participate in evaluating reusable agent skills against real engineering work. That does not make me the owner of an organization-wide transformation, and it does not establish that a particular framework caused a measured improvement.&lt;/p&gt;

&lt;p&gt;A successful task can depend on repository instructions, tool access, a well-chosen test, current domain knowledge, or a person's correction. A skill may contribute, add ceremony, or simply describe a practice already present.&lt;/p&gt;

&lt;p&gt;I try to keep those explanations apart. Record the outcome, corrections, residual risks, and what the available evidence can attribute. Unknown is a reasonable answer when the task does not support a stronger one.&lt;/p&gt;

&lt;p&gt;What a Skill Changed, and What It Didn't will make that distinction concrete without inventing comparative results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful specialization is not a new claim about the model
&lt;/h2&gt;

&lt;p&gt;This work does not mean I train models, conduct ML research, or operate production MLOps. It also does not mean role-based agent configurations have become reliable multi-agent execution simply because the definitions exist.&lt;/p&gt;

&lt;p&gt;It means I design the conditions in which coding agents participate in software delivery: context, tools, boundaries, checks, human decisions, and a way to learn from ordinary failures.&lt;/p&gt;

&lt;p&gt;My frontend and full-stack background is part of that, not something to replace with a new label. Interfaces, data ownership, service contracts, tests, and release behavior provide the questions against which generated output gets evaluated.&lt;/p&gt;

&lt;p&gt;The diff at the beginning can remain plausible. I still need to know what changed, what was checked, and who owns the unresolved decision. I am comfortable letting an agent do a substantial part of the work when those answers are available. I am less comfortable calling the work complete because the explanation sounds finished.&lt;/p&gt;

&lt;p&gt;If your agent workflow is reliable until one ordinary exception appears, tell me which assumption the exception exposed. That is usually a more useful starting point than another prompt template.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>agenticengineering</category>
      <category>developertooling</category>
      <category>engineeringworkflow</category>
    </item>
    <item>
      <title>Same Container Image, Different Application</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Thu, 08 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/same-container-image-different-application-1c9g</link>
      <guid>https://dev.to/maximusft/same-container-image-different-application-1c9g</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%2Fj1uun2y3jzzfmr2wq9ps.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj1uun2y3jzzfmr2wq9ps.png" alt="Same Container Image, Different Application" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image passed staging. Production starts the same digest with different environment variables.&lt;/p&gt;

&lt;p&gt;The browser still calls the staging API.&lt;/p&gt;

&lt;p&gt;There is no contradiction. The server received its configuration at startup. The browser bundle received its configuration earlier, during the build. "Same image" was true. "Same application, configured at runtime" was only partly true.&lt;/p&gt;

&lt;p&gt;I like building once and promoting an immutable artifact. It removes a whole class of uncertainty about what was tested. But that promise deserves a more careful definition than "we use Docker now."&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate the configuration clocks
&lt;/h2&gt;

&lt;p&gt;There are at least three moments when configuration can become fixed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build time, when the artifact is produced;&lt;/li&gt;
&lt;li&gt;process startup, when the runtime initializes;&lt;/li&gt;
&lt;li&gt;request time, when a value is consulted again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A public frontend environment variable may be substituted into JavaScript during the build. Changing the container environment does not rewrite the compiled bytes. Next.js documents this behavior for &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; values; Vite's &lt;code&gt;VITE_&lt;/code&gt; values have a similar public-build role.&lt;/p&gt;

&lt;p&gt;For a browser API address, I would first consider same-origin paths such as &lt;code&gt;/api&lt;/code&gt;. The proxy selects the environment-specific backend without putting that address into the bundle.&lt;/p&gt;

&lt;p&gt;If the browser truly needs runtime settings, publish a small, explicitly public configuration resource or inject them into the initial response. Validate it and decide its cache behavior. No secret becomes safe because the file is named &lt;code&gt;runtime-config.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This also creates compatibility work: an old bundle may read new settings. Keep the public configuration schema additive, and record which artifact and configuration revision were deployed together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables do not form a typed contract
&lt;/h2&gt;

&lt;p&gt;The process can start with &lt;code&gt;ORDER_TIMEOUT_MS=ten&lt;/code&gt;. It can also start with a missing variable that quietly activates a development default.&lt;/p&gt;

&lt;p&gt;I would rather reject an invalid production configuration before the instance receives traffic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RuntimeConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;ORDER_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;ENABLE_EXPORTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RuntimeConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exportsEnabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENABLE_EXPORTS&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values are illustrative, not recommended timeouts. Notice the boolean handling: the string &lt;code&gt;'false'&lt;/code&gt; is truthy in JavaScript. A generic truthiness conversion is not a configuration parser.&lt;/p&gt;

&lt;p&gt;Errors should identify the invalid setting without dumping every environment value into logs. Validation is useful; printing a database password beside the validation failure is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secret mounts solve one part of the problem
&lt;/h2&gt;

&lt;p&gt;Builds sometimes need credentials to download private dependencies. Passing them through Docker build arguments or environment instructions can leave them in image metadata or layers. Deleting a file in a later layer does not remove it from the earlier layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/build/building/secrets/" rel="noopener noreferrer"&gt;BuildKit secret mounts&lt;/a&gt; expose a credential to one build step without intentionally baking it into the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret,id&lt;span class="o"&gt;=&lt;/span&gt;npmrc,target&lt;span class="o"&gt;=&lt;/span&gt;/root/.npmrc &lt;span class="se"&gt;\
&lt;/span&gt;    npm ci

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That does not prevent the invoked tool from copying the credential into output or printing it. The mount is a delivery mechanism, not a guarantee about everything executed in that step.&lt;/p&gt;

&lt;p&gt;Runtime secrets have a different lifecycle. An environment-injected database password usually stays unchanged in the process until it restarts. A mounted secret file may update while the application still holds the old value in memory. A secrets service can rotate credentials while existing database connections continue to work and new connections fail.&lt;/p&gt;

&lt;p&gt;Rotation therefore includes application behavior: refresh or restart, connection-pool replacement, overlap between old and new credentials, and rollback. A secret manager can store the next password. It cannot decide when your client library rereads it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin the artifact you mean to deploy
&lt;/h2&gt;

&lt;p&gt;An image tag is a name. A digest identifies particular content.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;checkout:production&lt;/code&gt; is overwritten while deployment is in progress, instances pulling at different moments can receive different bytes under the same tag. It is possible to build safeguards around tags, but deploying a recorded digest gives the release a less ambiguous identity.&lt;/p&gt;

&lt;p&gt;Record the source revision, image digest, configuration revision, and migration state. That is enough to explain considerably more than "version 18 is running."&lt;/p&gt;

&lt;p&gt;Architecture matters too. A locally built image for one CPU architecture is not automatically a usable artifact on another. Multi-platform builds help, but native dependencies still need testing in the runtime actually deployed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A container does not make local files durable
&lt;/h2&gt;

&lt;p&gt;A generated invoice written into the container filesystem belongs to that instance. The next request may land elsewhere, and the next deployment may remove it entirely.&lt;/p&gt;

&lt;p&gt;Use the local filesystem for temporary work with a known lifetime. Put durable exports, uploads, and receipts in deliberately managed storage. Return an object identifier rather than a path inside the process that happened to create the file.&lt;/p&gt;

&lt;p&gt;The same distinction applies to caches. A local cache is useful if losing it is safe and other instances can tolerate different entries. A shared product truth should not accidentally live in whichever container first computed it.&lt;/p&gt;

&lt;p&gt;Read-only root filesystems and non-root execution can make accidental persistence and unnecessary privileges harder. They also expose implicit assumptions in libraries that want to write temporary files. Test the constrained runtime, not just the permissive development container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resource limits change behavior before a process dies
&lt;/h2&gt;

&lt;p&gt;CPU throttling can stretch an ordinary request past its timeout without high host CPU usage. Memory limits can kill a process while the host still has plenty of RAM. Event-loop delay may explain latency that database timing does not.&lt;/p&gt;

&lt;p&gt;I would set concurrency and heap behavior with the container's actual limits in mind. More parallel promises are not always more throughput.&lt;/p&gt;

&lt;p&gt;The database pool deserves particular attention. A pool of twenty connections seems modest until twelve replicas each create one. During a rolling deployment, old and new replicas overlap, and the peak connection count can be larger than the steady-state count.&lt;/p&gt;

&lt;p&gt;We will examine that budget in the scaling article. For now, the useful habit is to treat per-process settings as quantities that multiply when the scheduler adds processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not let every replica migrate the database
&lt;/h2&gt;

&lt;p&gt;Running migrations in the application's startup command is convenient for one instance. Start ten instances and you have ten potential migration runners, possibly while the old application still serves traffic.&lt;/p&gt;

&lt;p&gt;Use a controlled release step with explicit migration ownership, lock behavior, retry policy, and compatibility gates. Database tools may provide advisory locking; that still does not make a destructive change compatible with the old deployment.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ma-x.im/blog/full-stack-zero-downtime-migrations" rel="noopener noreferrer"&gt;expand/contract approach&lt;/a&gt; belongs to the release sequence, not merely to the SQL file.&lt;/p&gt;

&lt;p&gt;Startup and readiness also need separate meanings. The process may be alive while warming caches or preparing required resources. Conversely, restarting every replica because one shared dependency is briefly unavailable can add more load to that dependency.&lt;/p&gt;

&lt;p&gt;Health checks should support the failure response we want, rather than giving every unpleasant condition the same instruction: restart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test shutdown as carefully as startup
&lt;/h2&gt;

&lt;p&gt;A container usually gets a termination signal and a finite grace period. If the process ignores the signal or an intermediate shell fails to forward it correctly, deployment ends by force-killing work.&lt;/p&gt;

&lt;p&gt;Use a process arrangement that forwards signals. Stop accepting new work, allow in-flight requests to finish within a bound, and let queue workers acknowledge only completed jobs. Design what happens after the deadline too; the platform will not wait indefinitely because an export is nearly done.&lt;/p&gt;

&lt;p&gt;An immutable image is useful precisely because it narrows uncertainty. It does not remove configuration, storage, or process lifecycle from the design. I would keep the artifact fixed and make those moving parts explicit enough to reproduce.&lt;/p&gt;

&lt;p&gt;Next, a practical AWS deployment puts these decisions into a concrete infrastructure layout, without treating every available service as a requirement.&lt;/p&gt;

&lt;p&gt;Which setting in your application changes at a different time than people assume? I'd be interested in the small configuration detail that made an otherwise sound release behave differently.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>docker</category>
      <category>configuration</category>
      <category>deployment</category>
    </item>
    <item>
      <title>The Domain Moved. Some Requests Did Not.</title>
      <dc:creator>Maksym Kuzmitskyi (MaximusFT)</dc:creator>
      <pubDate>Tue, 06 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/maximusft/the-domain-moved-some-requests-did-not-1dg0</link>
      <guid>https://dev.to/maximusft/the-domain-moved-some-requests-did-not-1dg0</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%2Fcl2egm1avyamervphkn3.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcl2egm1avyamervphkn3.png" alt="The Domain Moved. Some Requests Did Not." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new domain works on your laptop. The certificate is valid. The application responds.&lt;/p&gt;

&lt;p&gt;Someone else is still reaching the old server.&lt;/p&gt;

&lt;p&gt;There is usually nothing particularly mysterious about this. The system has several caches, several connections, and several ideas about what "the address" means. They do not update together because we changed a record in a dashboard.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://ma-x.im/blog/full-stack-after-fetch" rel="noopener noreferrer"&gt;first part of this guide&lt;/a&gt;, I followed a request from the browser into the backend. Here I want to stay at the entrance, where fairly small configuration changes can leave an application working for one group of users and quietly wrong for another.&lt;/p&gt;

&lt;h2&gt;
  
  
  A DNS change has a transition period
&lt;/h2&gt;

&lt;p&gt;Lowering a record's TTL immediately before changing its value does not shorten answers already cached under the previous TTL. A resolver that cached an hour-long answer ten minutes ago can keep it for the remaining fifty minutes.&lt;/p&gt;

&lt;p&gt;I would lower the TTL ahead of a planned cutover, wait for the old lifetime to pass, and keep both destinations usable during the move. DNS TTL is a cache instruction, not a synchronized release mechanism.&lt;/p&gt;

&lt;p&gt;There is another easy-to-miss cache: the absence of a record. If someone queried a hostname before it existed, their resolver may retain a negative answer. Creating the record does not necessarily make that user able to resolve it immediately.&lt;/p&gt;

&lt;p&gt;Existing HTTP connections can also outlive a DNS update. A client does not need to resolve the name again for every request on an already-open connection.&lt;/p&gt;

&lt;p&gt;None of this is a reason to avoid DNS cutovers. It is a reason not to delete the old destination the moment your own lookup looks correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check both address families
&lt;/h2&gt;

&lt;p&gt;A hostname can publish both an A record for IPv4 and an AAAA record for IPv6.&lt;/p&gt;

&lt;p&gt;If the IPv4 route is healthy while IPv6 reaches an old endpoint, the result may depend on the user's network. Browsers have strategies for choosing between address families, but those strategies cannot turn a wrong AAAA record into the right infrastructure.&lt;/p&gt;

&lt;p&gt;The symptom is frustratingly ordinary: "It works here."&lt;/p&gt;

&lt;p&gt;These are diagnostic commands, not a deployment script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short A api.shop.example
dig +short AAAA api.shop.example
curl &lt;span class="nt"&gt;-4&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; https://api.shop.example/health
curl &lt;span class="nt"&gt;-6&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt; https://api.shop.example/health

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last command requires a working IPv6 path from the machine running it. Failure there is evidence to interpret, not automatic proof that the server is broken.&lt;/p&gt;

&lt;p&gt;I would also inspect the authoritative records and compare them with the resolver used by an affected client. "Propagation" is often used as a name for any uncertainty around DNS. It is more useful to identify which answer is cached where.&lt;/p&gt;

&lt;h2&gt;
  
  
  The certificate belongs to a connection, not a diagram
&lt;/h2&gt;

&lt;p&gt;With a CDN in front of a load balancer, there may be two TLS connections: browser to CDN, and CDN to origin. Each has its own certificate validation and hostname expectations.&lt;/p&gt;

&lt;p&gt;A valid browser-facing certificate says nothing about whether the CDN can validate the origin certificate. The origin address, TLS server name, certificate names, and HTTP Host header have related but distinct jobs.&lt;/p&gt;

&lt;p&gt;Suppose the origin certificate covers &lt;code&gt;origin.shop.example&lt;/code&gt;, while the CDN connects using a load balancer's generated hostname. Depending on the configured origin behavior, verification can fail before the application sees a request.&lt;/p&gt;

&lt;p&gt;I would debug the two connections separately rather than temporarily disable origin verification. The latter makes the immediate error disappear by removing the property we were trying to establish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Renewal is the configuration test that arrives later
&lt;/h2&gt;

&lt;p&gt;A certificate issued successfully today still needs an automated renewal path.&lt;/p&gt;

&lt;p&gt;An HTTP-01 challenge requires the validation resource to be reachable through the public route. Add authentication, a new redirect, or a different proxy rule later, and renewal may fail while ordinary application requests continue working.&lt;/p&gt;

&lt;p&gt;DNS-01 avoids that HTTP path and supports wildcard certificates, but introduces credentials and DNS update behavior into the renewal system. Give the renewal process narrowly scoped access rather than the registrar's unrestricted credentials. Challenge delegation can help separate that responsibility.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://letsencrypt.org/docs/challenge-types/" rel="noopener noreferrer"&gt;Let's Encrypt challenge documentation&lt;/a&gt; explains these trade-offs. A wildcard for &lt;code&gt;*.shop.example&lt;/code&gt; also does not cover the apex &lt;code&gt;shop.example&lt;/code&gt;; certificate names deserve the same explicit review as routing rules.&lt;/p&gt;

&lt;p&gt;I would monitor expiry from outside the application and exercise renewal before the certificate becomes urgent. A calendar reminder is not quite the automation people usually mean when they say HTTPS is handled.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proxy changes what the application believes
&lt;/h2&gt;

&lt;p&gt;Behind TLS termination, the application may receive plain HTTP from the load balancer. Without trusted forwarding information, it can generate HTTP callback URLs, fail to set secure cookies, or redirect a request that is already HTTPS into a loop.&lt;/p&gt;

&lt;p&gt;Forwarded protocol, host, and client-address headers provide that context. They are not trustworthy merely because they have conventional names.&lt;/p&gt;

&lt;p&gt;An internet client can supply &lt;code&gt;X-Forwarded-For&lt;/code&gt; too. The proxy must remove or normalize incoming values according to the topology, and the application must trust only the known proxy path. Blindly trusting every hop makes client-IP rate limits and audit records easier to mislead.&lt;/p&gt;

&lt;p&gt;For password-reset and OAuth URLs, I prefer a configured, validated public origin rather than constructing an absolute URL from an arbitrary Host header. It is less flexible. That is sometimes the point.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Public address, transport address, and trusted request context are separate configuration decisions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Moving the hostname can change authentication
&lt;/h2&gt;

&lt;p&gt;A host-only cookie for &lt;code&gt;shop.example&lt;/code&gt; is not sent to &lt;code&gt;api.shop.example&lt;/code&gt;. A cookie scoped to the parent domain has a broader reach, which can be undesirable if another subdomain is less trusted.&lt;/p&gt;

&lt;p&gt;Also, two subdomains can be same-site while still being different origins. SameSite cookie rules and CORS answer different questions. Cross-origin browser requests still need the right credential mode and CORS response; a credentialed response cannot use a wildcard allowed origin.&lt;/p&gt;

&lt;p&gt;The distinction becomes visible after a seemingly harmless move from &lt;code&gt;/api&lt;/code&gt; on the main origin to a separate API hostname. Authentication, preflight requests, callback allowlists, and browser storage behavior may all change.&lt;/p&gt;

&lt;p&gt;I would test an existing session, not just a fresh login. I would test logout too. Deleting a cookie with the wrong path or domain can leave the original cookie present, which is a fairly unhelpful way to discover how cookie scope works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve request semantics through redirects
&lt;/h2&gt;

&lt;p&gt;A canonical-domain redirect is fine for a public page. Applying the same rule indiscriminately to API writes is less comfortable.&lt;/p&gt;

&lt;p&gt;Some redirect statuses can lead clients to change a POST into a GET. Others preserve the method and body. Even a method-preserving redirect can encounter credential and origin rules that an ordinary page navigation does not.&lt;/p&gt;

&lt;p&gt;For a moved API, I would keep the old route compatible during the transition rather than expect every client to follow a redirect correctly. The client might be a browser tab, an SDK, or a webhook sender that cannot be upgraded today.&lt;/p&gt;

&lt;p&gt;Permanent redirects can be cached too. A rollback of DNS or application code does not necessarily rewind the redirect already stored by a client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test an address change as a release
&lt;/h2&gt;

&lt;p&gt;A useful cutover check includes more than a homepage returning 200: authenticated reads, writes, OAuth callbacks, uploads, streaming responses, certificate renewal, and the old endpoint during overlap.&lt;/p&gt;

&lt;p&gt;Proxy buffering is worth checking if the application streams. A server can emit chunks correctly while a proxy collects them and sends everything at the end. The request technically works; the intended latency behavior does not.&lt;/p&gt;

&lt;p&gt;I would keep the old endpoint alive until observed traffic has moved, then remove it deliberately. The decision comes from request logs and compatibility requirements, not the moment the DNS control panel says the record was saved.&lt;/p&gt;

&lt;p&gt;The domain is a small part of the application, but it has a long memory. Caches, cookies, certificates, and old clients all remember slightly different versions of it. A good move gives those memories time to become harmless.&lt;/p&gt;

&lt;p&gt;Next comes &lt;a href="https://ma-x.im/blog/full-stack-container-configuration" rel="noopener noreferrer"&gt;container and environment configuration&lt;/a&gt;, where the application can have the right address and still be running the wrong settings.&lt;/p&gt;

&lt;p&gt;If a domain move left one awkward client behind, I'd be interested in which layer retained the old assumption. Those details are more useful than another checklist that stops at a green padlock.&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>dns</category>
      <category>https</category>
      <category>infrastructure</category>
    </item>
  </channel>
</rss>
