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
46 changes: 35 additions & 11 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,41 @@
</ItemGroup>
<!-- Wolverine -->
<ItemGroup>
<PackageVersion Include="WolverineFx" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Http" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Http.FluentValidation" Version="6.19.0" />
<PackageVersion Include="WolverineFx.FluentValidation" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Grpc" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Marten" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Polecat" Version="6.19.0" />
<PackageVersion Include="WolverineFx.AzureServiceBus" Version="6.19.0" />
<PackageVersion Include="WolverineFx.Kafka" Version="6.19.0" />
<PackageVersion Include="WolverineFx.SignalR" Version="6.19.0" />
<PackageVersion Include="WolverineFx.RuntimeCompilation" Version="6.19.0" />
<PackageVersion Include="WolverineFx" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Http" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Http.FluentValidation" Version="6.21.0" />
<PackageVersion Include="WolverineFx.FluentValidation" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Grpc" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Marten" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Polecat" Version="6.21.0" />
<PackageVersion Include="WolverineFx.AzureServiceBus" Version="6.21.0" />
<PackageVersion Include="WolverineFx.Kafka" Version="6.21.0" />
<PackageVersion Include="WolverineFx.SignalR" Version="6.21.0" />
<PackageVersion Include="WolverineFx.RuntimeCompilation" Version="6.21.0" />
</ItemGroup>
<!-- gRPC proto-first codegen (Telemetry ReportLocations).
Grpc.Tools runs protoc + the C# gRPC plugin at build time over the
<Protobuf> items in CritterCab.Telemetry.csproj; Google.Protobuf is the
runtime the generated message classes bind against; Grpc.AspNetCore is the
ASP.NET Core server integration WolverineFx.Grpc layers on top of.
Versions are pinned to exactly what WolverineFx.Grpc 6.21.0 declares as its
own dependencies (Grpc.AspNetCore 2.76.0 -> Grpc.Tools 2.76.0 +
Google.Protobuf 3.31.1), so the codegen toolchain matches the pairing
Wolverine itself was built and tested against. Newer lines exist
(Grpc.* 2.80.0, Google.Protobuf 3.35.1) — take them as a deliberate
tidy: packages bump, not incidentally. -->
<ItemGroup>
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
<PackageVersion Include="Grpc.Tools" Version="2.76.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageVersion Include="Google.Protobuf" Version="3.31.1" />
</ItemGroup>
<!-- H3 geospatial indexing (Telemetry cell computation).
pocketken.H3 is the published id for github.com/pocketken/h3.net (the bare "H3" id is a
different, prerelease-only package). Pure-managed C# port — no native P/Invoke, so CI stays
clean. Ships a native lib/net10.0 and pulls NetTopologySuite transitively, which is what
makes the degrees-native NTS Coordinate path free of any added dependency. -->
<ItemGroup>
<PackageVersion Include="pocketken.H3" Version="4.5.0.1" />
</ItemGroup>
<!-- SignalR client (integration-test transport for Relay BC push assertions) -->
<ItemGroup>
Expand Down
17 changes: 12 additions & 5 deletions apphost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#:package Aspire.Hosting.PostgreSQL@13.4.6

#:project ./src/CritterCab.Dispatch/CritterCab.Dispatch.csproj
#:project ./src/CritterCab.Telemetry/CritterCab.Telemetry.csproj

var builder = DistributedApplication.CreateBuilder(args);

Expand All @@ -36,11 +37,17 @@
.WithReference(dispatchDb)
.WaitFor(dispatchDb);

// Telemetry is CritterCab's second service (stream-processing shape, W006). This PR
// stands up its skeleton + config-as-events slice 1 only; the Kafka resource that
// slice 3 needs is deliberately NOT wired yet (same deferral the Dispatch skeleton
// made for transport). Ports follow the +5 slot convention after Dispatch's 5310;
// 5315 https / 5316 http. See docs/skills/aspire/SKILL.md § Port allocation.
// Telemetry is CritterCab's second service (stream-processing shape, W006). Ports follow
// the +5 slot convention after Dispatch's 5310; 5315 https / 5316 http. See
// docs/skills/aspire/SKILL.md § Port allocation.
//
// The ReportLocations gRPC ingest (W006 §6.2) rides the HTTPS endpoint via Kestrel HTTP/2 —
// the same arrangement the Dispatch block describes above, so gRPC needs no endpoint of its
// own. This is CritterCab's first gRPC surface that actually serves traffic.
//
// The Kafka resource that slice 3 needs is still deliberately NOT wired: slice 2's publish
// goes to the IDriverLocationPublisher seam, and PR C swaps that for the real producer and
// adds the broker here.
builder.AddProject<Projects.CritterCab_Telemetry>("telemetry", launchProfileName: null)
.WithHttpsEndpoint(port: 5315, name: "https")
.WithHttpEndpoint(port: 5316, name: "http")
Expand Down
1 change: 1 addition & 0 deletions docs/prompts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,4 @@ Subsequent sections are prompt-specific. Existing prompts in this directory serv
- [`implementations/004-dispatch-slice-5-2-fare-quoted-failure-paths.md`](./implementations/004-dispatch-slice-5-2-fare-quoted-failure-paths.md) — Third vertical slice: closes W001 §5.2's three FareQuoteFailed alternate-path GWTs (transient retry recovery, exhausted retries, non-transient failure) deferred from slice 003. Adds `FareQuoteFailed` event, `FareQuoteAttempts` terminal-events-only projection, `IFareQuoteOutcome` marker interface, two `IPricingClient` exception types for failure injection, `FareQuoteRetryPolicy` DI record (test-override seam pre-shaping Slice 11's `DispatchPolicyConfigured`), and a manual retry loop in `FareQuoteAutomation`. Three implementation-mechanism choices committed up-front in the prompt: exception-typed failure contract, manual retry loop (not Wolverine chain policy), terminal-only projection. Flags one W001 §5.2 inconsistency to amend in a future workshop-tidy session. **Second substantive forward exercise of the spec-delta closure-loop convention** — meets ADR-016's 2–3-exercises deferral trigger. Status: complete (2026-05-19). Produced retro at [`retrospectives/implementations/004-dispatch-slice-5-2-fare-quoted-failure-paths.md`](../retrospectives/implementations/004-dispatch-slice-5-2-fare-quoted-failure-paths.md).
- [`implementations/005-dispatch-slice-5-3-candidates-selected.md`](./implementations/005-dispatch-slice-5-3-candidates-selected.md) — Fourth vertical slice: first slice of the dispatch-round arc. `CandidateSelectionAutomation` reacts to `FareQuoted`, queries `INearbyAvailableDriversSource` (Telemetry + Driver Profile translation-in stub; parking-lot #4 deferred), and emits `CandidatesSelected` (happy path) or `NoCandidatesAvailable` (empty-set path) as a Klefter decision-event. Adds `DispatchPolicySnapshot` DI record (hardcoded `searchRadiusMeters: 5000`, `maxCandidatesPerRound: 5`; Slice 11 swaps for `DispatchPolicyConfigured`-fed projection), `ICandidateSelectionOutcome` marker interface (third instance of the pattern), `RequestRoundsProjection` inline projection (consumed by Slice 9), and `RequestTimeline` extensions for both outcome events. Three Alba integration tests, one per W001 §5.3 GWT. First use of `[WriteAggregate]` bound to a non-first stream event in the codebase. **Third substantive forward exercise of the spec-delta closure-loop convention.** Status: pending (authored 2026-06-16).
- [`implementations/006-telemetry-skeleton-and-slice-1-config.md`](./implementations/006-telemetry-skeleton-and-slice-1-config.md) — **Second service in the repo** and the opening PR of the W006 Telemetry transport chain. Bootstraps the `CritterCab.Telemetry` service skeleton **and** W006 slice 1 (`TelemetryPolicyConfigured` config-as-events) in one PR, per the named skeleton-plus-first-slice cadence exception (mirrors the Dispatch skeleton + slice-5.1 precedent). Config-as-events is the dependency-correct first slice: slice 2's gRPC ingest reads this slice's `TelemetryPolicy` view (`throttlePolicyVersion`, `h3Resolution`, intervals). Establishes two firsts in code — **first config-as-events instance** (ADR-011's third instance, first realized; Dispatch/Onboarding were design-only) and **first FluentValidation boundary validation**. Four pre-flight `jasperfx-source-verifier` gates (`IInitialData` seed vehicle, `long` stream-version property, self-aggregating `LiveStreamAggregation` registration + Marten-9 `partial` scope, Wolverine.HTTP FluentValidation middleware). None of W006 §11's three ADR candidates fired (all later-arc), but the Phase-2 audit surfaced an ADR-011 Option-A/B-for-Marten gap that — **per user direction, expanding the session mid-flight** — was resolved in-PR via an **ADR-011 amendment** (`IInitialData` as the canonical Marten Option-A realization; LWW for config singletons). No narrative anchor (PR #40: the narrative layer does not apply to Telemetry). Kafka deliberately **not** wired into `apphost.cs` this PR (transport lands with the slice that needs it — Dispatch-skeleton precedent). Substantive spec delta: W006 §6.1 designed → realized. Status: pending (authored 2026-07-10).
- [`implementations/007-telemetry-slices-4-and-2-transport.md`](./implementations/007-telemetry-slices-4-and-2-transport.md) — **CritterCab's first transport in code.** W006 slice 4 (`LastKnownPosition` store + heartbeat-absence eviction) and slice 2 (gRPC `ReportLocations` client-streaming ingest) in one PR under the **coupled-slices** reading of the cadence rule, not the skeleton-plus-first-slice exception (already spent on 006): slice 2's publish trigger evaluates against slice 4's document and slice 4's document is written only when slice 2 publishes, so building either alone means evaluating against a document that does not exist or writing one nothing reads. Establishes five firsts in code — **first gRPC surface serving traffic**, **first client-streaming RPC**, **first proto codegen** (`protos/` had been contracts with no consumer since PR #39), **first non-event-sourced document write path**, and **first recurring/scheduled work**. Retires the three-month client-streaming forward-constraint: WolverineFx.Grpc **6.21.0** auto-generates the shape, so nothing is hand-wired, and the two gRPC skills that still described the workaround are corrected in-session under the session-runner-blocking exception (a session cannot follow a skill telling it to hand-wire). Eleven Verify-before-wiring gates were source-verified before any code; gate 5 **corrected the prompt's own hypothesis** (Wolverine has no recurring-message primitive — the idiom is a plain `BackgroundService`) and gate 11 dissolved (Alba's `TestServer` feeds a `GrpcChannel` directly, so the Alba-first default holds for gRPC). Two W006 under-specifications surfaced and were resolved by user sign-off rather than silently: the `LastKnownPosition` field set (`lastPublishedAt` collapsed into `serverReceivedAt`, since upsert-on-publish-only makes them one instant) and the `accuracyMeters` threshold (**100m, invented at implementation time — W006 names the threshold but fixes no value**). Also fixed `apphost.cs`, which had not compiled since PR #42 and which CI does not build. Substantive spec delta: W006 §6.2 + §6.4 designed → realized; the §11 *windowed client-streaming* ADR candidate lands as a skill, not an ADR. Status: complete (authored 2026-07-20, executed 2026-07-24). Produced retro at [`retrospectives/implementations/007-telemetry-slices-4-and-2-transport.md`](../retrospectives/implementations/007-telemetry-slices-4-and-2-transport.md).
Loading
Loading