Skip to content
Home / System / Shipping software
Shipping softwareIn use since Aug 2026

How I ship software I did not write.

AI writes the code; these rules are what make it safe to ship for a real business. Each one exists because something went wrong once and was written down so it cannot go wrong the same way twice.

01The gate

Eight steps, in this order.

AI writes the code. The gate is what makes that safe to ship for a real business: a fixed sequence in which the three human steps and the one hard stop cannot be moved.

01 · me
Spec
Rulings recorded, with dates
02 · model
Build
From the spec, nothing else
03 · model
Review
A model that did not build it
04 · me
Read-back
I check the changed screens
05 · hard stop
Backup
Before any stored data changes
06
Staging
Installed, tested end to end
07 · me
Sign-off
Screens, not reports
08
Live
Rollback zip kept
My seatA model'sCannot be skippedA version that misses any step is not done
00Before the gate — the intake
00 · intake
A row, before anything else
Raised → Clarified → Planned → Built → Live, or Dropped with the reason
What went wrongEarly in the project a cancel function for single classes came up in a working session and I moved on. Weeks later the owner asked me for exactly that, and I remembered it had come up but could not find where it had gone: it was in a chat log, not in any plan. On 24 September 2026 it happened again while I was queuing two versions. That was the trigger: from that day every idea becomes a row in one database the moment it is raised, and the roadmap is built only from rows. The gate above starts at Clarified.
One idea, timed24.09.2026 · 13:47–15:25

A request does not become a build. This record shows an idea becoming a ruled, scheduled change in one afternoon, and the database catching that the idea reversed an earlier ruling. The request: the studio owner, the afternoon the new admin screens went live, wants a phone number on trial-class bookings so she can call when a class is cancelled.

13:47
Idea
Row created in the same minute it was raised. Raised by: the owner.
13:50
Idea
Mockup of the one screen it touches: the bookings list for a date, with the new column, in four states including “cancelled, one mail failed”.
13:56
Clarified
Five rulings from the mockup (required on the public form, optional in admin, trial classes only, „(Eltern)“ on children's classes, shown on one screen only) and the four questions: fails halfway, not built, ship day, undo.
14:00
Planned
A version slot, right after the version already in review.
15:25
Planned
Moved to slot 1.11.24, behind four versions that were queued first; the 14:00 slot withdrawn and written down as withdrawn. The row also records that this reverses a ruling from 15 September (“no phone field on trial bookings”), and that I confirmed the reversal.
—
Built
Not yet. Its turn comes when the versions ahead of it are live.
—
Live
Not yet. The privacy notice changes in the same hour it does.

Thirteen minutes from raised to planned, and another ninety to find out I had ruled it out nine days earlier. Zero minutes of code. That gap is the point: deciding is cheap, undoing is not.

What this establishes: nothing enters the gate unrecorded, and a reversal is caught before a build. What it does not: that the change is a good one. That is decided at the gate.

Idea8→Clarified8→Planned9→Built1→Live1→Dropped1
The board, 24 September 2026, 15:23: 28 rows in six columns, one live. Each bar is one row; dashed bars are still ideas. Drawn from the database; the details column is not shown, and one client's name and two detail cells are blacked out in the captures. See the board ↗︎ · See the table ↗︎

The row that is still “Idea” two weeks from now is the one to worry about, not the one that took thirteen minutes.

The other list. Not everything owed is a feature. A restore rehearsal, a password rotation, a privacy text, one real test booking — none of them belong on the ideas board, and each of them used to live in a chat log or in my head. Since 24 September they are rows in a second database, Plugin Chores: area, owner, status, and the version they block. Three of thirteen block something today. A version with an open blocking chore does not leave the gate.

What this establishes: that owed non-feature work is written down with an owner and a stop. What it does not: that the chores get done — the status column is the only proof, and today it reads eleven “to do” and two “waiting”.

ChoreAreaOwnerBlocks
C-8Code-literacy read for 1.11.21waitingReleaseMeiliMeili1.11.21
C-1Full restore rehearsal of the new live siteto doSafetyMeiliMeili1.11.22
C-10Publish the privacy text for the phone numberto doReleaseMeiliMeili1.11.24
C-3One test booking on liveto doTestingMeiliMeili—
C-2Owner's user test of 1.11.18–1.11.20 on liveto doTestingOwnerOwner—
C-11Find out what “IONOS wasn't working” meantto doTestingMeiliMeili—
C-4Backups: encrypted image only, delete unencrypted copiesto doSafetyMeiliMeili—
C-5to doSafetyMeiliMeili—
C-13Help file (German) for the owner's ChatGPT projectto doReleaseTerminalTerminal—
C-9After 1.11.21 is live: schedule block back on the homepagewaitingReleaseCoworkCowork—
C-6Plugin clean-up, second batchto doClean-upMeiliMeili—
C-12Update the product-hardening-protocol skillto doClean-upCoworkCowork—
C-7Newsletter page is missing its shortcodeto doSite contentCoworkCowork—
13 chores3 block a version11 to do · 2 waitingOwners: Meili 8 · Cowork 3 · Terminal 1 · Owner 1 (Cowork and Terminal are the two AI sessions that carry work)
Plugin Chores, 24 September 2026, 17:13. Blocking chores first, then by area. Titles shortened; one chore title and the details column are not shown. See the table ↗︎
02Before stored data changes

Four questions, answered in writing.

Asked before the plan review runs, for any version that changes what is stored. The answers become rulings the build has to honour.

  1. What happens if it fails halfway?
  2. What is deliberately not built?
  3. Who does what on ship day?
  4. How is it undone on live, and what does that lose?
03Rules that were not designed

Three mistakes, turned around.

None of these was planned. Each is the shape of one thing that went wrong, written down so it cannot go wrong the same way twice.

A fix on a failing path re-runs the full suiteA fix that touches the code path that just broke does not ship the night it is written.
What went wrong

Quick Edit wrote a teacher's id as 0 and a class lost its teacher without an error. The fix touched exactly the failing path, so every acceptance test was re-run the next morning before it shipped.

The reviewer is never the builderAnd a claim about the database is verified with a query before it enters a spec.
What went wrong

A reviewer reported the sign-up tables missing. It had checked plural names; the plugin's are singular — a confident wrong claim from a model that had never queried the database.

A parked ruling goes on the backlog the same dayA version number without a backlog line is a ruling waiting to be forgotten.
What went wrong

A mobile layout was ruled, given a version number and never built. The ruling lived in a document nobody re-read until the owner asked where it was.

04One real read-back

A sign-off, as recorded.

Step 07 of the gate for version 1.11.17, the cancellation mail, the evening before the site went live. I checked the flow against the booking table and the mail markers, step by step. The record, as written that night; only the test addresses are shortened.

1.11.17 — staging verification22.09.2026 · 19:40–19:46 · logged in

Installed after a database backup. Plugins page reads 1.11.17, active. Fixture: class 174 „Ballett für Kinder“, date 19.10.2026 — far future, 0 bookings before and after.

Two bookings via the real REST path (Testperson A, Testperson B)
2 von 12, both rows „online“
Tick „Dieser Termin findet nicht statt“, before saving
„Beim Speichern bekommen 2 Personen eine E-Mail, dass der Termin ausfällt: Testperson A, Testperson B“ — R4 as ruled
Save with reason „Testlauf 1.11.17“
„Termin abgesagt. 2 von 2 Personen wurden per E-Mail benachrichtigt.“ — N1’s „N von M“
Booking table
both rows show „verschickt 19:41“ — R5
Un-tick and save again
„Dieser Termin findet wieder statt. 2 von 2 Personen wurden per E-Mail benachrichtigt.“ and the markers are cleared — R8, as ruled
Cleanup
both test bookings removed; the date reads 0 von 12 and is not cancelled

No PHP notice, no admin error anywhere in the flow.

Not verified
  • The mail bodies. The mail log recorded nothing for these sends; the plugin reports success per row. I check my inbox for the four mails — that is the only reading of the actual German.
  • A failed send and the resend button. Needs a deliberately broken address; no time before the cutover. After live, or on the next staging clone.
  • The 375 px rendering of the new column.

R4, R5, R8 and N1 are the rulings the spec carried; the read-back checks each one by name. What it establishes: the four rulings behaved as ruled, on staging, with real bookings. What it does not: that a failed send recovers, or that the mails read well — neither was tested that night, and the record says so.

05One real ship day

A version going live, as recorded.

Steps 05 to 08 of the gate for version 1.11.18, the new settings overview, the day after the site went live. The release was a backup, a decided undo, a read of the changed code, an upload and five checks. Times are the tools' own timestamps; nothing is rounded.

1.11.18 — live install24.09.2026 · 13:04–13:37 · kayjays.de

Live was running 1.11.17. The host's own daily backup existed (23.09, 17:49, kept 14 days). What follows is the version's own backup and the undo, then the upload.

13:13
05 · hard stopDatabase export, all tables
9,310,977 bytes, 328 tables, file ends cleanly. Fingerprint noted. Moved into the encrypted image at 13:32; the copy there has the same fingerprint.
13:20
08 · undo, decided firstCompare the 1.11.17 and 1.11.18 zips
Both open without errors. 13 files differ, all of them code; no table, no new stored field. So the undo is re-uploading 1.11.17, and it loses nothing. Written down before the upload, not after.
13:25
04 · meRead the changed code: Settings.php, lines 166–245
The version's one behaviour change: a settings save that cannot say which screen it came from now saves nothing and asks for a reload; before, it could reset every setting. Read line by line before install, question answered in my own words.
13:36
08 · liveUpload through wp-admin
WordPress shows the comparison 1.11.17 → 1.11.18, same author, same PHP floor. „Installiertes durch Hochgeladenes ersetzen“ → „Das Plugin wurde erfolgreich aktualisiert.“
13:37
07 · meScreens, not reports
Plugins page: 1.11.18, active. Home, /stundenplan/, /probestunde/ all 200, no raw shortcode, no PHP message; 8 booking-deadline badges and 28 „Anmelden“ buttons still render. Admin menu shows the five new screens; the old settings page points to where each one moved.

On the live site, from upload click to last check: under two minutes. Before that: thirty.

Not verified
  • A booking on live. Nothing in 1.11.18 touches bookings. By the evening of 24 September the owner’s parents had made 21 sign-ups through the public forms as a test — the first real load on the booking path, though not one I made myself.
  • The owner's read. The owner has not yet opened the new overview while I watch. Her first questions decide what the next version fixes first.
  • A full restore of the new live site. The 23.09 rehearsal restored the old site's backup. Because 1.11.18 stores no data, the undo check above stood in for it today. The full rehearsal is due before the first post-launch version that changes stored data.

Backup, undo, read, upload, check: the order is the gate's. What it establishes: the version can be taken back without loss, and the public pages survived it. What it does not: that booking works on the new version — no booking was made. The third “not verified” item is a substitution I made on purpose and dated, so the next version cannot inherit it silently.

AI wrote the implementation. My part was to define what should happen, check what did, and decide whether it could run in a business. In use on a scheduling plugin live since 23 Sep 2026: eleven versions in September, nine defects caught before code existed, zero rollbacks.

The plugin case study ↗︎
06 — Contact

Discuss an in-house role.

meililwyss@gmail.com ↗︎ Back to the system ↗︎