<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[AI Forefather's Dev Notes]]></title><description><![CDATA[AI Forefather's Dev Notes]]></description><link>https://xylemnode.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>AI Forefather&apos;s Dev Notes</title><link>https://xylemnode.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 24 Sep 2026 15:31:10 GMT</lastBuildDate><atom:link href="https://xylemnode.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A coding agent changed your Spring Boot service. What behavior changed with it?]]></title><description><![CDATA[A small change to a Spring Boot project can produce a surprisingly tidy patch. The agent extracts a service method, replaces a response object, removes some repeated exception handling, and reports th]]></description><link>https://xylemnode.hashnode.dev/a-coding-agent-changed-your-spring-boot-service-what-behavior-changed-with-it</link><guid isPermaLink="true">https://xylemnode.hashnode.dev/a-coding-agent-changed-your-spring-boot-service-what-behavior-changed-with-it</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Testing]]></category><category><![CDATA[ai agents]]></category><dc:creator><![CDATA[AI Forefather]]></dc:creator><pubDate>Thu, 17 Sep 2026 02:55:29 GMT</pubDate><content:encoded><![CDATA[<p>A small change to a Spring Boot project can produce a surprisingly tidy patch. The agent extracts a service method, replaces a response object, removes some repeated exception handling, and reports that the build passes.</p>
<p>Before merging, I would still want to know what happens to the requests the application already receives.</p>
<p>Does an invalid value still get rejected? Does a missing record produce the same response? If the second database write fails, does the first one remain?</p>
<p>Those details are easy to overlook when the diff looks like routine cleanup. Here is how I would give a coding agent enough context to preserve them, and ask for evidence that the change actually does.</p>
<h2>Give the agent a behavior baseline</h2>
<p>“Keep the existing behavior” is a useful intention, but a weak specification. Start by identifying what callers and stored data depend on.</p>
<p>For the part of the service being changed, a short table is often enough:</p>
<table>
<thead>
<tr>
<th>Situation</th>
<th>What to establish before editing</th>
</tr>
</thead>
<tbody><tr>
<td>Valid request</td>
<td>Accepted input, response fields, status code, and expected writes</td>
</tr>
<tr>
<td>Invalid or missing input</td>
<td>Which values are rejected and how the error is represented</td>
</tr>
<tr>
<td>Missing resource or business conflict</td>
<td>Existing exception mapping and response shape</td>
</tr>
<tr>
<td>Unauthenticated or unauthorized request</td>
<td>Existing access checks and observable response</td>
</tr>
<tr>
<td>Failure partway through an operation</td>
<td>Which changes should remain and which should roll back</td>
</tr>
</tbody></table>
<p>Build this from the current implementation, tests, API documentation, and intended requirements. An existing bug is something to fix deliberately; it should not become a permanent requirement just because it already exists.</p>
<p>I would ask the agent to follow one relevant request from the controller through its request object, service, exception handlers, and repository calls. That gives “preserve behavior” a concrete meaning.</p>
<p>Have it read the project's Spring Boot version and configuration too. Advice for a different version, or a different validation setup, can lead to unnecessary dependency changes before the actual task even starts.</p>
<h2>Follow validation through the request path</h2>
<p>An annotation on a request class deserves a request-level check.</p>
<p>For example, adding a constraint to a DTO does not by itself prove that incoming HTTP requests are being validated as expected. Check the relevant controller signature, validation setup, and the handling of validation failures. Spring's <a href="https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-validation.html">MVC validation documentation</a> describes the argument and method validation paths.</p>
<p>A test that constructs the DTO and calls a service directly can be useful, but it does not exercise MVC binding and validation.</p>
<p>Ask the agent to send representative valid and invalid requests through the configured web layer. Check both the status and the error body fields that clients rely on. Missing, empty, and malformed values may follow different paths; choose the ones the endpoint actually needs to distinguish.</p>
<p>This is also where a convenient exception-handling change can have surprising effects. Moving errors into a broad catch block may turn an established client error into a generic response. Look at the existing controller advice before introducing another response format.</p>
<p>The useful review question is straightforward: what would an existing client observe after this patch?</p>
<h2>Review the transaction call path after a refactor</h2>
<p>This is one place where reading annotations alone is misleading.</p>
<p>Suppose an agent extracts database work into a method marked <code>@Transactional</code>, then calls it through <code>this.saveChanges()</code> from another method in the same class.</p>
<p>With Spring's default proxy-based transaction mode, that internal call does not pass through the proxy. The called method's transaction settings are therefore not applied through that invocation. Spring documents this in its <a href="https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/annotations.html">transaction annotation reference</a>.</p>
<p>That does not necessarily mean no transaction exists. An outer transaction may already be active. The point is that the newly annotated method does not automatically establish the boundary its author may expect.</p>
<p>Ask the agent to trace the actual entry point and identify where transaction interception happens. Depending on the intended boundary, the appropriate change might be to keep the transaction on the externally invoked service method or move the operation into a separate injected bean. Adding more annotations without examining the call path leaves the question unanswered.</p>
<p>Exception changes deserve the same attention. Under Spring's standard default rollback rules, <code>RuntimeException</code> and <code>Error</code> trigger rollback, while checked exceptions generally do not. Applications can override those rules, including through method-level settings and, in supported versions, global defaults. Read the project's actual policy before drawing a conclusion. The <a href="https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/rolling-back.html">rollback documentation</a> explains the defaults and overrides.</p>
<p>If the agent catches an exception inside a transactional operation and returns normally, review the consequence as well. It changes what the transaction interceptor sees, although another participant may already have marked the transaction rollback-only.</p>
<p>A cleaner exception hierarchy is welcome. Its effect on stored data still needs checking.</p>
<h2>Match each check to the behavior it can prove</h2>
<p>A mocked repository can help test a service's decisions. It cannot establish what a real transaction manager commits or rolls back.</p>
<p>For a change affecting rollback, exercise the real Spring-managed service with a configured transaction manager and an isolated test database. Trigger a failure after the first write, let the service invocation finish, and inspect the resulting database state outside the transaction being checked. With JPA, flush when needed to ensure the relevant SQL actually executes before the induced failure.</p>
<p>Take care with an outer <code>@Transactional</code> test. The test's own transaction can supply a boundary that is absent in production, and its automatic rollback can hide an unintended commit. For a test specifically about service transaction boundaries, avoid letting a test-managed transaction provide that boundary. Spring's <a href="https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/tx.html">transactional testing documentation</a> explains how test-managed transactions work.</p>
<p>Use a database and configuration representative of the behavior under test. Passing against an in-memory database does not automatically establish production-specific locking or isolation behavior.</p>
<p>For HTTP behavior, exercise the configured MVC path. For access control, include the relevant security configuration. Keep fast unit tests for local logic; add integration coverage where the change crosses framework or persistence boundaries.</p>
<p>The final report should say which request or failure was exercised and what happened. If the database or required environment was unavailable, that remains an unverified item.</p>
<h2>Keep long editing sessions attached to their evidence</h2>
<p>Following a request through a Spring project often takes several rounds: inspect the controller, trace the service, check configuration, change code, and run the relevant tests.</p>
<p>That makes continuity useful. Keep a short record of the behavior being preserved, the files changed, and the checks already completed. If a session stops, the next step should follow that evidence.</p>
<p>The model connection is another part of this workflow. At XylemNode, our <a href="https://xylemnode.com/en#home-auto-title">Auto group</a> evaluates channel health when selecting a request path and supports retries across groups when a channel fails, while the caller keeps the same model name. For coding agents that support custom model services, this is intended to reduce manual connection switching during a multi-step task.</p>
<p>The connection belongs to the coding agent helping with the Spring Boot project. The application's own transaction management remains separate. Request recovery cannot establish that a database write rolled back or that a test completed; those answers still come from execution records and observed results.</p>
<h2>Ask for a change you can account for</h2>
<p>A task brief can stay short:</p>
<blockquote>
<p>Identify the current request, error, access-control, and transaction behavior relevant to this change. State which behavior the requirement intentionally changes. Keep unrelated behavior stable, and verify the affected paths at the appropriate level. Report the checks actually run, their results, and anything still unverified.</p>
</blockquote>
<p>That gives the agent room to make useful implementation decisions while making the result easier to review.</p>
<p>What I want back is a patch whose effects I can explain: which inputs it accepts, what clients receive, and what happens to the data when something fails. That gives the reviewer a concrete basis for deciding whether the change is ready to merge.</p>
]]></content:encoded></item><item><title><![CDATA[Your coding agent wrote a Python tool. What happens on the second run?]]></title><description><![CDATA[The first run of a Python tool written by a coding agent can feel satisfying. The dependencies are installed, the command finishes, and the output files appear. Whether it organizes files, converts da]]></description><link>https://xylemnode.hashnode.dev/your-coding-agent-wrote-a-python-tool-what-happens-on-the-second-run</link><guid isPermaLink="true">https://xylemnode.hashnode.dev/your-coding-agent-wrote-a-python-tool-what-happens-on-the-second-run</guid><category><![CDATA[Python]]></category><category><![CDATA[Testing]]></category><category><![CDATA[ai agents]]></category><dc:creator><![CDATA[AI Forefather]]></dc:creator><pubDate>Thu, 17 Sep 2026 02:42:45 GMT</pubDate><content:encoded><![CDATA[<p>The first run of a Python tool written by a coding agent can feel satisfying. The dependencies are installed, the command finishes, and the output files appear. Whether it organizes files, converts data, or generates reports, it seems to do the job.</p>
<p>There is another question worth asking: what happens if you run exactly the same command again?</p>
<p>Does it overwrite the previous results? Append the same data twice? Skip completed items and carry on with the rest?</p>
<p>“The command succeeded” does not answer any of those questions.</p>
<p>When handing an automation task to an agent, I like to include the second run in the requirements. It brings behavior into view that is easy to miss while getting the first run working.</p>
<h2>Decide what running it again should mean</h2>
<p>“Write a batch-processing script” sounds specific, but it still leaves the agent with several decisions.</p>
<p>If an output file already exists, should the script overwrite it, report a conflict, or choose another name? If one input is invalid, should the whole batch stop? If an input changes, can the previous result still be reused?</p>
<p>There is no single correct policy. A daily report might need to replace an older result. A tool organizing original documents might need to preserve existing files.</p>
<p>Leaving these choices unstated means the agent has to make them. If its assumptions turn out to be wrong, the implementation and its checks both need revisiting.</p>
<p>I would add a short behavior agreement to the task:</p>
<blockquote>
<p>Preserve the input files and write results to a separate output directory. If a target file already exists, report a conflict without overwriting it. Record individual processing failures and continue with the remaining files. Report separate counts for successful items, conflicts, and failures. Return a nonzero exit code if any items remain unfinished.</p>
</blockquote>
<p>Here, reporting a conflict is the chosen policy. Other policies are valid too. What matters is choosing one explicitly and making the implementation and checks agree with it.</p>
<h2>One file mode can change the tool's behavior</h2>
<p>Python's <code>"w"</code> and <code>"x"</code> file modes differ by one character, but their behavior is quite different.</p>
<p>Opening an existing file with <code>"w"</code> truncates it. The <code>"x"</code> mode creates a file exclusively and fails if it already exists. These behaviors are documented in <a href="https://docs.python.org/3/library/functions.html#open">Python's <code>open</code> reference</a>.</p>
<p>For the policy “preserve existing results,” a small test can capture the requirement:</p>
<pre><code class="language-python">from pathlib import Path

import pytest


def write_result(target: Path, content: str) -&gt; None:
    with target.open("x", encoding="utf-8") as file:
        file.write(content)


def test_rerun_preserves_existing_result(tmp_path):
    target = tmp_path / "result.txt"

    write_result(target, "first result")

    with pytest.raises(FileExistsError):
        write_result(target, "second result")

    assert target.read_text(encoding="utf-8") == "first result"
</code></pre>
<p>Save this example as <code>test_output_policy.py</code> and run <code>python -m pytest -q test_output_policy.py</code> in an environment with pytest installed.</p>
<p>The test checks a specific behavior: the first write succeeds, the second raises <code>FileExistsError</code>, and the original content remains intact. Pytest's <a href="https://docs.pytest.org/en/stable/how-to/tmp_path.html"><code>tmp_path</code> fixture</a> provides a temporary directory for the test.</p>
<p>In an actual project, import the real writing function from the tool's module. Keeping a separate copy of the implementation inside the test would only test that copy. Testing the real function gives the agent a constraint that should survive later refactoring.</p>
<p>There is a limit here: <code>"x"</code> prevents overwriting an existing file. It does not guarantee a complete write. A failure after creating the file can still leave partial output, so recovery needs separate attention.</p>
<h2>An existing file is not necessarily a completed result</h2>
<p>A batch may stop after creating some output files. On the next run, “skip anything that exists” can accidentally skip unfinished work.</p>
<p>Before asking the agent to implement recovery, ask what it will use as evidence of success.</p>
<p>For structured output, that might include checking readability and required fields, along with the expected record count or the task's completion conditions. A CSV missing several rows can still open successfully. Readability alone is insufficient.</p>
<p>For a longer batch, the tool could record the outcome for each input and mark it successful only after writing and checking the result.</p>
<p>This does not mean every short script needs a task-management system. For a small, one-off batch, a clear list of successful and failed items may be enough. Persistent progress becomes more useful for tools that run regularly or process longer jobs.</p>
<p>Previous success records can also become outdated. Inputs change, and processing rules evolve. You need some way to identify which input and rule versions produced a result; matching filenames alone tells you too little.</p>
<p>During development, use temporary data to check three cases: rerunning after success, rerunning after an item fails, and rerunning with incomplete output already present. Inspect the actual results each time.</p>
<p>Recovery then has a concrete meaning: which results can be reused, which need processing again, and which require a decision from you.</p>
<h2>Separate model-request retries from script reruns</h2>
<p>So far, this is about running the finished Python tool. During development, a different interruption can occur: the coding agent's own model request fails.</p>
<p>The agent may already have edited the code and executed the script. The interruption might happen in the next round of analysis, after its tools returned their results.</p>
<p>Telling it to “start over” could execute that code again. If the script changes files, writes to a database, or creates resources, those repeated actions deserve a closer look.</p>
<p>There are two things to consider: how model requests recover, and how the agent recognizes work already completed.</p>
<p>The model service can handle part of the request recovery. At XylemNode, our <a href="https://xylemnode.com/en#home-auto-title">Auto group</a> selects request paths based on channel health and supports retries across groups when a channel fails. The caller continues using the same model name. Here, a channel means a path used to handle a model request.</p>
<p>For coding agents that support custom model services, this can reduce manual connection switching during development. The service connects to the coding tool, supporting the agent as it analyzes, edits, and checks the Python project.</p>
<p>Whether the script has already executed, and whether its output is complete, still needs to be established from tool records and actual files. Check that progress before deciding to continue verification or run the script again. This is where the rerun policy becomes useful during development too.</p>
<h2>Include the second run in the handoff</h2>
<p>For the next Python automation task, add something like this:</p>
<blockquote>
<p>Alongside the normal flow, explain what happens on repeated runs, how existing results are handled, and how the tool recovers from an interrupted run. Verify these cases with temporary data while preserving the inputs. Finish by listing the checks actually performed and anything still unverified.</p>
</blockquote>
<p>If the tool calls external services or writes to a database, check the effects of repeated execution separately. A file-writing test cannot establish correctness for those operations.</p>
<p>These requirements add some checking to the first delivery. They also make the behavior easier to anticipate when debugging, changing inputs, or handing the tool to someone else.</p>
<p>A dependable Python tool answers a few practical questions: where are the results, what remains unfinished, and what happens when you press Enter again? Making those answers explicit helps agent-written code become useful in everyday work.</p>
]]></content:encoded></item></channel></rss>