---
title: "Can Operations Staff Ask AI to Modify a Todo App? Clarification Questions and Confirmed Requirements"
description: "I built an interface that refuses to send ambiguous requests such as 'add priorities and make Todos easier to read' directly into implementation. It records answers, manual requirement edits, and human confirmation, then verifies that the server blocks change jobs while questions remain unanswered or the requirements remain unconfirmed."
lang: "en"
canonical: "https://llm-lab.dev/en/posts/todo-cms-change-request-confirmation/"
source: "https://llm-lab.dev/en/posts/todo-cms-change-request-confirmation.md"
publishedAt: "2026-07-20"
updatedAt: "2026-07-20"
category: "AIDD"
tags:
  - "aidd"
  - "requirements-engineering"
  - "human-in-the-loop"
  - "non-engineer"
---

# Can Operations Staff Ask AI to Modify a Todo App? Clarification Questions and Confirmed Requirements

> [!NOTE]
> What this article confirms
>
> I added clarification questions, answer fields, editable requirements, human confirmation, and change-job creation controls to the web interface that receives Todo app modification requests.
>
> For both priority and due-date changes, the server rejected change-job creation while questions remained unanswered and while the requirements remained unconfirmed. It issued one job ID only after human confirmation. A request to "make Todos more useful" stopped with two unanswered questions instead of selecting a feature on the user's behalf.
>
> The questions were predefined to make the verification reproducible. This article does not test whether an external AI API can generate appropriate questions or complete the code change.

## The End Goal Runs from Chat to a Draft PR

This series is building, in stages, a workflow that lets Todo app operations staff request changes through a dedicated web interface without working directly with Git or a terminal. The end goal is for a user to answer AI questions, edit and confirm the structured requirements, then have code changes and tests run in an isolated environment. Only passing changes should become GitHub Draft PRs, which are proposals prepared before requesting formal review. The final comparison will run ten types of modifications and compare this interface with manually asking an existing coding agent to perform each task.

```text
Request a change in natural language
  ↓
Answer questions about missing information    ← Part 2
  ↓
Edit and confirm structured requirements      ← Part 2
  ↓
Modify code and run tests in isolation         ← Part 3 onward
  ↓
Create a draft change proposal only if it passes ← Part 5
  ↓
Compare manual requests across ten changes     ← Part 6
```

[Part one](/en/posts/todo-cms-safe-local-code-agent/) tested the foundation required for the latter half of this flow. I called three AI APIs through a common interface and tested their generated code proposals in an isolated environment. Three of nine fixed tests failed and the process stopped. Nothing was written to the GitHub code or production data, confirming that a failed change could be stopped before leaving the environment.

The first interface, however, displayed decisions such as "three priority levels," "existing Todos default to medium," and "the list can be filtered" from the beginning. The screen made those values look like user decisions, but they were fixed experimental inputs.

When did the user receive questions? Where did they answer? What exactly did they review before confirming the change?

Those steps did not exist in the interface.

Switching among three AI providers does not make a change interface usable by non-engineers if the confirmation process is omitted. I therefore placed a **Change Request** between the natural-language request and the code modification. A Change Request stores the conversation, unanswered questions, structured requirements, and human confirmation state for one modification.

In this article, **structured requirements** separate the conversation into a change summary, current state, expected state, acceptance criteria that define completion, and a test plan. A **change job** is the unit that sends confirmed requirements to the later code-modification stage.

## Four Ambiguities Inside "Make It Easier to Read"

I used the same request as in part one:

```text
I want priorities on my Todos. Make them easier to read.
```

The verification log refers to this request as scenario S01. S01 abbreviates "Scenario 01"; the number does not represent difficulty or execution order.

"Add priorities" identifies the feature, but "make them easier to read" does not define its behavior. The Change Request interface returned four unanswered questions:

1. How many priority levels should exist, and which values should they use?
2. What priority should existing Todos receive?
3. How should users distinguish priorities in the list?
4. How should the priority filter interact with the existing status filter?

![Change Request interface showing four clarification questions for an ambiguous priority request and blocking the change job while they remain unanswered](/images/posts/todo-cms-change-request-confirmation/01-clarification-questions.webp)

The structured requirements on the right still have empty expected-state, acceptance-criteria, and test-plan fields. The interface shows "Waiting for answers" and disables both "Confirm these requirements" and "Start change job."

I also called the change-job creation API directly without using the interface. A disabled button is not a meaningful boundary if a direct API request can bypass it.

The server rechecked the four entries in `openQuestions` and issued no job ID. The number of calls to the code-modification AI remained zero.

## Answered Questions Still Leave an Unconfirmed State

I answered the questions as follows:

| Clarification | Human answer |
|---|---|
| Priority values | Three levels: `low`, `medium`, and `high` |
| Default for existing Todos | `medium` |
| List display | A badge using both color and text |
| Filtering | Can be combined with the existing `status` filter |

`status` is the existing API field that represents whether a Todo is open or completed.

A deterministic transformation applied the answers to the common `change-request-v1` format and generated the expected state, acceptance criteria, and test plan. Rather than retaining only the conversation, it splits the information into arrays that later stages can validate field by field.

```json
{
  "openQuestions": [],
  "confirmedByHuman": false,
  "acceptanceCriteria": [
    "Existing Todos are displayed as medium",
    "The API returns 400 for a disallowed priority",
    "The list displays priority with a badge that uses both color and text",
    "The priority filter can be combined with status"
  ],
  "testPlan": [
    "Test migration of existing Todos to medium",
    "API test that rejects a disallowed priority",
    "End-to-end test of priority display and filtering from the UI to the API"
  ]
}
```

There are now zero unanswered questions. `confirmedByHuman`, however, is still `false`.

Receiving answers and receiving permission to proceed with implementation are separate states.

## "Use Color and Text" Was Still an Ambiguous Acceptance Condition

One generated acceptance criterion said, "The list displays priority with a badge that uses both color and text." That wording does not establish whether a user who cannot distinguish the colors can identify the priority from the text alone. I added another criterion through the interface: "Priority can be distinguished by text without relying on color."

![Interface after four answers were incorporated into the structured requirements and a human edited the acceptance criteria, still stopped while awaiting confirmation](/images/posts/todo-cms-change-request-confirmation/02-human-edited-requirements.webp)

The interface allows a human to edit the change summary, expected state, acceptance criteria, and test plan. Saving any edit resets the confirmation state to `false`, even if an earlier version was confirmed. Otherwise, approval of old content could remain attached after the requirements changed.

After applying the four answers, I called the change-job creation API again. The server stopped with "Human confirmation of the change requirements is incomplete." Together with the unanswered-question case, the server-side start conditions had now blocked the process twice.

## A Disabled Button Cannot Stop a Change Job by Itself

When the user selects "Confirm these requirements," the server checks:

- All required fields are present
- `openQuestions` contains zero entries
- The acceptance criteria and test plan are not empty
- A human has reviewed the current content

Only after all four conditions were satisfied did "Start change job" issue one job ID.

![Interface showing two pre-confirmation stops, zero code-AI calls, and a single job ID issued from confirmed requirements](/images/posts/todo-cms-change-request-confirmation/03-confirmed-job-gate.webp)

The part-two job stops at `queued_for_next_phase`. The code-modification AI has been called zero times, and the runner that would apply and test a generated proposal has not started. This verification confirms that only confirmed requirements can pass into the later stage.

Disabling buttons reduces accidental operations, but it does not form a safety boundary. The change-job API must recheck the confirmation state and record rejection reasons in the audit trail so the same conditions apply to calls made outside the interface.

## Testing Both "Add a Due Date" and "Make Todos More Useful"

An interface that works only for priorities cannot handle other requests. I passed a due-date change and an underspecified request through the same start and stop conditions. The verification logs record priority as S01, due date as S02, and the underspecified request as S06. The numbering jumps from S02 to S06 because this verification selected three cases from a ten-case plan. S03 through S05 cover tags, CSV export, and other requests planned for later articles; they were not run here.

| Modification request (scenario ID) | Initial questions | Unanswered | Unconfirmed | Job after confirmation | Code AI |
|---|---:|---:|---:|---:|---:|
| Add priority (S01) | 4 | Stopped | Stopped | 1 | 0 calls |
| Add due date (S02) | 3 | Stopped | Stopped | 1 | 0 calls |
| Underspecified request (S06) | 2 | Stopped | Not reached | 0 | 0 calls |

For the due-date request, the interface asked whether the field should contain only a date or include a time, which time zone should determine expiration, and how completed Todos should be treated. The human answers were "date only," "Asia/Tokyo," and "exclude completed Todos from overdue results." After these three points were recorded in the acceptance criteria and confirmed, the server issued a job ID.

The underspecified input was "Make Todos more useful." The interface asked who was struggling with which operation and what outcome would count as complete. I left both questions unanswered and called the change-job creation API.

The result was zero jobs. The deterministic transformation did not choose priority, due date, tags, or another feature on the user's behalf.

## Reproducing the Same Stops

`npm run verify:change-requests` is a custom verification script prepared for this article. It feeds three fixed requests and their answers into the Change Request management logic. The script checks rejection while questions remain unanswered, rejection while requirements remain unconfirmed, the number of jobs issued after confirmation, and the fact that neither the code-modification AI nor the runner executes.

```bash
npm run verify:change-requests
```

```text
S01: queued, jobs=1, providerCalls=0
S02: queued, jobs=1, providerCalls=0
S06: needs_clarification, jobs=0, providerCalls=0
```

`queued` means waiting for the next stage, and `needs_clarification` means waiting for answers. `providerCalls=0` confirms that the code-modification AI was not called.

The server stores conversations and Change Requests in a JSON file, so questions, answers, manual edits, and stop history remain after a page reload. This storage mechanism is for a local proof of concept. A multi-user environment in which several people can update the same request would require a database and version checks to prevent stale writes from overwriting newer content.

## Predefined Questions Cannot Evaluate AI Question Quality

In part one, live responses from Sakura AI Engine, Cloudflare Workers AI, and Google Gemini were normalized into the common `requirement-plan-v1` format. This verification does not call an external API. It uses a predefined transformation for the three requests so that the same questions appear on every run. The implementation calls this component `deterministic-scenario-adapter`.

This separation makes the state transitions easier to test. If questions vary on every run, it becomes difficult to tell whether a failure belongs to the change-job gate or to missing questions. Fixed requests and questions make the "unanswered," "answered but unconfirmed," and "confirmed" states reproducible.

Stopping on predefined questions does not show that a live AI can generate the necessary questions. Question quality for unrestricted change requests, follow-up questions after an answer, and handling contradictory answers remain unverified.

## The Change Job Still Has No Code Change Behind It

For both priority and due-date changes, the server rejected job creation while questions remained unanswered and while the requirements remained unconfirmed. It issued a job ID only after a human edited and confirmed the requirements. The underspecified request stopped with unanswered questions instead of selecting an improvement automatically.

The decision for part two is therefore **Conditional Go**. Change Request state management and the server-side start conditions worked from conversation through confirmed requirements. The quality of questions generated by an external AI API and the ability to complete a real code change from an issued job remain unverified.

Can the runner start from a confirmed Change Request and repair the three test failures from part one? Whether the dedicated interface can reach a completed code change depends on that next result.
