Skip to content

Build1 publisher3 min readPublished

Concurrency tests against real Postgres fit inside the hour this Sekiban app took to build

Sekiban DCB's Decider template ships three worked feature slices for an agent to copy. In this walkthrough, review, implementation, build, concurrency tests on a real PostgreSQL database and UI fixes took under an hour.

The Engineer · Build desk

Illustration accompanying Concurrency tests against real Postgres fit inside the hour this Sekiban app took to build

What happened

  • The walkthrough builds a library management application with register, borrow and return operations on Sekiban DCB, storing events in PostgreSQL behind a basic Blazor UI.
  • Two commands create the project, dotnet new install Sekiban.Dcb.Templates followed by dotnet new sekiban-dcb-decider -n BookManagement, on the .NET 10 SDK with Docker Desktop running Linux containers.
  • The generated project already contained Student, ClassRoom and Enrollment samples spanning UI, APIs, commands, Deciders, events, states and queries, and the instructions named those samples as the standard to copy.
  • The author reports that the whole pass, covering review, implementation, build, integration and concurrency tests against a real PostgreSQL database and UI fixes, took less than an hour with Codex and GPT-6 Astra.
  • Business requirements, consistency rules and verification scenarios are published in docs/spec.md, alongside the BookManagement sample code on GitHub.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost Before the first command handler exists, the adopting team pays for a .NET 10 SDK, Docker Desktop on Linux containers and a live PostgreSQL instance. The append-time conflict path only tests against a real store.
  • constraint The copy-the-existing-code instruction only works where an end-to-end slice of the same shape already exists in the repo, so a greenfield codebase gets the template's speed only for features the template already demonstrates.
  • decision Teams reusing this have to choose whether to write the consistency rules and verification scenarios before generation, as this project did in docs/spec.md, or let the model infer the invariants it will then be tested against.
  • capability Because the Decider holds no persistence code, a reviewer can read the whole write-side rule in one file and check it as a pure function.

Two borrow requests for the same book arrive together. Both handlers retrieve state, both get an available book, both pass validation, and both produce a BookBorrowed event. The handler validates against a state that was true at the moment it was read [16]. The published flow puts the resolution one stage later: after event creation comes conflict detection and persistence by Sekiban, and only then the projector and the query the UI reads [17]. Of the eight stages in that diagram, two decide whether a write is allowed, with one stage between them [22].

A Decider needs no code to connect to PostgreSQL [16], so Validate and Evolve can be exercised as pure functions. The conflict check at append time cannot be exercised without the store it appends to. The concurrency test therefore has to run against a real database, and in this project it did [12].

The Decider excerpt shows how the invariant is expressed. Validate is declared on BorrowedBookState and its body is a single throw of InvalidOperationException, "Book {state.BookId} is already borrowed"; Evolve is declared on AvailableBookState, takes a BookBorrowed event, and returns a BorrowedBookState carrying the LoanId and UserId [14]. No boolean field is involved: the state type carries availability, so a second borrow attempt is rejected by which method resolves [15].

The features the agent added map onto samples that shipped in the template. Borrowing and returning a book is enrolling and withdrawing with a capacity of one: Enrollment already covered enrolling in and withdrawing from classes, ClassRoom already had capacity, and Student already had enrollment limits [6]. The instruction leaned on that: read the three existing implementations end to end, treat them as the standard for the project, and "Do not introduce custom helpers, new abstractions, or shorthand syntax" [9][10]. It also told the model that if the existing approach could not meet the requirements, it should explain why, propose a change, and ask for confirmation before proceeding [11].

For the sub-hour figure to mean anything in another repo, that repo needs a feature slice of the same shape, running from UI through APIs and business rules to event persistence [7]. It also needs the consistency rules and verification scenarios written down before generation, as this project has them in docs/spec.md [8].

The author's case for the approach is legibility. The agent implemented the new business rules using the same Decider structure as the existing code, and keeping that structure consistent as features are added makes it easier for developers to know where to look for business rules [18]. "This is where I found the approach particularly useful for AI-assisted coding," the author wrote [19]. The available text ends mid-sentence at "Checking the current state alone doe" [21], so the concurrency scenarios and what they showed are not in it.

What to watch

  • Whether the rest of the post publishes the concurrency scenarios and what Sekiban returns to the losing command.
  • Whether the template's sample set grows past Student, ClassRoom and Enrollment, since the copy-the-samples instruction depends on a matching reference.
  • Whether the same prompt discipline holds for a feature with no analogue among the shipped samples.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories