The first PatchFlow private-pilot migration did not travel in a straight line. That is precisely why it was useful.
We selected a repository we own, pinned one transition—TypeScript 5.9.3 to 6.0.2—and named one customer-owned GitHub Check, smoke, as the verification boundary. PatchFlow could inspect the repository, ask a bounded coding agent to make the upgrade, and open a draft pull request. It could not merge.
The measured result
The coding-agent attempt completed in roughly three minutes and reported 83.43 cents of execution cost. The resulting draft pull request changed 16 files. It pinned TypeScript 6 across the workspace, added explicit Node and Vite types, and adapted the configuration for TypeScript 6 defaults.
Local verification reported:
| Gate | Result |
|---|---|
| Workspace typecheck | 9 packages passed |
| Tests | 33 tests passed before the baseline repair |
| Builds | Web, admin, and marketing passed |
| Required GitHub Check | Failed |
That last row mattered more than the first three.
The failure was real—but not caused by the migration
The smoke workflow failed all three offline agent fixtures with an empty error. We reproduced the same failure on the exact pre-migration commit. The TypeScript change had not caused it; the repository's smoke harness already depended on tenant/database state despite calling itself offline.
It would have been easy to wave that away. A migration product cannot do that. The named check is the repository owner's boundary, not a suggestion.
We fixed the harness separately. Offline runs now avoid tenant storage and use deterministic in-memory tools. Its own pull request passed the hosted smoke check, was reviewed, and merged before the TypeScript branch was refreshed.
A false green we had to remove
The pilot also exposed a PatchFlow defect: the run was initially recorded as having an open PR before the required check had settled. That state was too optimistic.
We changed the control plane so a run becomes ready only after PatchFlow:
- resolves the draft pull request;
- records its exact head SHA;
- waits for every named check on that SHA;
- fails closed on missing, pending, cancelled, or failed checks; and
- persists the settled verdict and provider cost.
When the base branch later advanced with the smoke repair, the verifier rejected the stale relationship. We added a narrow recheck rule: GitHub must prove that the new base descends from the originally inspected commit and that the checked pull-request head contains the new base. The original policy was not replaced with “trust the latest.” It became an ancestry proof.
What finally merged
The refreshed TypeScript branch passed the hosted smoke check on its new exact head. PatchFlow reconciled the existing run without launching another paid agent. A human reviewed and merged the draft pull request.
The outcome was one completed migration, one repaired repository check, one hardened control plane, and a real cost measurement.
That is the standard we want for the pilot: not a perfect demo, but a bounded system that tells the truth when the path is messy.
What this does not prove
One repository and one migration do not establish broad compatibility. A passing smoke check proves only the configured check passed on the recorded commit. It does not prove untested behavior is correct.
The next migrations should deliberately vary the package, repository shape, and check topology. The goal is not a bigger automation claim. It is a larger body of measured evidence.