Telemetry: service skeleton + slice 1 (TelemetryPolicyConfigured config-as-events)#42
Merged
Merged
Conversation
…ig-as-events)
Stands up CritterCab.Telemetry as the repo's second service and realizes W006
slice 1 in one PR (skeleton + first-slice cadence exception; mirrors the Dispatch
skeleton + slice-5.1 precedent). Opening PR of the W006 transport chain — config-
as-events is the dependency-correct first slice (slice 2's gRPC ingest reads this
slice's TelemetryPolicy view), and it lands no transport.
- TelemetryPolicyConfigured singleton event stream (full-replacement, ADR-011)
- ConfigureTelemetryPolicy command + nested AbstractValidator (boundary validation)
- TelemetryPolicy self-aggregating live-stream view; throttlePolicyVersion as long
(the Marten stream version, matching the proto int64)
- IInitialData migration-time idempotent bootstrap seed (defaults 9/30/5,
operatorId=system-bootstrap) per ADR-011 Option A
- 3 Alba GWTs (bootstrap / reconfigure / reject) + DB-less smoke test
- apphost: Telemetry + crittercab_telemetry DB (5315/5316); Kafka deliberately
deferred to slice 3
First config-as-events instance in code (ADR-011's third instance; Dispatch and
Onboarding were design-only) and first FluentValidation use. Four jasperfx-source-
verifier gates ran before wiring. No ADR fired (W006 §11 candidates are later-arc).
Prompt + retro under docs/{prompts,retrospectives}/implementations/006-*. DEBT row
registered for the config-as-events bootstrap-seed skill (ADR-011's deferred follow-up).
…liation The critter-skill-auditor Phase 2 pass caught a design-vs-implementation gap: W006 §6.1 locks the seed as "ADR-011 Option A (migration-time seed)", but the Marten IInitialData realization runs at host startup — structurally Option B, the option ADR-011 rejected over a multi-instance seed race. IInitialData does serve Option A's intent under the JasperFx `resources setup` deploy step, but also self- seeds at host start; the race is benign here (idempotent guard + full-replacement) and irrelevant at single-instance MVP scale. Corrects artifacts to stop bare-claiming "Option A" and registers the reconciliation (plus the write-path optimistic-concurrency question — Append with no expected version, because [WriteAggregate] has no binding to a constant singleton id) as questions the future canonical-pattern skill must resolve. The ADR-011 amendment itself is a user-owned decision, not made here. - TelemetryPolicyBootstrap.cs / Program.cs: accurate seed comments + reconciliation note - W006 Document History: open-reconciliation note - DEBT.md: two design questions the reference impl must resolve before enshrining - retro: "design meets code" section capturing the finding
…est) CI caught it: the reject GWT got 200 instead of 400 — the boundary validator never ran. UseFluentValidationProblemDetailMiddleware resolves IValidator<T> from DI, but nothing registered the validators. Add opts.UseFluentValidation() (WolverineFx.FluentValidation) which discovers and registers all IValidator<> in the app assembly — the idiomatic pairing the Wolverine HTTP sample uses, and it auto-discovers future validators rather than needing a per-validator registration. Local build green; the reject test's 400 is verified on CI (local Docker wedged).
…wiring DEBT Records the confirmed CI outcome (run 29119259592: Telemetry 4/4 + Dispatch 11/11) and the CI-caught validator-registration bug as a methodology lesson (a Docker-wedged session's DB-less smoke test gives false confidence about paths it never touches). Registers the Wolverine.HTTP FluentValidation two-call wiring as a wolverine-http-handlers skill gap.
… LWW Resolves the Option-A/B-for-Marten gap the slice-1 Phase-2 audit surfaced (user- directed, in-PR). Amends ADR-011 with a 2026-07-10 section recording that IInitialData (via .InitializeWith<T>()) is the canonical Marten realization of Option A — it seeds at the deploy-time apply step and idempotently at host start as a self-healing safety net; the multi-instance race is mitigated by the idempotent guard + full-replacement and avoided by the deploy step / single-instance MVP. Also records last-writer-wins as the accepted config-singleton write semantic (full-replacement has no invariant to defend; optimistic concurrency not required; manual constant-id append since [WriteAggregate] has no id field to bind). Cascades the "resolved" status through DEBT (skill now unblocked), W006 history, the retro (design-meets-code + spec-delta + outstanding items, documenting the mid-flight user-directed expansion), both README indexes, and the two seed code comments. Prompt left as authored (historical record), not retroactively re-scoped.
erikshafer
added a commit
that referenced
this pull request
Jul 10, 2026
…nsport build Introduces three handoff notes tracking Telemetry chain progression from PR #39 (protos) through PR #42 (skeleton + slice 1). Post-PR-42 handoff orients next session on PR B: slices 4+2 paired (LastKnownPosition store + ReportLocations gRPC ingest), CritterCab's first gRPC surface in code and first Kafka testcontainer. Documents verified WolverineFx.Grpc client-streaming gap (must hand-wire against IMessageBus through 5.37.2; 6.17 unconfirmed), local Docker wedged state (lean on CI), and ADR-011 amendment locked (IInitialData bootstrap + last-writer-wins singletons). Supersedes three earlier untracked handoffs after PR #40 (narrative decision—does not apply, recorded) and PR #41 (package refresh to 6.17.0) both merged. Carries forward design-locked guardrails, three W006 §11 ADR candidates, and open skill-debt items. Includes narrative-decision and post-PR-41 intermediate handoffs for session lineage; all disposable once next session orients.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Opening PR of the W006 Telemetry transport chain. Stands up
CritterCab.Telemetryas the repo's second service and realizes W006 slice 1 (TelemetryPolicyConfiguredconfig-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
TelemetryPolicyview (throttlePolicyVersion,h3Resolution, intervals). So this opening PR of the "first real transport build" deliberately lands no transport — that's the correct dependency order, not an omission.What landed
Skeleton — new
Microsoft.NET.Sdk.Webservice mirroring Dispatch (owncrittercab_telemetryDB, ports 5315/5316), paired Alba test project, apphost + slnx wiring. Kafka deliberately not wired intoapphost.cs— transport lands with the slice that needs it (slice 3), the same deferral the Dispatch skeleton made.Slice 1 (
TelemetryPolicy/feature folder)TelemetryPolicyConfiguredsingleton event stream (full-replacement, ADR-011)ConfigureTelemetryPolicycommand + nestedAbstractValidator(boundary validation: intervals positive,heartbeat ≥ minPublish,h3Resolutionin 0–15)TelemetryPolicyself-aggregating live-stream view exposingthrottlePolicyVersionas along(the Marten stream version, matching the protoint64)IInitialDatamigration-time idempotent bootstrap seed (defaults9/30/5,operatorId=system-bootstrap) per ADR-011 Option ATwo firsts in code
DEBT.mdrow (not authored here).WolverineFx.Http.FluentValidation.Verification
jasperfx-source-verifiergates ran before wiring:IInitialDataseed vehicle,longstream-version property, self-aggregatingLiveStreamAggregationregistration + Marten-9partialscope, Wolverine.HTTP FluentValidation middleware. All confirmed at build.dotnet buildgreen; smoke test green locally. Local Docker's container-start path was wedged all session (the handoff-flagged condition), so the 3 slice-1 Testcontainers tests are gated on CI here rather than run locally.No ADR fires — W006 §11's three candidates are all later-arc (Kafka topic-naming → slice 3; stream-processing-4th-shape → slices 2–4; windowed client-streaming → slice 2). No narrative anchor (PR #40: the narrative layer does not apply to Telemetry).
Prompt + retro:
docs/{prompts,retrospectives}/implementations/006-telemetry-skeleton-and-slice-1-config.md.Follow-on PRs
LastKnownPosition+ eviction) + slice 2 (gRPC ingest, hand-wired againstIMessageBus)DriverLocationUpdated→ Kafka; wires Kafka into apphost)NearbyAvailableDriversStub)