one loop and one graph
114 requirements authored before any code, 45 tickets, 2 parallel lanes, 8 human decisions, and about 35 hours from the first merge to the last. Its retro turned the friction log into fixes before the next run.
This is the AI SDLC drawn as one loop, with the animations from the talk. Until now the unit of work was one ticket. Since September 2026 intake, specification, ticketing, build, QA, deploy and monitoring run as one loop that retrospects itself continuously, so what comes out of the end changes the front before the next run starts. I gave this as the third field report to the engineering team on September 18, 2026, and every number on the page is counted from git and written in industry-portable terms.
01 · the shift
Until now the unit of work was one ticket. Take an intake, make a ticket, tell the coding agents what to build and how to test it, and ship it. That level still exists, and I define it carefully further down this page, because everything else stands on it.
What changed is that we rose above it. Intake, specification, ticketing, build, QA, deploy and monitoring now run as one loop, and the loop retrospects itself continuously: every run is measured, every measurement becomes a finding, and every finding changes a prompt before the next run starts. The recursive self-improvement that used to live inside one ticket's learnings now runs across the entire arc, and that broadening is what I mean when I say AI SDLC.
// the outer ring is continuous intake, through one door
The inner ring is continuous retrospection: learnings, spec rows, test cases and production signals all flow back to where the next piece of work starts, and a retro only counts once it has changed a prompt.
02 · continuously retrospecting
A retro needs something to read. Since August every run writes a manifest about itself, every ticket carries a ledger that every stage writes to, and every release leaves a record in git. So a retro is something agents can run over what is on disk, and I no longer have to reconstruct a run from memory to learn from it.
114 requirements authored before any code, 45 tickets, 2 parallel lanes, 8 human decisions, and about 35 hours from the first merge to the last. Its retro turned the friction log into fixes before the next run.
351 requirements, 77 tickets minted, 75 built across 30 waves in 6 days on 3 lanes, and a telemetry manifest the run wrote about itself at every mint. Its retro landed the same day as the last merge and proposed seven changes.
The August run stopped at merged behind a flag, so its retro had no QA actuals to read and no deploy stage to measure. Both are covered on this page, and the retros that read them changed the stages upstream.
QA returned 37% of the tickets, then 37% of the fixes, and three retros later that number has a cause and a fix. Four production releases have since run through a deploy command that did not exist in August, each one retrospected in its own ledger. Those two threads are the rest of this page.
The retro that traced the reopens ran ten analysis lenses and ten adversarial checkers over what was on disk, 22 agents in 43 minutes, with every claim marked measured or inferred. Its most uncomfortable finding was about retros themselves. Eleven of the first fifteen proposals from earlier retros had never reached a prompt, so they had changed nothing. Now a retro only counts once it has changed a prompt, and every proposal lands as exact before-and-after prompt text in the same pull request as the finding that produced it.
03 · level 1 · the single-ticket lane
I want to define this level carefully, because the drain and the deploy only make sense on top of it. A ticket, a bug, a question or an idea enters through one front door and leaves as one hardened change. The human is asked once, at triage, and the brief carries that answer downstream so plan, work and fix never ask the same question again.
The human pause happens once, at triage: is the spec right, is anything unclear, and how far may this run on its own. After that the lane runs the spine end to end and stops wherever the dial says.
302 triage briefs since July. Heavy risk, auth, migrations, billing, PHI and API-contract changes cap at L2. This lane ran a production change on September 16 and 17 with a 50 of 50 test-case ledger, and that change deployed to production on September 18.
04 · level 2 · rising above the ticket
A big artifact does not become one ticket. It becomes a graph of tickets with their dependencies, and there is a whole layer above the lane whose only job is to create that graph well. This is the difference between the two kinds of intake. Trivial intake runs the single lane you just saw, and large-scope, high-fidelity intake is decomposed, ruled on, minted and forecast before any lane starts, so that the lanes can then run without asking anyone anything.
The question is how to divide a big artifact into units that agents can build in parallel without stomping on each other's files, and without splitting requirements that belong together from a product point of view even when the code is far apart. Get it wrong and you get merge conflicts and regressions across lanes.
Ten units, 77 tickets, 129 blocked-by edges, a dependency-ordered build order. The unit names are scrubbed to industry-portable terms; the counts are from the run's own telemetry manifest.
I confirm the unit list before any fan-out, because a wrong list fans out an expensive, misframed map. Three readers always run across every unit: shared vocabulary, blast radius, and the delta against what already shipped.
A ticket names the spec rows it covers and carries file-and-line anchors into the prototype snapshot, so a lane reads the same truth the spec author read, and the PR gate can produce a fidelity receipt against it.
A scout maps each ticket's edits to file and line on current main, and the lead writes fence directives. Two tickets that contest the same region never run in the same wave; one waits and its map is banked.
05 · level 3 · the drain
Once the ticket graph is static, the drain walks it. A ticket whose blockers have all merged is ready. N lanes pick from the ready set, each lane runs the level-1 lane end to end in its own worktree with its own database, and when a ticket merges, the tickets it was blocking become ready. If one ticket blocks seven others, merging it frees seven, and those run in parallel.
This is the real August drain, replayed from the manifest the run wrote about itself, with the identifiers scrubbed: 77 tickets, 129 blocked-by edges, columns are dependency depth, colors are units. Four and a half calendar days play in about twenty-five seconds, so the flat stretches are two nights of machine sleep and one model-provider outage. The drain landed at 30 waves against a capacity bound of 29, and only the final wave had fewer ready tickets than lanes, so the lanes set the pace and the graph set the order. On this graph the critical path is 10 tickets deep, so it would keep about eight lanes busy before that path became the limit, and my laptop is why it got three.
06 · level 4 · deploy management new · 2026-09
Everything upstream is the pipeline you have seen. The deploy is the last command in that pipeline and the first input to the next plan, and that second half is the part I most want to land. Production deploy management is inside the flywheel now, so what the deploy and the soak find is distilled back into the repository as tickets, learnings and ledger rows, and the context concentrates there for the next run instead of living in someone's head after a release night.
Every read of production. Deriving the commit ranges and the delta of PRs, tickets and migrations. Printing the card. Queueing the pipelines once the card says GO. Verify, the soak ticks, every ledger event and checkpoint, the release notes and the ticket comment drafts.
Every ruling on the card, typed in words and stored with a name. The pipeline approvals. Any production write, SQL grant or cancel. The word that stops the soak. Posting anything to the tracker. The helper cannot do these, and the command text says so under every phase.
One release ledger per window, an HTML file committed to git. Every check is a row that states its expected value before it runs, every result is an append-only event with an author, and the final checkpoint plus a tag is the release. Nothing else holds release state: no server, no shared file.
The command shipped on September 14. Before it, a production deploy was a person at a keyboard with a checklist in their head, and the September 13 ledger had to be rebuilt after the fact from the run record. Four releases have run through it since, and the first live one is below, step by step.
Once tickets merge, the deploy command finds the last green run of each pipeline from its stage results, derives the exact commit range between that release and this candidate, and lists every PR, ticket and migration in it. From that it builds a pre-flight card, and a named human rules go or no-go before anything launches.
The first card was NO-GO, and that was the system working. I typed two rulings in words: roll back both or neither, and a one-line merge revision for the two heads. The second card read GO on all ten, and every production write still waited for a named human.
monitoring · the release ledger nobody had seen this before September 18
The release record is one HTML file committed to git. Every check is a row that states its expected value before it runs, so no row can pass by construction, and every result is an append-only event with an author. Three kinds of participants write to it, and the final commit plus a tag is the release record.
Health, catalog, flags, each pending migration, grants, the revisions, the UI entry bundle, the log service. Verified by re-reading production against the stated expected value.
One row per test case from each ticket's test-case ledger, or its acceptance criteria. Testers fill them in their own browser and export markdown, merged by author and sequence, never overwritten.
Every ten minutes the soak reads the service tags in the log service, subtracts the known-noise list and everything already seen, and turns each new signature into a row plus an event. Nothing is filtered silently.
// the soak on September 15, tick by tick
21 ticks over 5 hours 43 minutes. Two new signatures, both pre-existing in production, both fixed at source the next day.
// four ledgers in six days
The soak ran unrecorded while QA and I tested, so this ledger exists to close the record, and it is why the next three were written live.
0 red stages, 19 of 19 automated rows, 2 new patterns in the soak: an unreadable contract file and a deprecation warning, both fixed at source.
One red UI build stage caught and re-queued green, then 24 new patterns in the soak as an upstream validation burst hit the sync path. 107 events on 47 rows.
12 of 12 verify rows, 0 unmatched over 130 log records, the two September 15 fixes proven live by a noise count of zero, and the soak now watching all three products.
07 · every signal flows back up
Nothing found downstream stays downstream. In every one of these chains the signal came from the end of the loop and changed the beginning of it, and each step is a commit I can point to.
The soak caught a deprecation warning and an unreadable contract file, both older than the release.
Two fixes went through the single-ticket lane as two pull requests, with two learnings filed.
The next ledger's noise entries for both hit zero: the fixes are proven live by the monitor that found them.
37% of tickets reopened, twice. A 22-agent retro traced 12 of the 35 reopens upstream of ticketing.
QA's own rules became a shared file and a new command, and 9 of 27 retro proposals landed in one PR as exact prompt text.
Test cases derive at triage and at mint. One ticket ran the new lane, 50 of 50, and deployed on the 18th.
The mint proposed 53 human gates and the run needed 3. Risk labels predicted nothing: Heavy reopened at 35%, Light at 37%.
Gate calibration, coverage lint after every authoring pass, and a git ground-truth check on lane claims.
One policy-level gate with a trigger and an expiry instead of 47 per-ticket clones, and the lint re-runs on every pass.
08 · where do we go from here?
The reopen rate since the test-case ledger shipped has been about 15%, and the promise for the next full drain is 18% or lower on the first QA pass. I chose 18 rather than the 14 the arithmetic gives, because the causes behind the 35 reopens are inferred, and the last two numbers were 37% with confident stories behind both. What would falsify it is a drain of 20 or more tickets with green ledgers reopening above 18% on the first pass, and I will report the number either way.
I should also be plain about the limits of the evidence. This is one company, one stack, and one regulatory regime, and nine months of git history on a real HIPAA-covered product. The forecast has one calibration run behind it, and the deploy command has four windows. What I can say is that the loop is closed now, and that every finding on this page changed a prompt before the next run started.
// open to roles and engagements building AI SDLC · enterprise engineering teams · AI labs