Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LayerCake.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<File Path="docs/build-log.md" />
<File Path="docs/file-inventory.md" />
<File Path="docs/frontend.md" />
<File Path="docs/critter-stack-audit.md" />
</Folder>
<Folder Name="/solution items/docs/slices/">
<File Path="docs/slices/001-publish-browse-cakes.md" />
Expand Down
1 change: 1 addition & 0 deletions docs/build-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ Running record of decisions made during build sessions: anything a later session
- **2026-09-05** Audit Tier B, first pass (B1, B5, B9 from `docs/critter-stack-audit.md`). (B1) `NotifyBakerHandler` is now a pure function: `Handle(NotifyBaker) => Storage.Store(new BakerTask {...})` returning `Store<BakerTask>` (Wolverine.Persistence), no `IDocumentSession`, no await; the transactional middleware executes the upsert after `Handle` returns. Same identity-upsert idempotency, now unit-testable by inspecting the returned value. (B5) New project `tests/LayerCake.Slices.Tests` (xUnit + Shouldly, no Alba, no Testcontainers): 15 facts calling `PlaceOrderEndpoint.Decide`, `PlaceOrderEndpoint.Validate`, `CouponValidation.Evaluate`, and `NotifyBakerHandler.Handle` directly, including a ToEven half-cent rounding case and a `ReferenceEquals(WolverineContinue.NoProblems)` happy-path check. Runs in ~50 ms. Deliberately after-twin-only: the contract suite stays the shared proof, this is the "pure functions, no mocks" exhibit the before twin cannot match. Added to `LayerCake.slnx`; `dotnet test` now runs both projects (15 + 54). (B9) `dotnet list package --include-transitive` on the console shows a real in-process mix: CritterWatch 1.0.1 pulls WolverineFx.Http/.Marten/.Postgresql/.SignalR at 6.29.1 while the direct refs follow the 6.30.0 pin. Tried the skill's remedy (`VersionOverride="6.29.1"` on the console's two direct refs): it unifies every package but does NOT compile, because `ProcessInParallelWithNativeAcks()` from the official 1.0 quickstart is a 6.30 API. Reverted. Conclusion: the 6.29.1/6.30.0 mix is the pairing JasperFx's own quickstart requires; the skill's "must equal the compiled-against version" rule is stricter than their shipped sample. Re-verified live at 6.30.0 with today's changes: console 200 on 42030, zero exceptions in its log, `critterwatch` queue 1 consumer / 0 backlog, `layercake-control` 1 consumer with the console holding a sender to it (it knows the service), after twin 200 on `/ping`, `POST /orders` 201 and the baker task present via the durable local queue and the new handler. `after.wolverine_incoming_envelopes` and friends confirmed present on the compose database. Reasoning recorded as a comment on the console csproj. Suite 54/54 + 15/15, 0 warnings. Line counts: after twin 706 raw / 585 non-blank (unchanged; the handler rewrite is net zero), before twin unchanged.
- **2026-09-05** Audit Tier B, second pass (B3 + B4 from `docs/critter-stack-audit.md`). The flat `Features/` folder is gone: slices now live beside their documents in the bounded-context folders the style skill prefers (`Cakes/` holds `Cake.cs` + `PublishCake.cs`, `BrowseCakes.cs`, `GetCake.cs`; `Coupons/` holds `Coupon.cs` + `CouponValidation.cs`, `ValidateCoupon.cs`; `Orders/` holds `Order.cs`, `BakerTask.cs` + `PlaceOrder.cs`, `NotifyBaker.cs`, `GetOrder.cs`, `GetBakerTasks.cs`), `Ping.cs` sits at the project root with `SeedData.cs` and `Program.cs`, and `NotifyBakerHandler.cs` is renamed `NotifyBaker.cs` after the message it carries (style rule 1). Namespaces follow the folders (`LayerCake.Slices.Cakes` / `.Coupons` / `.Orders`; the `LayerCake.Slices.Features` and `.Features.Coupons` namespaces no longer exist), which made eleven `using` lines redundant and removed them. All moves via `git mv`, so history follows the files. No behaviour change; routes, contract, and file count unchanged. Paths updated in README (tour tree and the PublishCake pointer), `docs/file-inventory.md`, and the three slice specs; `openspec/changes/archive/` left as the historical record it is. Unit-test usings updated. Suite 54/54 + 15/15, 0 warnings. Line counts: after twin 695 raw / 574 non-blank (was 706 / 585; the eleven dropped usings), before twin unchanged.
- **2026-09-05** Audit Tier B, third pass (B2). The two HTTP response records were named like events (`CakePublished`, `OrderPlaced`) while being neither events nor messages; the repo has no events at all (state-stored by design) and exactly one message, the command `NotifyBaker`. Renamed to noun phrases, `PublishedCake` and `PlacedOrder`, so `(PlacedOrder, NotifyBaker)` reads as response-plus-command at a glance and past tense stays reserved for events. The JasperFx sample style (`TodoCreationResponse`) was considered and declined: **Erik's standing rule, now in CLAUDE.md, is no role-word suffixes on type names (`Response`, `Request`, `Event`, `Message`, and the like) when avoidable; without the layers, the labels are not needed.** Rename only: routes, JSON shape, and contract untouched (the contract suite deserializes into its own records and never names these types). README code excerpt updated. A suffix scan of the whole solution found the after twin otherwise clean except `BakerTaskItem` in `GetBakerTasks.cs` (flagged, not changed); the before twin's `Command`/`Query`/`Dto`/`Request` suffixes are the Clean Architecture exhibit and stay by non-negotiable 1; the contract suite's private `CakeItem`/`OrderEnvelope`/`CouponEnvelope`/`BakerTaskItem` records are test-local deserialization shapes. Suite 54/54 + 15/15, 0 warnings. Line counts unchanged (after twin 695 raw / 574 non-blank).
- **2026-09-05** Critter Stack audit closed (`docs/critter-stack-audit.md`). Across PRs #8 to #11: durable local queues (the outbox claim made true), solo-mode after-twin fixture, pure `NotifyBaker` handler returning `Store<BakerTask>`, `tests/LayerCake.Slices.Tests` (15 pure-function facts), CritterWatch version coupling checked and the 6.29.1/6.30.0 mix kept with reasoning on the console csproj, slices moved from `Features/` into `Cakes/`/`Coupons/`/`Orders/`, `NotifyBaker.cs` rename, `PublishedCake`/`PlacedOrder` naming plus the no-role-word-suffix rule in CLAUDE.md. Accepted without change, reasons in the audit doc's closing status: inline clock (deliberate asymmetry exhibit), two round trips in `PlaceOrder.LoadAsync` (slide readability), explicit seeding over `IInitialData` (one line), unconditional `RuntimeCompilation` reference (Development-only repo), and the baker-task polling loop (the skill's own escape hatch for a shared suite). `BakerTaskItem` flagged for its `Item` suffix, left alone. Doc-only change; no code, counts unchanged (after twin 695 raw / 574 non-blank, before twin 1,733 / 1,432).
12 changes: 12 additions & 0 deletions docs/critter-stack-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Skills consulted: wolverine-http-fundamentals, wolverine-handlers-fundamentals,

Verdict in one line: the after twin is idiomatic Critter Stack code and would pass a JasperFx maintainer's glance. One claim the talk makes about it is not currently true (Tier A1). Everything else is either a two-line hardening or a judgment call worth a conversation.

**Audit closed 2026-09-05.** Both Tier A items and five of the eleven Tier B items shipped across PRs #8 through #11 (durable local queues, solo-mode fixture, pure `NotifyBaker` handler, after-twin unit tests, CritterWatch version check, context-folder layout, `NotifyBaker.cs` rename, `PublishedCake`/`PlacedOrder` naming). The remaining six Tier B items are accepted divergences, each with its reason recorded in the closing status under Tier B. Nothing in this document is outstanding; the per-pass status blocks below are the change record, and `docs/build-log.md` has the detail.

---

## Tier A: act before the talk
Expand Down Expand Up @@ -63,6 +65,16 @@ Each item is a defensible divergence or a judgment call. Listed roughly by how m

**Status 2026-09-05, third pass:** B2 done. The two HTTP response records are now noun phrases, `PublishedCake` and `PlacedOrder`, so the past-tense event convention is reserved for events (of which this repo has none; `NotifyBaker` is the only message and it is a command). `Response`/`Request` suffixes were considered and rejected as a standing rule, now in CLAUDE.md. B6, B7, B8, B10, B11 remain open.

**Status 2026-09-05, closing pass.** The remaining items are accepted as they stand, no code change:

- **B6, inline `DateTimeOffset.UtcNow`.** Accepted. The before twin's injected `IDateTimeProvider` against the after twin's inline clock is a deliberate exhibit recorded in the build log (slice 002), and the seed windows make time control unnecessary in every test.
- **B7, two round trips in `PlaceOrder.LoadAsync`.** Accepted. A Marten batch query would save one round trip at demo scale and cost readability on the A-Frame slide; the sequential version is the one the talk shows.
- **B8, explicit `SeedData.ApplyAsync` over `IInitialData`.** Accepted. The switch saves one line in `Program.cs`, and the test fixture would still call the seeder explicitly after wiping.
- **B10, unconditional `WolverineFx.RuntimeCompilation` reference.** Accepted. The repo only runs in Development; the csproj comment and the 2026-08-23 build-log entry already pre-answer the production question.
- **B11, the baker-task polling loop.** Accepted as compliant. It is the skill's own escape hatch (deadline poll, reason commented) because the shared suite cannot use `ExecuteAndWaitAsync` against the before twin. An after-only tracked-session test remains an option for a contrast slide, not a gap.

Also flagged during B2 and left alone: `BakerTaskItem` in `GetBakerTasks.cs` carries an `Item` suffix. Rename to a noun such as `BakerTodo` if it ever reaches a slide.

### B1. `NotifyBakerHandler` could be a pure function

Current shape injects `IDocumentSession` and calls `session.Store(...)`. The declarative-persistence skill's stated preference for a simple write is a storage-action return:
Expand Down