WritingAI and agents
Build a software factory around the whole delivery loop
Follow a bug from its first report through an approved plan, a tested change and human review. Then use what happened to improve the next run, instead of stopping at another merged PR.
11 min read
Say a teammate needs a CSV export for a demo, but a comma in a note breaks the file. The same bug turns up in Slack. An agent can write a fix, but someone still has to connect those reports, decide what correct means and check the result. I want to follow that whole route, including what changes before the next bug arrives.
The reports and CSV values here are made up. The supplied exercise runs fixed local code, not a coding agent. Its test output is from a real local run. The workflow documents describe decisions a real team would make, not approvals already given.
For me, a software factory is useful when it improves the whole delivery loop, not just how quickly an agent opens a pull request.
By software factory, I mean the setup that carries a request through a coding agent, review and delivery, then feeds what happened into the next run. I'm following the work between those steps. The existing agentic SDLC article covers intent and ownership at those boundaries. Here the same CSV bug travels through them.
The work starts before the prompt
A report can come from a customer call, a chat message, failed CI or a note pinned to the interface. That is input for investigation. It is not automatically permission to change the product.
Start by looking for an existing issue or open PR. If the export bug is already being fixed, attach the new report there. Keep the second person's evidence without making another implementation of the same fix. If the reports only look similar, leave that uncertainty visible for the owner to resolve.
The intake record keeps this decision small:
issue: csv-cells
reports: demo-report, chat-report
duplicate decision: attach chat-report to csv-cells
owner: export maintainer
risk: low, no permissions or critical request path change
triage: confirm the bounded fix before buildOne agent organizes the requests and their dependencies. Another, the worker, gets a specific change to finish.
Risk changes the route. This example labels the isolated CSV fix low risk because it changes neither permissions nor a critical request path. If investigation finds either, or the scope is uncertain, an engineer decides what happens next. Plan approval and PR approval stay separate.
The marker follows the report and pauses at human decisions. Reduced motion keeps the complete graph still. Static fallback.
Decide what the fix has to prove
Testing and design come first for me. “Fix CSV export” is too loose to check. Acceptance criteria are the specific behaviors a person agrees the change must satisfy.
For this exercise, the ticket fixes those behaviors before implementation:
AC1: a comma remains inside its original cell
AC2: an embedded newline remains inside its original cell
AC3: a literal double quote survives parsing unchanged
AC4: empty cells remain empty cellsEach criterion points to a named test. The test compares parsed cells with explicit expected values. It does not compare the exporter with another copy of its own string-building logic.
A person owns the target, even when an agent drafts it. A study of spec-driven development recommends that people write or approve acceptance criteria. Participants reported more reliable agent behavior, but they could not separate that from model improvements. Those are associations, not evidence that specs caused the improvement.
The plan names the proposed implementation: replace the faulty exporter and run the tests. It also keeps spreadsheet-specific behavior outside this fix.
A human plan gate checks that scope before a worker starts. If investigation changes what “correct” means, bring the criteria back to their owner. Do not quietly weaken them while fixing a red test. Larger changes can split proposal, behavior specs, design and tasks into separate files. This CSV fix does not need a framework installation to make those distinctions clear.
A spec can also become another file nobody maintains. Update it when intended behavior changes, and record why. An old plan should not quietly become today's instructions. A failing check does not settle which behavior is right. The owner still chooses whether to correct the implementation or update the spec.
Give the worker a repo it can check
The agent still needs a place where wrong work gets useful feedback. Keep a feature's tests near its implementation. Use types where they expose mismatched interfaces. Make lint and test commands easy to find, and keep the required CI checks quick enough to use during a repair.
For me, the instruction file is advice and the check is enforcement. The instruction can ask an agent to use a CSV library. The parsed-cell test catches the broken result even if the agent ignores that advice.
The complete example needs only Python's standard library. Its deliberately broken exporter joins cells with commas:
def export_csv(rows):
return "\n".join(",".join(row) for row in rows) + "\n"For a cell containing ready, set, that comma becomes a column boundary. An embedded newline becomes another record. From the example directory, reproduce it:
EXPORTER_IMPL=exporter_broken python3 -m unittest -v test_exporterThis excerpt from the failing run shows what the selected cases caught:
test_embedded_newline (test_exporter.ExportTests.test_embedded_newline) ... FAIL
test_empty_cells (test_exporter.ExportTests.test_empty_cells) ... ok
test_literal_quote (test_exporter.ExportTests.test_literal_quote) ... FAIL
test_quoted_comma (test_exporter.ExportTests.test_quoted_comma) ... FAILThe same log shows the parsed values in these two assertion excerpts:
AssertionError: Lists differ: [['Ada', 'ready', ' set', 'demo']] != [['Ada', 'ready, set', 'demo']]AssertionError: Lists differ: [['Mira', 'ready', 'demo']] != [['Mira', '"ready"', 'demo']]The comma case produces an extra cell. In AC3, the unescaped double quotes are read as CSV quoting and stripped, so "ready" comes back as ready. That run executed four tests and failed three. The corrected exporter delegates quoting to the CSV writer:
import csv
import io
def export_csv(rows):
output = io.StringIO(newline="")
csv.writer(output).writerows(rows)
return output.getvalue()The writer marks the cell boundaries instead of assuming every comma separates cells. Run the acceptance tests and artifact checks together:
python3 -m unittest -v test_exporter test_artifactsThe recorded result, using Python 3.13.5, ends with:
Ran 10 tests in 0.001s
OKFour tests cover the chosen cell cases. Six check the combined fixture and handoff files, including the risk decision and relative file paths.
A real worker follows the reproduce, fix and test sequence inside its execution environment. That environment must restrict access independently of the test result. Passing a CSV test says nothing about whether a process can reach production credentials.
A plan saying “only touch the exporter” cannot stop a process reading another service's data. Enforce that outside the prompt: give it an identity with limited access and an environment that blocks the systems it must not reach. The source of installed dependencies needs controls too.
Pass evidence forward, not the whole conversation
A reviewer needs the requirements, the changed code and the checks that matter to this task. Sending the entire planning conversation makes the reviewer sort through information the builder already used.
The clean handoff packet points to files rather than retelling the session. Its core looks like this:
{
"criteria": "ticket.md",
"plan": "plan.md",
"changed_files": ["exporter.py"],
"evidence": ["evidence/red.txt", "evidence/green.txt", "evidence/source-manifest.json"]
}Paths resolve from the example directory. A separate review agent can inspect the change against the criteria with fresh context. Asking the builder to grade its own reasoning can carry the same mistake into the review. CI failures go back to the worker. Review findings go back with a concrete reason, then the checks run again. A disagreement about intended behavior needs its owner, not another automatic rewrite.
This baseline requires a human PR decision before merge. Low-risk automatic merging is another possible policy, but it has to be granted explicitly. Green CI and agent agreement do not grant it. The decision card keeps evidence separate from permission.
If review becomes the bottleneck, limit the work waiting for it. An increasing pile of unread PRs is a reason to slow new work, not add another coding session.
After merge, improve the product and the factory
Merge is followed by your existing release process and checks on the resulting behavior. A fresh failure can become another input. After release, tell the teammate waiting on the demo which export changed and what was checked. The release ownership article covers who may authorize that step.
There are two different things to improve here. A CSV defect changes the product. A repeated omission in the worker's approach may call for a change to the factory. Those deserve separate proposals, because changing the instructions or checks affects future work too.
A new product request goes back to intake. An approved factory change alters how the next build runs.
The review-to-rule entry makes that second change visible:
finding: delimiter joining loses cell boundaries
product fix: use csv.writer
proposed guidance: use a CSV library for this export
enforced check: keep the parsed-cell tests in verification
human decision: pendingThe last line leaves the decision with a reviewer. A written note can explain why delimiter joining failed, but the parsed-cell test catches the mistake next time. Review its scope before requiring that check on future changes.
When the same failure repeats, group the run records before proposing a change. Link them to the proposal and its check. The factory can help find that pattern. It should leave a reviewable change, not silently edit the rules under its own work.
For a deeper next step, preserve a successful task and its checks as an eval: a saved task used to check future agent runs. The candidate manifest keeps the request and expected behavior available for a later model or configuration comparison.
Keep criteria fixed during that comparison. Otherwise a candidate can appear better because the target changed. The source hashes also let a reader detect changes since this recorded local run. They are not a signature or a substitute for trusted CI evidence.
Start small enough to see whether it helps
I would start with one low-risk path I can inspect end to end, then earn the right to automate more.
For csv-cells, the export maintainer reviews the generated file and the test evidence. Then the person waiting for the demo can try the export again. If either needs a long explanation from the coding session, the handoff is missing something.
Record where this change spent its time. A patch that waited for review needs a different improvement from one that failed the same test repeatedly. The blank record separates review waiting from total elapsed time and leaves cost empty until it has been measured.
Once a few real changes have used this route, compare the effort per finished fix with how many useful fixes reached release. Also count the fraction of merged PRs that used the route. That fraction measures adoption, not quality. The earlier SDLC article's green but incorrect publishing change is a reminder to inspect what those PRs actually delivered.
There is no need to move every kind of work into this path at once. Give the maintainer a way to send another export report into it and inspect the result. Keep the request, test command and review record as separate files, so replacing the coding tool does not require rewriting the meaning of the task. Let that narrow path get useful before expanding it.
This is one routine bug path, not a production orchestrator. Team policy and risk determine the gates. The local exercise does not test models, deployment or sandbox isolation. The study's reported reliability gains are not causal proof, and a tiny change may need much less paperwork than this teaching example.
Pick one routine task. Write down its human-approved criteria, carry the test evidence into review, and propose one specific improvement for the next run. You should be able to open the files and see why the change could move forward.
Newsletter
No comments yet.