Self-reinforcing quality / adopting verification pattern
After implementing the small-change pattern, Imprint Engineering’s next focus
in improving our development loop has been
implementing a verification loop for our software development. This is an increasingly common
pattern, particularly popularized by poteto’s pstack,
but you’ll find similar ideas emerging in other places as well, e.g. Niko Matsakis’ post on
the correctness ratchet,
among others.
This captures some of the confusion I’ve seen in our initial rollout, and the particulars of how we are implementing the approach.
What verification pattern is, and what it isn’t
The verification pattern suffers from confusing naming: when you tell a team that you’re planning to roll it out, they’ll often ask you what mechanism you’re using to verify the codebase, don’t we already have tests, linters and so on?
However, the verification pattern itself is more similar to the
chain-of-thought pattern,
which aims to steer the harness towards your desired outcome in a clear way.
For example, we require that each pull request generate a verifications/{pr_num}.md file
that describes each step the harness took to verify the changes, and also what
it was unable to verify.
You can argue that your harness was already performing these steps, but it’s actually hard to say whether it was or wasn’t. My sense is that it often wasn’t happening: I’ve seen too many pull requests go to CICD that had failed basic lints that could have been run locally to believe the harness was always running them. Now the harness has to explicitly document that it’s done those steps, or acknowledge it hasn’t. This allows the harness to self-drive more effectively.
Equally importantly, this generates a renewing source of data about where your harness is struggling to verify its work. That list is your roadmap for improving the ability of your harness to self-drive work more reliably over time.
Our verification loop

The core of our verification loop is five steps:
- Implement something that you’ve identified or that has been identified by an automated system to resolve. Let’s say addressing a new error that’s shown up in the logs.
- Create a pull request containing that work after your harness has verified it locally.
Pull requests cannot be moved from
drafttoreadyuntil they have averifications/{pr}.mdverification file available - Provide feedback on the pull request, at minimum from our
ai-code-reviewtool that automatically reviews all pull requests, but potentially also from humans - Incorporate and reject feedback on the pull request. For low quality feedback, we explicitly dismiss it using a
/dismiss {reason}syntax in the pull request comment responses - Maintain our systems on a daily basis by pulling in the above steps to improve our software:
- Use pstack’s
/maintain-verification-skillskill to update the feature maps and tools used based on what has changed and where verifications have run into issues. Automatically generate a pull request with these changes for review - Review all verification files to identify where they struggled to verify, and generate issues for review that would reduce those gaps
- Review which feedback from
ai-code-reviewwas incorporated and which was rejected, tightening up its guidance
- Use pstack’s
This is working pretty well for us so far, typically each of our major code areas (frontend, backend, data, and native) wakes up with 4-6 pull requests to review as output of this process, improving our codebase’s correctness while we sleep.
feedback tool
The above feedback loop still misses meta-issues in our CICD and testing patterns.
To address that, we’ve implemented the feedback tool pattern described by
Teddy Riker in Designing for Agents,
which has worked very well for us with respect to addressing places where CICD and harnesses themselves are
failing above the level of verifying a specific pull request.
feedback and verifications are complementary, not competing, techniques.
For example, if the container’s runner crashed before completing, the feedback tool would often
report on this issue, whereas the verification file wouldn’t even get generated.
Explore (raise ceiling) vs exploit (raise floor)
One of the fundamental tradeoffs in how organizations approach AI adoption comes down to an explore vs exploit tradeoff. When you explore by having the full team do its own thing, you explore for ideas which can raise the ceiling, but when you centralize you raise the floor by ensuring everyone gets better PR review and better tooling.
The other related–and extremely open–question is whether exploration tends to over-optimize for the particulars of a given individual or team’s preferences, which often reduces cohesion across a codebase. At this point, I think of misaligned guidance as “context poison”, and am pushing hard to eliminate duplicate guidance on any topic, to ensure we have consistent, cohesive direction.
So far, our approach is running this as a centralized process for our repositories, building a single, continually improving, corpus for each area using the self-reinforcing loop built around the verification pattern. I think it’s working well for us, although certainly I’ll admit that there’s some skepticism about how far we go towards centralizing, and I think that skepticism is warranted: we do want to continue exploring, even if we are primarily exploiting. The best techniques for AI-enhanced development in 2027 will be ideas that are mostly unknown today.