Skip to content

Review and close

Where the review runs decides what it costs

Section titled “Where the review runs decides what it costs”

Run the adversarial review at the close and every defect it finds is close work by definition. It arrives after the sprint is nominally over, is repaired fast and late by whoever is still holding the context, and lands in the most load-bearing code in the project.

One measured run here delivered in five hours and took six and a half hours to close. Gate and test time across the whole close was about 70 minutes - roughly 18%. The rest was repair generated by a review that ran too late.

There was a compounding effect too: a review of the repairs then found nine more surviving mutants, because the repairs had been written fast, late and self-reviewed. Repairs made under close pressure are the least-reviewed code in a sprint, and they sit in the most load-bearing paths.

So the review moved to the delivery batch boundary - the point the project already commits on. Reviewed there, a finding is delivery work in the batch that caused it, priced against that batch, and fixed by a context that still holds it.

Open a span over the units a batch will land, and review it when the batch is committed.

Terminal window
# open the span as the batch starts
sprint.py review-batch --open US0560,US0561,US0562,US0563
# ... deliver ...
# record the independent pass and close the span
sprint.py review-batch \
--reviewer "the fresh context that did not write this" \
--author "whoever wrote it" \
--verdict APPROVE \
--findings "what was probed, and what was found - 'none blocking' is a finding"

Reviewer and author must differ. A self-review is the context that wrote the code agreeing with itself, and it clears nothing. A REJECT is recorded - the range was reviewed - but it clears no gate.

Any finding filed while a span is open is stamped against that span, so a sprint can report where its defects were found. Filed with no span open, the artefact says so rather than being silently attributed to the last one.

Scope is the unit’s declared Affects against the run’s base ref. Findings are sorted by origin - regression, newly introduced, or pre-existing - and that is decided by execution, not by impression. Only the first two block. Anything already true of the tree, or already recorded in an open bug or change request, is reported with its id and does not hold the gate.

This is what makes reviews discriminating rather than uniformly negative. An unjustified REJECT is as much a failure as an unjustified APPROVE, and only a bounded review can tell the two apart.

sprint.py preflight --retro RETRO0001

Read-only. It reports every unmet close prerequisite in one pass: the gate lanes, the retro’s missing sections, an unjudged goal, and the per-unit sign-off prerequisites. Those last ones otherwise surface only after the whole chain has passed, so a close used to take as many runs as it had unmet prerequisites, each costing a full gate run.

/sdlc-studio sprint close # scaffolds the retro, then stops
/sdlc-studio sprint close --retro RETRO0001 # the close ceremony as one chain
/sdlc-studio sprint close --retro RETRO0001 --apply-signoff --principal "You"

Run it with no --retro the first time and it scaffolds the retro for you - allocated id, template, index row, batch and goal pre-filled from the run - then stops so you fill it. Never hand-author a retro; the scaffold is the one path that also wires its index row.

The chain is deterministic: goal verdict, retro validate and extract, lessons summary, the close gate, handoff, reconcile. It stops loudly at the first failing step with the remedy named.

--apply-signoff fans your reviewer-of-record approval into per-unit sign-offs and Done transitions. It is gated on the criteria having passed, it cascades, it is idempotent, and it stops at the first refusal rather than half-applying. It never runs without an explicit --principal.

The checklist is part of the sprint report, not a second document. It carries one row per stage of the cycle - the pre-plan reconcile, the goal’s seat review, the grooming gate, the run opening, the batch-boundary reviews, the closing review, the goal verdict, the retro, the lessons, the sign-off, the handoff - plus the figures a close otherwise re-derives by hand: planned against delivered, what was dropped or held or carried and why, scope creep as a count and a ratio, who reviewed what under which seat, and cost.

Every row but one is derived from the tree, because a checklist that asks you to retype what the files already hold gets filled in from memory.

The exception is a judgement, and it is the honest part:

Carried finding Ruling Ruled by Date
BG0402 not-stop-ship you
CR0510 deferred you

Every open finding takes a ruling - stop-ship, not-stop-ship, accepted-risk or deferred. An open finding with no row is reported UNRULED, because “we carried it” and “nobody looked” must never read the same. A stop-ship ruling holds the close.

If an item genuinely does not apply, waive it on the record rather than fudging it.

A finding at close is filed, never repaired inline

Section titled “A finding at close is filed, never repaired inline”

The close writes an account of the batch and then stamps the ledger saying the batch is accounted for. Anything reaching a terminal status after that stamp is, by construction, unaccounted for.

So a finding surfaced during a close is filed and deferred. Repairing inline produces a close that appears never to finish: every mechanical check passes, the run reads closed, and the ledger still says a close is owed. One run hit that twice in a single close.

/sdlc-studio sprint boundary --retro RETRO0001 # close this cycle, open the next from the live backlog
/sdlc-studio sprint plan --cycles 3 --goal done # a standing policy: roll three cycles

Each cycle regenerates its plan against the backlog as it stands, rather than executing a plan drawn before the last two sprints changed it.

  • The retrospective - why it is checked on content and not existence.
  • Lessons - where a retro’s findings go, and how the next plan reads them.
  • Two-role review - the independence rule behind the sign-off.
  • Charters - queueing the next run before this one closes.