AI Bug-Fixing and Regression Testing for Personal Automations

AI Bug-Fixing and Regression Testing for Personal Automations
About the Author

Sam Na writes practical guides on AI-assisted productivity, dependable personal automations, and maintainable digital workflows. RoutineOS explores how to build useful systems that can be understood, checked, and improved when something goes wrong.

Author: Sam Na Contact: seungeunisfree@gmail.com Published and updated: October 26, 2026
AI Bug Fixing · Regression Testing · Personal Automation

Fixing an automation bug once is useful. Making sure it stays fixed is what turns a fragile script into a dependable routine. An AI bug-fixing and regression testing workflow helps you capture a real failure, preserve the input that triggered it, verify the repair, and keep checking that the same problem has not returned after future updates.

Imagine a personal automation that sends reminders for tasks due today. You built it with help from an AI assistant, ran it a few times, and added it to your daily schedule. One morning, the script sends the same reminder twice. You ask the assistant to fix the duplication, apply the suggested change, and see a single reminder on the next run.

A week later, the duplicates return after a small update to the task-import function. The original fix worked for one example, but nothing in your maintenance process required later changes to preserve that behavior. The problem was resolved temporarily without becoming a permanent condition that the project could check.

This is why regression testing matters. A regression is when something that previously worked stops working correctly after a change. A regression test preserves an expected behavior so future changes can be checked against it. When the test comes from a real incident, it also documents a mistake your automation has already made.

Every repaired bug should leave behind a useful piece of evidence: the input that exposed it, the behavior that was required, and a repeatable check that would fail if the problem returned.

AI can make this workflow easier by summarizing error records, turning sanitized incident details into test cases, comparing a patch with the previous version, and helping interpret later failures. It cannot decide which business rule is correct or prove that a test ran unless you supply an actual result.

We will follow one practical scenario involving duplicate task reminders, using Python to prevent duplicate entries within an import and JavaScript to illustrate a separate problem that arises across repeated executions. Then we will connect those checks to a lightweight maintenance routine and an optional automated test workflow.

Build a repeatable bug-to-regression workflow

A personal automation can break without anyone making a deliberate change to its central function. An imported file may contain a new format, a scheduled job may run twice, or a connected service may retry an operation after a timeout. Sometimes the code is wrong; other times the code is relying on an assumption that no longer holds.

The maintenance workflow needs to handle both cases. It begins with the incident rather than a new AI prompt, and it ends only after the corrected behavior has been made observable and repeatable.

Understand the difference between a fix and a regression guard

A fix is a change intended to remove a particular failure. A regression guard is a lasting check that the important behavior remains correct. They belong together, but they do different jobs.

Suppose the reminder script receives duplicate rows from an exported task list. The fix might identify repeated task IDs and avoid creating duplicate reminder candidates. The regression test then feeds the same duplicated rows into the selection function and checks that only one candidate is returned.

If another developer or AI agent later replaces that selection function, the test can detect the reappearance of duplicate candidates. It does not depend on remembering an old chat conversation or recalling why a particular conditional statement was added.

Fix without a lasting check
The original example works today

The patch produces the desired output once, but there is no saved reproduction or automatic warning when the behavior changes later.

Fix with a regression guard
The expected behavior becomes executable

The failure is documented, the repaired behavior is captured by a test, and future updates must satisfy that same requirement.

Give every incident a place in one maintenance loop

A useful workflow does not require expensive software or a complicated issue tracker. A small project folder, a text-based incident record, and a few repeatable commands can be enough. The important choice is to keep evidence together instead of scattering it across terminals, AI chats, and temporary files.

Assign an incident identifier, such as BUG-014, whenever a failure deserves investigation. That identifier can appear in the incident note, the test name, and the change description. It lets you connect a failed automation run with the later decision that resolved it.

Keep the record short enough to maintain. Note the expected behavior, observed behavior, affected operation, smallest relevant input, accepted patch, and verification outcome. Add environment details when they matter, but do not turn every minor issue into an extensive report.

1
Capture
Record the real failure, including when it appeared and which automation action was affected.
2
Reproduce
Reduce the problem to a small input or controlled sequence that produces the unwanted result.
3
Specify
Write the correct outcome independently of the current code or any AI-generated explanation.
4
Repair
Apply a reviewed change that addresses the supported cause without modifying unrelated behavior.
5
Guard
Keep a regression check that would recognize the same failure after a future change.
6
Monitor
Run the relevant checks after changes and retain enough history to investigate a recurrence.

Choose the right level of maintenance for the automation

Not every personal script deserves the same amount of testing. A one-time calculator that reads no private files has different consequences from a scheduled process that updates a calendar or sends messages. Choose the amount of regression protection based on the effect of an incorrect result.

For a small deterministic function, one precise test may preserve the important behavior. For an automation that talks to external services, you may need separate tests for selection logic, delivery behavior, failure handling, and stored state. Those checks should use safe data and controlled dependencies whenever possible.

The goal is not to test every implementation detail. It is to preserve the commitments the automation makes: which records it processes, which records it skips, and which actions it is allowed to perform.

Key Takeaway

Treat debugging as a complete maintenance cycle: capture, reproduce, specify, repair, guard, and monitor. A permanent regression check turns an individual bug into useful project knowledge.

Record the failure and preserve a reproducible case

The quality of your bug history depends on what you preserve before changing the code. Once a patch has been applied, it can be surprisingly difficult to recreate the original conditions. Logs may be replaced, temporary inputs may disappear, and the original AI conversation may contain several different proposed explanations.

Capture the smallest useful evidence while the failure is still understandable. You do not need to keep every line of a large log. You need the information that distinguishes this incident from other failures that merely look similar.

Write a bug report that describes an observable mismatch

Imagine that your daily reminder automation is expected to create one candidate reminder for each distinct open task due on the selected day. A task export contains the same task twice, perhaps because two imports were combined. Your existing selection function includes both entries in the output.

The report should identify that exact mismatch. Avoid descriptions such as "the AI automation is unreliable" or "notifications are broken." Those statements do not identify the record involved, the expected count, or the boundary at which duplication occurred.

You should also distinguish the candidate-selection problem from actual message delivery. Two candidate records may cause two sends, but they are not proof that every duplicate notification originates in the candidate selector. The scheduler or the delivery service could be involved too.

Example incident record
BUG-014 — Duplicate reminder candidates

Observed: Two identical rows with task ID t-17 produce two candidates.

Expected: One candidate should represent that task within the same daily import batch.

Trigger: The import includes a repeated open task due on the selected day.

Boundary: The first repair covers duplicate rows within one batch, not repeated scheduled executions.

Save the input, runtime, and previous version

The test input should be small enough to share with an AI assistant safely. Replace real task names, personal information, and account identifiers with artificial values while preserving the structure that caused the bug.

In this case, the task ID matters because duplicate detection uses that field. The actual identity of the user's task does not matter. A fabricated ID such as t-17 and a title such as "Pay invoice" are enough to demonstrate the behavior.

Record the script version or Git commit that produced the failure. When relevant, keep the Python or Node.js version and the configuration controlling the automation's schedule. That information becomes useful when a bug appears only after a runtime or dependency change.

Do not replace the original failing example with an AI-generated "cleaner" version before confirming that the cleaned example still produces the bug. A reproduction that no longer fails cannot establish the original cause.

Ask AI to turn the evidence into an incident summary

AI can help organize a messy failure report, especially when you have terminal output, a scheduled-job log, and a small code fragment. Give it the observations and ask it to separate confirmed facts from possible explanations.

That distinction matters because AI may confidently blame a scheduler for duplicate sends when the only evidence available is a duplicated data row. Your incident record should not convert a hypothesis into a confirmed root cause.

Copy-Ready Prompt: Create a Reproducible Bug Record
Help me document a failure in a personal automation. Automation purpose: [DESCRIBE THE JOB] Observed behavior: [PASTE ACTUAL RESULT] Expected behavior: [DESCRIBE THE REQUIRED RESULT] Sanitized input: [PASTE THE SMALLEST RELEVANT DATA] Code version and environment: [PASTE KNOWN DETAILS] Write a short incident record containing: - A clear incident title - Reproduction steps - Expected versus actual result - Confirmed observations - Possible causes, clearly labeled as hypotheses - Missing evidence - A proposed regression-test requirement Do not invent logs, execution results, or root causes. Do not propose unrelated refactoring. Do not assume the code was executed.

A useful incident record is not a transcript of everything the AI suggested. It is a concise, evidence-based account of a failure that another person could understand and reproduce later.

Key Takeaway

Preserve the failing input and the expected result before changing the implementation. Keep observed facts separate from AI hypotheses, and define the precise failure boundary.

Turn a duplicate-reminder bug into a Python regression test

Now we can turn the incident into a lasting check. Our example assumes a daily task export contains records with an ID, title, due date, and status. The selector should return open tasks due on the requested day, in their original order.

The new requirement is that repeated rows with the same ID and the same title represent one reminder candidate. If two matching rows use the same ID but disagree on the title, the function should report the conflict rather than silently choosing one.

Reproduce the original defect in the selector

The simplified original function filters records by due date and status. Its logic works for ordinary rows but has no rule for repeated task IDs.

def due_reminders(rows, day):
    return [
        {
            "id": row["id"],
            "title": row["title"],
        }
        for row in rows
        if row["due"] == day
        and row["status"] == "open"
    ]

If an imported list contains two identical qualifying records, the list comprehension returns two candidates. The code is not experiencing a Python exception. It is doing exactly what the expression requests, which differs from the newly clarified requirement.

Before modifying this function, write a test that captures the desired behavior. On the original implementation, that test should fail because it receives two candidates instead of one. This is a meaningful red state: it demonstrates that the regression test can recognize the bug.

Apply a narrow fix with explicit duplicate rules

The repaired function below keeps a dictionary of task IDs already selected. It ignores identical repeated records while rejecting conflicting titles for the same ID. Records that are not open or are due on another day remain outside the result.

Save the implementation in a file named reminders.py. This example assumes that each row is a dictionary and that the supplied day uses the same date-string format as the imported records. Those input assumptions are part of this small example, not universal production validation rules.

def due_reminders(rows, day):
    seen = {}
    result = []

    for row in rows:
        if (
            row.get("due") != day
            or row.get("status") != "open"
        ):
            continue

        task_id = row.get("id")
        title = row.get("title")

        if (
            not isinstance(task_id, str)
            or not task_id.strip()
        ):
            raise ValueError("Active task needs an ID")

        if (
            not isinstance(title, str)
            or not title.strip()
        ):
            raise ValueError("Active task needs a title")

        title = title.strip()

        if task_id in seen:
            if seen[task_id] != title:
                raise ValueError(
                    "Conflicting duplicate task ID"
                )

            continue

        seen[task_id] = title

        result.append({
            "id": task_id,
            "title": title,
        })

    return result

This patch makes the duplicate rule visible. It does not install a package, change the scheduler, or introduce a delivery service. It also avoids using a task title as the unique key, because two different tasks might legitimately have the same title.

One important design choice remains: the function uses the task ID as an identity within the imported batch. If the source system recycles IDs or uses a different identity rule, that requirement must be revisited.

Notice that this function creates candidates; it does not send reminders. That separation keeps its behavior deterministic and makes the duplicate-row problem easier to test. Delivery across separate runs requires a different kind of protection, which we will address next.

Preserve the real bug as a permanent pytest test

The test suite below uses the incident's duplicated record as its first case. It also checks that unrelated tasks are excluded, conflicting IDs are rejected, and a selected task cannot have a missing ID. Each test represents a separate behavior that matters to the automation.

Save the test code as test_reminders.py in the same example directory as reminders.py.

import pytest
from reminders import due_reminders


DAY = "2026-10-26"


def test_duplicate_rows_make_one_candidate():
    rows = [
        {
            "id": "t-17",
            "title": "Pay invoice",
            "due": DAY,
            "status": "open",
        },
        {
            "id": "t-17",
            "title": "Pay invoice",
            "due": DAY,
            "status": "open",
        },
    ]

    assert due_reminders(rows, DAY) == [
        {
            "id": "t-17",
            "title": "Pay invoice",
        }
    ]


def test_ignores_closed_and_other_day():
    rows = [
        {
            "id": "a",
            "title": "Archive",
            "due": DAY,
            "status": "done",
        },
        {
            "id": "b",
            "title": "Plan",
            "due": "2026-10-27",
            "status": "open",
        },
    ]

    assert due_reminders(rows, DAY) == []


def test_conflicting_duplicate_is_rejected():
    rows = [
        {
            "id": "t-17",
            "title": "Pay invoice",
            "due": DAY,
            "status": "open",
        },
        {
            "id": "t-17",
            "title": "Cancel invoice",
            "due": DAY,
            "status": "open",
        },
    ]

    with pytest.raises(
        ValueError,
        match="Conflicting duplicate",
    ):
        due_reminders(rows, DAY)


def test_active_missing_id_is_rejected():
    rows = [
        {
            "title": "Pay invoice",
            "due": DAY,
            "status": "open",
        }
    ]

    with pytest.raises(
        ValueError,
        match="needs an ID",
    ):
        due_reminders(rows, DAY)

From the example project directory, run the tests using the Python environment where pytest is installed.

python -m pytest -q test_reminders.py

The four displayed regression cases were executed with pytest against the corrected function, and all four passed in that local check. That result verifies the particular example shown here. It does not establish that a different task importer or a real reminder service will behave correctly.

1 Original regression case Two identical imported rows should produce one reminder candidate.
3 Additional safeguards Unrelated records, conflicting IDs, and missing identifiers.
4/4 Example checks passed The demonstrated pytest cases passed against the displayed fix.

For workflows involving files, place test exports in temporary directories instead of pointing at your real documents folder. pytest provides a tmp_path fixture for separate temporary test directories. It is useful when you want to preserve a regression involving a file import without rewriting production data.

Key Takeaway

Keep a reproducible example of the original bug in your test suite. The corrected Python selector prevents duplicates within one import batch, while separate tests protect related requirements from later changes.

Protect repeated JavaScript automation runs

Duplicate rows within one import are only part of the problem. A scheduled automation may run again after a restart, a service may retry a request, or someone may manually start the same task twice. Even with a perfectly deduplicated candidate list, the next execution can select the same task again.

The difference matters because preventing duplicate entries inside one batch is not the same as preventing duplicate actions across multiple runs. A function's in-memory set disappears when the process exits. A later execution cannot remember what happened earlier unless durable state is maintained.

Distinguish batch deduplication from repeat-run protection

Suppose the reminder selector produces one candidate for task t-17. The sender delivers it, then the scheduler starts the job again. The candidate selector still returns t-17 because the task remains open and due today.

From the selector's perspective, this is correct. Its job is to choose due tasks from the input. Preventing another delivery requires knowing whether the reminder was already sent for the relevant reminder period.

This usually means recording a durable delivery key after an operation has been confirmed. A key could combine the task ID with the reminder date or another defined notification window. Using the task ID alone may accidentally suppress a legitimate reminder on a later date.

Within one run
One candidate per repeated record

Deduplicate the imported batch by the identity required by the task selector. This does not persist information between executions.

Across separate runs
Check a durable reminder history

Consult a record of previously confirmed deliveries for the relevant reminder period before deciding which candidates remain.

Test the decision to skip an already recorded reminder

The following JavaScript function shows the selection part of this process. It receives reminder candidates and a collection of IDs previously recorded as sent. It returns candidates whose IDs are not in that collection.

Save the function as checkpoint.cjs. The use of CommonJS here keeps the small example compatible with a straightforward Node.js setup.

function chooseUnsent(reminders, sentIds) {
  const sent = new Set(sentIds);

  return reminders.filter((item) => {
    return !sent.has(item.id);
  });
}

module.exports = { chooseUnsent };

This function assumes the caller supplied a list of already deduplicated candidates, valid IDs, and the correct delivery history for the relevant period. It does not read or save a checkpoint. Those responsibilities belong to other parts of the automation.

The matching test checks that an ID previously recorded as sent is excluded, while an unrecorded candidate remains available. It also checks that an empty history does not suppress every reminder.

Save the following Jest tests as checkpoint.test.js. The test file imports the CommonJS module from checkpoint.cjs.

const { chooseUnsent } = require("./checkpoint.cjs");

describe("reminder checkpoint filtering", () => {

  const reminders = [
    {
      id: "t-17",
      title: "Pay invoice",
    },
    {
      id: "t-19",
      title: "Review draft",
    },
  ];

  test("skips an already recorded reminder", () => {
    const result = chooseUnsent(
      reminders,
      ["t-17"]
    );

    expect(result).toEqual([
      {
        id: "t-19",
        title: "Review draft",
      },
    ]);
  });

  test("keeps all reminders with no history", () => {
    expect(
      chooseUnsent(reminders, [])
    ).toEqual(reminders);
  });

});

The JavaScript arrow functions in the HTML source use the correct => character sequence for display in a code block. When Blogger renders the HTML, readers will see the ordinary JavaScript arrow operator.

This example is intended for a project with Jest installed. The core filtering behavior was checked using Node.js assertions, and the JavaScript syntax was checked separately. The complete Jest suite was not executed in an installed Jest environment, so you should run it in your configured project.

Jest's asynchronous testing documentation is also useful when the surrounding automation sends messages or writes state asynchronously. Those tests must wait for the relevant promise before judging the outcome.

Handle partial failures and delivery acknowledgments

A durable checkpoint introduces a harder question: when should the automation record that a reminder was sent? If it records success before the message is delivered, a later failure may cause the reminder to be skipped permanently. If it records success after delivery, the process could crash between delivery and checkpoint storage, leading to another send on retry.

This is a partial-failure problem. The automation has two separate operations whose outcomes may not be committed together: delivery and local state persistence. A simple file of sent IDs cannot guarantee exactly-once delivery under every failure condition.

For low-risk personal reminders, you may accept occasional duplicates while prioritizing delivery. For an operation with financial consequences, account changes, or other sensitive effects, you may need provider-supported idempotency keys, durable queues, transactional safeguards, or independent engineering review.

An idempotent operation is designed so repeating an equivalent request does not create an unintended additional effect. Where an external service supports an idempotency mechanism, use the documented contract rather than assuming a local filter is enough.

Do not describe a local set of sent IDs as a complete guarantee against duplicate notifications. It protects only the conditions represented by that stored history. Concurrency, failed persistence, retries, and delivery uncertainty still need deliberate handling.

Ask AI to review the failure sequence, not merely the final function. A useful test plan considers a successful send, a rejected send, a failed checkpoint write, and two overlapping executions. Each scenario may need a different observation to establish that the workflow behaves as intended.

Copy-Ready Prompt: Investigate Repeated Automation Runs
Review this scheduled automation for repeated-run failures. Task: [DESCRIBE THE AUTOMATION] Current selection logic: [PASTE CODE] Delivery mechanism: [DESCRIBE THE PROVIDER WITHOUT SHARING SECRETS] Checkpoint or state storage: [DESCRIBE THE PERSISTENT STORAGE] Expected behavior: [STATE WHETHER REPEATED DELIVERY IS ALLOWED] Analyze these separate cases: 1. Duplicate input rows within one run. 2. A second run using the same inputs. 3. Delivery succeeds but checkpoint storage fails. 4. Delivery fails before confirmation. 5. Two runs overlap. Identify which guarantees are supported by the code and which require provider or storage capabilities. Suggest safe regression scenarios with mocks. Do not make live requests. Do not claim exactly-once delivery without evidence.
Key Takeaway

Regression protection must follow the real failure boundary. Deduplicating an import batch does not prevent repeated sends across executions. Durable state and partial-failure behavior require their own tests and design decisions.

Compare before-and-after behavior and approve a fix

Once a patch is proposed, the next question is whether it repairs the incident without changing something else that users depend on. An AI assistant may produce a shorter implementation or a more elegant approach, but those qualities do not establish that existing behavior has been preserved.

Before approving the change, compare the failing case, a representative normal case, and any surrounding behavior that could be affected by the patch. Keep these observations connected to the same code revision so later maintenance does not mix results from different implementations.

Compare the same inputs against both versions

A useful before-and-after comparison keeps the environment and input as consistent as possible. For BUG-014, feed the identical duplicated task rows into the previous selector and the repaired selector.

The previous version returns two candidates. The repaired version should return one. That establishes the intended change in behavior. Next, pass a list with two distinct eligible tasks and confirm that both still appear.

Finally, check the rule for conflicting duplicate IDs. If the same ID appears with different titles, the current contract requires an explicit error rather than silently choosing the first entry. That test protects a different condition from the original duplicate-row defect.

BEFORE Two identical rows The original selector returns two candidates for one task ID.
AFTER One candidate The corrected selector returns one candidate for identical repeated rows.
GUARD Permanent test The saved case checks that a future change does not restore the old result.

Inspect the changed code without accepting unrelated edits

The accepted fix should have an understandable scope. In the Python example, the change adds task-ID tracking and explicit handling for repeated records. It does not need to rewrite the scheduling mechanism, change message templates, or install another dependency.

If an AI assistant proposes a broader refactor, ask which changes are required for the incident and which are optional improvements. Separating those decisions makes a later regression easier to investigate.

When using Git, a diff helps identify additions and deletions. Keep a version of the code from before the repair, and record the accepted change. An earlier good version becomes a practical recovery point if a new change causes unexpected effects.

The regression test should be reviewed independently of the implementation. If the AI changes both the code and the expected test output merely to produce a passing result, the test may no longer represent the intended behavior.

Interpret a failed regression test before updating it

A failed test is a signal, not a diagnosis. The implementation may be wrong, the environment may be different, the test may contain an incorrect assumption, or a product requirement may have changed deliberately.

If a test starts failing after a legitimate requirement change, update the behavior contract and document that decision. Then revise the test to reflect the new requirement. Do not delete the test simply because it blocks the latest AI-generated patch.

In contrast, if the requirement has not changed, a failure demands investigation. A passing test from last week is not enough to approve this week's code. Run the test against the exact version you intend to use.

Copy-Ready Prompt: Compare a Fix With the Previous Version
Review this proposed bug fix for a personal automation. Incident ID: [BUG ID] Required behavior: [EXACT ACCEPTANCE CONDITION] Original failing input: [SANITIZED INPUT] Previous code: [CODE OR DIFF] Proposed code: [CODE OR DIFF] Relevant regression tests: [TEST CODE] Actual results, if available: [PASTE REAL TEST OUTPUT] Identify: 1. Which change addresses the original failure. 2. Which previously working behavior might change. 3. Any unrelated code or dependency changes. 4. Whether test expectations match the stated requirement. 5. Additional evidence needed before approval. Do not invent test results. Do not rewrite expected outputs to match a failed patch. Return a short review with an approve, revise, or investigate recommendation and the supporting reasons.
Key Takeaway

Compare the same input across versions, preserve previously correct behavior, and approve only a reviewed change. Regression tests should enforce requirements, not adapt automatically to whatever the latest code returns.

Run regression checks automatically

The value of a regression test increases when you do not have to remember to run it every time. Automated checks can run when code changes are pushed, before changes are merged, or at selected maintenance intervals.

The important distinction is between testing an automation and running the automation's real actions. A regression workflow should generally operate on synthetic input and mocked dependencies. It should not send real reminders or update production accounts simply to verify the selection logic.

Start with one local command that checks the project

Before adding any scheduled checks, make sure the relevant tests can be run locally with a documented command. For a Python-only project, this may be as simple as invoking pytest from the project directory.

python -m pytest -q

For a JavaScript project, use the test command provided by its package configuration. If Jest is installed and configured, you can run the intended test files from the command line.

npx jest checkpoint.test.js --runInBand

If both languages are used, maintain separate dependency environments and record the commands for each. It is better to have two reliable, understandable commands than one complex script that hides which test suite failed.

When a test fails, save the command, code version, and relevant error output. Those details help distinguish a genuine regression from a missing dependency or configuration problem.

Add a GitHub Actions check without production credentials

For code stored in a GitHub repository, GitHub Actions can run a regression suite whenever relevant code is pushed or reviewed. The official GitHub guide to building and testing Python explains how to set up a Python environment and run tests in a workflow.

The example below assumes a small Python project whose tests require only pytest. Save the configuration as .github/workflows/regression.yml. It installs pytest in the workflow environment and runs the tests without any delivery credentials.

name: Regression checks

on:
  push:
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  python-tests:
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install test framework
        run: python -m pip install pytest

      - name: Run regression tests
        run: python -m pytest -q

This is a minimal example, not a complete workflow for every repository. If the tests require project dependencies, install them from the project's approved dependency definition as well. Review third-party actions and repository permissions according to your security requirements.

This workflow does not run your real reminder sender. It runs local tests designed to use artificial records. There should be no reason to add a live email password or messaging-service token merely to test reminder selection.

GitHub Actions also supports scheduled workflows, but the schedule belongs to a different decision. If your test suite already runs on each code change, adding a daily schedule may provide little value unless external dependencies, runtime updates, or time-dependent behavior can change between commits.

Use test results as maintenance signals

An automated test result should help you decide what to do next. A failed run needs investigation, but the report must first identify whether the failure came from the test assertion, an import, a missing dependency, or an unavailable service.

Avoid turning every warning into an immediate production fix. A transient problem in a test runner may require a rerun or environment investigation. Changing application code without understanding the failure can introduce a new regression.

If the automated check detects a previously repaired bug, reopen the relevant incident record and connect it to the new code change. That preserves the relationship between a historical failure and its recurrence.

Tests pass
Supported behavior remains checked

The configured assertions succeeded in the tested environment. This does not guarantee that untested production behavior is correct.

Tests fail
Inspect the cause before editing

Determine whether the mismatch comes from code, expected behavior, environment, or a test dependency.

Tests are skipped
Check what was not verified

A successful workflow may still skip meaningful checks. Review the test summary and any intentionally disabled cases.

Real service is contacted
Reconsider test isolation

A unit-test workflow should not unexpectedly send messages, alter accounts, or change real records.

Never connect a regression workflow to production credentials merely because a generated test asks for them. Isolate external effects with suitable test substitutes and use deliberately authorized integration checks when real-service behavior must be verified.

Key Takeaway

Automate the verification of expected behavior, not the live side effects of the automation itself. Keep test commands reproducible and use failures as evidence for investigation.

Maintain a simple AI-assisted bug history

A regression suite protects behavior, while an incident history explains why the protection exists. Both become more useful as a project changes. Without that context, someone may remove a seemingly redundant test and accidentally recreate an old failure.

You do not need to preserve the entire AI conversation for every bug. Store the decision-making facts: what happened, what was required, what changed, and what evidence showed the fix was accepted.

Connect incident IDs, code changes, and test names

Use a simple convention so you can find all material related to one issue. A filename such as BUG-014.md might describe the duplicate-reminder case. Its resolution can mention the accepted Git commit and the regression test that protects the behavior.

When the same symptom appears months later, compare the new incident with the earlier record. It could be the same bug returning, or it could be a new defect in a different part of the workflow.

For example, one case may concern duplicate input rows, while another concerns a scheduler restarting after partial delivery. Both can cause repeated notifications, but they require different regression checks.

Example maintenance note
BUG-014 — Closed after regression verification

Component: Daily reminder candidate selection.

Cause: The previous selector did not account for repeated task IDs within one imported batch.

Accepted behavior: Identical repeated records produce one candidate; conflicting duplicates produce an error.

Verification: Four demonstrated pytest cases passed against the repaired example.

Remaining scope: Delivery retries and persistent checkpoints are separate automation concerns.

Use AI to summarize change history without rewriting the facts

AI can help turn a collection of incident notes, diff summaries, and test results into a concise maintenance update. That is useful when several small fixes have accumulated and you need to understand what changed in the workflow.

Provide the actual records rather than asking the assistant to remember previous events. It should identify resolved issues, outstanding questions, and any changes that affect existing regression checks.

The summary should never invent a successful test run or imply that a particular incident is resolved without supporting evidence. If a test was suggested but not executed, the record should say so.

Copy-Ready Prompt: Maintain an Automation Bug History
Summarize the supplied maintenance records for my personal automation. Incidents: [PASTE SANITIZED INCIDENT NOTES] Changes: [PASTE ACTUAL CHANGE SUMMARIES] Test results: [PASTE ACTUAL OUTPUTS] Produce a short maintenance report with: - Bugs resolved - Behavior now protected by regression tests - Bugs still open - Relevant changes to dependencies or scheduling - Unverified assumptions - Recommended next maintenance action Use only the supplied records. Distinguish passed tests from suggested tests. Do not invent incidents, dates, or outcomes. Do not repeat the same point in multiple sections.

Keep maintenance proportionate and revisit old assumptions

A personal automation should become easier to maintain as your test history grows, not buried under documents that no one reads. Keep the workflow small enough that you will actually use it.

Review the oldest regression tests when the project undergoes major changes. Some tests may still protect essential behavior. Others may refer to requirements that have changed deliberately.

If you retire a test, record why it is no longer relevant. If you change a task identity rule or reminder schedule, make the new contract explicit before updating the related assertions.

A lightweight maintenance routine can also include occasional checks of dependencies, expired credentials, and scheduled execution settings. These concerns are not always regression tests, but they can explain why an automation changes behavior even when its source code remains stable.

Every meaningful incident has a reproducible or clearly documented trigger.
Expected behavior is distinguished from the original faulty output.
The accepted code change can be connected to the incident record.
A lasting regression check protects the important repaired behavior.
Test results are recorded as observed outcomes, not AI predictions.
External services and real user data remain separate from ordinary automated unit tests.
Old tests are revised only after the behavior contract changes.
Recurring incidents are compared with earlier causes rather than assumed to be identical.
Key Takeaway

Keep a compact chain of evidence connecting the incident, approved repair, and regression check. Use AI to organize that history without allowing it to replace missing facts with guesses.

Frequently Asked Questions

Q1. What is AI regression testing for personal automations?
AI regression testing uses AI assistance to create, organize, or review checks that protect existing automation behavior after changes. The tests must still be executed in an appropriate environment. AI suggestions alone do not establish that a regression has been prevented.
Q2. How is regression testing different from fixing a bug?
Fixing a bug changes the code or configuration to address a failure. Regression testing preserves the expected result so later changes can be checked for the same mistake. A useful incident workflow connects both activities.
Q3. Can ChatGPT or Claude create regression tests from an error log?
Yes. Both can suggest test cases from a sanitized log, relevant code, and a written behavior contract. However, a log may not contain everything needed to reproduce the incident. Verify the assumptions and execute the generated tests yourself.
Q4. How do I prevent an automation from sending duplicate reminders?
First identify whether duplicates arise within the input batch or across separate executions. Batch deduplication can prevent repeated candidates in one run. Repeated delivery may require durable checkpoints, documented provider idempotency features, and explicit handling of retries and partial failures.
Q5. Should I save every bug as a permanent regression test?
Preserve tests for meaningful behavior that could break again. A reproducible mistake affecting data, selection, scheduling, or external actions usually deserves a lasting check. Avoid keeping redundant tests that provide no additional protection.
Q6. Can GitHub Actions run my regression tests automatically?
Yes. GitHub Actions can run configured test commands when code is pushed, during pull requests, or through manual and scheduled triggers. Keep ordinary regression tests isolated from production services and grant only the permissions they actually need.
Q7. What if a regression test fails after a legitimate feature change?
Confirm whether the intended behavior changed. If it did, document the new requirement and update the relevant tests deliberately. If the requirement did not change, investigate the failure rather than editing the expected output merely to make the suite pass.
Q8. Does passing a regression suite mean my automation cannot break again?
No. Passing tests show that the configured assertions succeeded under the tested conditions. They cannot cover every input, service outage, configuration change, or partial failure. Maintain safe operational checks and update the suite when new incidents reveal missing cases.

Conclusion: make every bug fix easier to trust next time

Personal automations are meant to remove repetitive work, but an unreliable automation can create a different kind of burden. When every failure starts a new AI conversation from scratch, the same assumptions may be rediscovered again and again.

A maintainable workflow keeps the important facts. It preserves the failing input, states the intended behavior, records the accepted repair, and runs a regression check when later changes are introduced. AI can help with analysis and test construction, while the actual code and execution results remain the source of verification.

The duplicate-reminder example shows why precise boundaries matter. Removing repeated task rows in one import batch is a useful improvement, but it does not guarantee that the reminder will be delivered only once across retries or restarted jobs. Keeping those issues separate makes the maintenance process more accurate.

Begin with the next meaningful error in an automation you use regularly. Give it an incident ID, save a small reproduction, and create one test that would fail if the same problem returned. You do not need to build an elaborate testing platform. You need a repeatable way to turn a repaired failure into a rule that the next version must respect.

Your Next Step: Turn One Old Bug Into a Regression Guard

Choose a bug you have already fixed in a Python or JavaScript automation. Recreate the smallest safe input that caused it, write the required result, and ask an AI assistant to help create a focused test. Run the test against the actual repaired code, save the result, and add the check to your normal update routine. The goal is to make the next code change safer than the last one.

About Sam Na

Sam Na writes RoutineOS guides on AI-powered productivity, practical automation systems, and sustainable digital workflows. His articles help readers understand how their tools behave, recognize fragile shortcuts, and maintain reliable routines with clear evidence instead of guesswork.

Sam Na · RoutineOS seungeunisfree@gmail.com
A Quick Note Before Applying These Examples

This article provides general information and educational examples. The appropriate bug-fixing and testing approach depends on your code, data, permissions, external services, and the consequences of each automation action. Run examples with safe data and review any change that could affect important files or accounts. For consequential systems, confirm current official documentation and consult a qualified developer or security professional when appropriate.

References and Official Documentation
pytest Documentation — How to Use Temporary Directories and Files in Tests. Official explanation of the tmp_path fixture and isolated temporary test files.
Jest Documentation — Testing Asynchronous Code. Official guidance on promises, async/await, and waiting for asynchronous test results.
GitHub Docs — Building and Testing Python. Official instructions for creating a GitHub Actions Python test workflow.
Previous Post Next Post