DEV Community

Cover image for The Assistant Wrote the Code. How Do You Know It Is Ready to Ship?
Mansur Fattakhov
Mansur Fattakhov

Posted on Originally published at mind.mansur.expert

The Assistant Wrote the Code. How Do You Know It Is Ready to Ship?

The email arrived. It has the right name, the right order number, and even the button leads where it should. The assistant says the task is done, the checks passed, and the changes are ready. At this point, closing the tab and moving on sounds very appealing. Especially if this little task has already taken up half the day.

I would leave the tab open a little longer.

In the previous article, we worked through an illustrative example: adding an email after an order is completed in an existing service. We first worked out what “completed” meant, found the existing notification mechanism, and agreed on the constraints. Now imagine the assistant has implemented that plan. We still have to decide whether we are ready to release the change to users.

An email arriving at a test address is a satisfying moment. For the first time, you can see the result you were working toward. But alongside that email, I would reopen the original task. We promised the customer a notification at a particular point, and the team that email problems would not disrupt the order. I want to know how much of that promise the result actually confirms.

A short request is enough to begin:

Show me the path from the relevant order event to the email being sent. What changed, and why? Compare the result with what we agreed: what has been checked, what evidence supports it, and what is still unknown. Do not fix anything yet.

That last sentence helps. Otherwise, a discussion of the result can easily turn into another development cycle: the assistant spots an improvement and immediately starts making it. First, I want to look at what we already have.

Suppose the reply points to the order handler, the code that adds a job to the queue, and the email template. I open the changes and follow that path myself. Where does the address come from? Why this particular status? What data goes into the message? Has the new code affected neighboring notifications?

You do not need to learn the entire project for this review. But I do want to understand the parts responsible for the behavior we promised. If the explanation ends with “this uses the standard mechanism,” I would ask to see that mechanism. If the code is still unclear, I would bring in a colleague who knows it. A polished description does not make unfamiliar code familiar.

Sometimes this is where an unexpected expansion of the task becomes visible. We were adding one email, yet the changes include a new way of processing every notification. There may have been a reason. It is worth recovering that reason before release, while the necessary change is still easy to separate from incidental cleanup. The more we changed, the more behavior we need to check.

After reading the code, I would return to that email. How did it reach the inbox? Did we take a test order through the relevant state, or did we call the sending function directly? In the second case, we have learned something useful about the template and email delivery, but we have not yet traveled the path from order to notification. That needs a separate check.

Imagine that works too. The order reaches the agreed state, and the email goes to the test address. Now we can introduce a little trouble into this happy story.

For example, give the handler the same event again.

In the last article, we agreed that a repeated event should not create an extra notification. Now we can make that agreement observable. How many jobs were created? How many times did the system try to send the email? What lets it recognize an event it has already processed? In a test, a replacement for the sending service can record calls so we can inspect them.

Suppose the test list contains the reassuring name “does not send the email twice.” I would still look inside. It might only check that a particular field exists in the job. That is a useful check of the field. The promise about duplicate sending remains a separate question.

It is easy to end up in a closed loop here: the assistant writes the code, writes tests to match that code, and reports that everything agrees. That is why I return to the behavior we discussed before implementation. What should the customer see? What should remain unchanged? What outcome would we consider wrong? These questions give the checks a reference point outside the implementation itself.

The next problem is an unavailable email service. We reproduce it in a test environment or with a test double and see what happens to the order. Is its status preserved? Can the person using the service carry on? Can the team see that the notification was not sent, and is it clear what happens next?

For our example, that matters more than checking once again that the email button looks nice. We agreed upfront that an email failure must not interfere with the order. Now we can verify that condition while the consequences stay inside a test.

There is a more awkward case too: the email service accepted the message, but its acknowledgment never reached us. Sending may look unsuccessful to the application even though the email has gone out. If the assistant promises that duplicates are impossible under any circumstances, I would ask it to examine this particular moment. How does the system find out the result of the first attempt? What does it do if it cannot find out? We need to understand the solution’s actual limits and agree on acceptable behavior before promising the customer more than the system can deliver.

These scenarios do not have to become a large, separate testing program. I would choose checks based on what this change could break. For an order email, that means timing, recipient, repeated events, and keeping order processing independent of email delivery. If the review shows that a shared notification mechanism has changed, we also need to look at its other callers.

After that, “the checks passed” carries much more meaning. Ideally, the actual results are there too: which checks ran, in which environment, and what they confirmed. Separately, there should be a record of what could not be run. Perhaps the local tests passed, but access to the test email service was unavailable. That means part of the path still needs checking. Someone with access can do it, and we can return to the release decision once we have the result.

I would also ask the assistant to compare the final changes with the original plan. The code may have changed while we investigated retries and failures. Checks performed before the last edit do not necessarily describe what we are about to ship. It helps to finish with one clearly identified version of the changes and check results for that version.

Even then, one question remains before release, a question that rarely comes to mind while looking at an email in your own inbox: what will we do if a problem appears once users have the change?

In our example, I would find out in advance whether we can stop the new emails while keeping order processing running. Who will notice a failure? Where can we see unsuccessful attempts? Will jobs already created continue sending after the feature is disabled? If that control is needed for a safe release and does not exist, we have another concrete task to complete beforehand.

An ordinary code rollback cannot recall an email that has already been sent. Being able to stop has a practical purpose: it helps contain the consequences within the next few minutes, instead of continuing to send while the team works out what happened.

By this point, the release decision usually feels calmer. I can explain what changed, show checks of the important scenarios, and name the remaining limits. I know how to observe the new sending behavior and how to stop it. If a significant “probably” remains in the story, it has an address: a specific piece of code, an unchecked scenario, or a question about product rules. We can work with that.

I like how this approach gradually changes the conversation with the assistant too. Instead of a vague “check again that everything is definitely fine,” we ask questions with verifiable answers. We stop circling through reassurances and start examining specific behavior.

The email in the test inbox still feels good. Only now I can see the whole path behind it: the right order, the right moment, the right recipient, and understood behavior when something fails. I can explain why I am ready to let this code meet users.

Over time, these questions become a habit. That does not always require a separate practice project or a free month to learn a new tool. In the next article, we will look at learning to work with a coding assistant through everyday tasks, while the regular work is still there to be done.

Top comments (0)