>the whole loop

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

##We used to process one piece of work at a time. Now we run the whole loop.

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

  • big featuresa prototype, a PRD, a Figma file, or the transcript of a customer meeting
  • customer feedbacksupport tickets, and the questions that come back from the field
  • production signalsevery new error signature the soak finds after a release, while people are still testing
  • compliance and securitynew requirements as zero-days are reported and as audit findings land

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.

continuous intakefeatures · feedback · production signalscompliance and security findingsintakeprototype · bug · zero-dayreadrows with permanent IDswriteone lane, or a draintestcases derived before codedeploygo / no-go cardmonitorsoak · release ledgerfeed backretro → prompt text

02 · continuously retrospecting

##The telemetry is what makes continuous retrospection possible

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.

July 23 · field report no. 1

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.

August 27 · field report no. 2

the run measures itself

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.

open on August 27

measured QA outcomes, and a deploy stage

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

##Trivial intake takes one lane, from intake to a pull request

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.

  1. triageinvestigate · classify · brief
  2. newtest-caseswhat done means, in QA's format
  3. one human pausespec state · clarity · autonomy level
  4. planresearch team → plan
  5. debatefive adversarial lenses
  6. prreview · PR · merge
compound-master · the nine-step spine every lane runs
  1. db-syncreal data down
  2. ledger gateready, or refuse
  3. workstrike team + QA loop
  4. verifythe ledger, in a real browser
  5. reviewmulti-lens, read-only
  6. fixevery finding, then iterate
  7. learningsthe per-ticket retro
  8. autonomy dialstop · PR · merge

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.

L0
stop after the plan
L1
stop before the PR (default)
L2
open the PR, a human merges
L3
merge on green CI, light risk only

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.

level 1triage → test-cases → plan → debate → master → PRone lane

04 · level 2 · rising above the ticket

##When the intake is a prototype, a PRD, or a customer transcript

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.

  1. the raw intakeprototype · PRD · Figma · transcript, snapshotted as anchors
  2. spec-decomposeunits · blast radius · delta vs shipped
  3. scope gateI rule the units and the open questions
  4. spec-reconcile · spec-authormint immutable requirement IDs
  5. spec-to-ticketsvertical slices · dependency graph · telemetry manifest
  1. approve the epicnothing is created before this
  2. newtest-cases per ticketat mint, so every lane starts with its ledger
  3. forecast stampedin the manifest, gradeable after the run
  4. a graph ready to drainlevel 3
42min
a teammate's prototype walkthrough on August 18, captured as spec input
511
requirement candidates extracted by 13 autonomous readers in 25 minutes
351
rows authored overnight, then 70 tickets minted in 31 minutes with 129 edges
60 / 61
open candidates I ruled in one sitting on August 20, and the drain started that afternoon

##dividing the work so lanes do not clobber each other

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.

WS-J · flag & nav
2 tickets · the tracer bullet starts here
WS-A · config API
16 tickets · the schema
WS-C · list & editor frame
8 tickets
WS-D · option-one editor
8 tickets · option one
WS-E · groups
6 tickets
WS-F · applicability
3 tickets · built beside groups
WS-G · rule board
7 tickets · option two
WS-H · templates
9 tickets
WS-I · cross-site copy
7 tickets
WS-B · runtime chain
11 tickets · the deep chain

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.

units come from the source's own structure

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.

every ticket is a vertical slice with anchors

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.

fences are written before the wave starts

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

##Agents loop over the graph, and every node runs the whole single-ticket lane

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.

depth 0 · 4depth 1 · 9depth 2 · 13depth 3 · 11depth 4 · 11depth 5 · 12depth 6 · 8depth 7 · 4depth 8 · 3depth 9 · 2S-01S-02S-03S-04S-05S-06S-07S-08S-09S-10S-11S-12S-13S-14S-15S-16S-17S-18S-19S-20S-21S-22S-23S-24S-25S-26S-27S-28S-29S-30S-31S-32S-33S-34S-35S-36S-37S-38S-39S-40S-41S-42S-43S-44S-45S-46S-47S-48S-49S-50S-51S-52S-53S-54S-55S-56S-57S-58S-59S-60S-61S-62S-63S-64S-65S-66S-67S-68S-69S-70S-71S-72S-73S-74S-75S-76S-77
merged 0 / 75ready 3in flight 1lane 1lane 2lane 3Aug 20 · 05:45 UTC · wave 0 of 30
WS-A · config APIWS-B · runtime chainWS-C · list & editor frameWS-D · option-one editorWS-E · groupsWS-F · applicabilityWS-G · rule boardWS-H · templatesWS-I · cross-site copyWS-J · flag & navreadyrunning a lanemerged

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

##After the merge, the deploy is a command with a record and a named human at every gate

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.

  1. pre-flightread everything about prod, print a go or no-go card
  2. card GOrulings typed in words, approval by name
  3. launchAPI pipeline, then UI on green
  4. red stagea playbook: fix alone, or stop
  5. verifyre-read production against expected values
  6. soaka filtered watch while humans test
  7. close-outtag · ledger · release notes · learnings
autonomous

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.

waits for a named human

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.

the record

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.

##the deploy derives its own delta and asks for a go or a no-go

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.

pre-flight card · September 15 window9 tickets · 16 PRs · 7 migrations in the range
  1. VPN, subscription and privileged-role reads; point-in-time restore anchor recordedGO
  2. Last green run per pipeline read from stage results, commit ranges derivedGO
  3. Human approval gate exists on both production environmentsGO
  4. Mock-upstream flag empty on api, worker and beatGO
  5. Migration job runs as the managed identity with the DDL roleGO
  6. Default privileges grant the identity new tables and sequencesGO
  7. Live migration head read; expected head computedGO
  8. Ticket states for the nine tickets in range (two flagged, not blocking)GO
  9. Two migration heads on backend mainGRAY
  10. UI-alone rollback: both the API and UI contracts changedNO-GO
verdict: NO-GO · two checks need a human ruling
0
red pipeline stages on September 15; 19 of 19 automated rows passed
21
soak ticks over 5 h 43 min; two pre-existing issues found and fixed at source

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 agent checks, humans check, and the monitor checks, all in one file

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.

agent · automated rows

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.

humans · tester rows

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.

soak · monitoring rows

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

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

Sep 13
17 tickets · 74 PRs · 13 migrations
rebuilt after the fact

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.

Sep 15
9 tickets · 16 PRs · 7 migrations
first live run

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.

Sep 17
8 tickets · 16 PRs · 2 migrations
the loud one

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.

Sep 18
5 tickets · 10 PRs · 0 migrations, plus two sibling products
three products in one window

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

##Every run is retrospected, and every finding changes the next run

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.

monitor · Sep 15

The soak caught a deprecation warning and an unreadable contract file, both older than the release.

intake · Sep 16

Two fixes went through the single-ticket lane as two pull requests, with two learnings filed.

monitor · Sep 18

The next ledger's noise entries for both hit zero: the fixes are proven live by the monitor that found them.

QA · Aug 25 to Sep 10

37% of tickets reopened, twice. A 22-agent retro traced 12 of the 35 reopens upstream of ticketing.

pipeline · Sep 11 to 12

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.

intake · every ticket since

Test cases derive at triage and at mint. One ticket ran the new lane, 50 of 50, and deployed on the 18th.

drain · Aug 20 to 24

The mint proposed 53 human gates and the run needed 3. Risk labels predicted nothing: Heavy reopened at 35%, Light at 37%.

retro · Aug 24

Gate calibration, coverage lint after every authoring pass, and a git ground-truth check on lane claims.

mint · next epic

One policy-level gate with a trigger and an expiry instead of 47 per-ticket clones, and the lint re-runs on every pass.

continuous retrospectionlearnings · spec rows · test casessoak signals · gate calibrationintakeprototype · bug · zero-dayreadrows with permanent IDswriteone lane, or a draintestcases derived before codedeploygo / no-go cardmonitorsoak · release ledgerfeed backretro → prompt text

08 · where do we go from here?

##The promise I made on stage, and what would falsify it

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.

read the case studies and click through the drain graph →the nine principles and the five artifacts →

##contact

// get in touch
[loc]
Redondo Beach, CA

// open to roles and engagements building AI SDLC · enterprise engineering teams · AI labs