Meridian Field Services: instructional example, not project evidence
The register: a schema registry alone is not governance; the catalog layers ownership and discovery. Provenance: the design walk against the container view, July 12 (building blocks[1]).
| Event · schema | Producer | Consumers | Classes |
|---|---|---|---|
| position.observed v2 backward · additive-only |
Feed adapter | Board read model · position-store writer | RESTRICTED (labels[2]) · payload cites Position[3] |
| job.ready v1 | Intake | Board · suggestion trigger | CONFIDENTIAL |
| assignment.created v1 via the outbox, §3 |
Dispatch API | Board · notification worker · audit writer | CONFIDENTIAL · cites Assignment[3] |
| assignment.confirmed v1 | Mobile confirmation path | Board · audit writer | CONFIDENTIAL |
| override.recorded v1 | Dispatch API | Audit writer · exception-review view · note-embedding hook (freshness[4]) | CONFIDENTIAL worker-conduct |
| notification.requested v1 | Assignment consumer | Notification worker → INT-2 | CONFIDENTIAL |
Every schema lives in the registry with its compatibility mode; a consumer addition is a registration, not a silent subscription; the embedding hook's addition to override.recorded was an explicit catalog change, dated.
Ordering is a per-key promise; the forfeit is stated with the promise.
Shape, citing the seams (integration and data views[1]): position.observed rides the durable log (replayable: the board can rebuild); assignment and override events ride the fan-out topic; notification.requested is point-to-point to the worker.
| Key | Ordered (the promise) | NOT ordered (the forfeit) |
|---|---|---|
| vehicle_id | One vehicle's readings: the reconciliation the adapter's single-writer design needs (INT-1 design[1]) | Across vehicles, and none is needed; the forfeit buys the fan-in parallelism the scale frame requires |
| job_id | One job's lifecycle: created before confirmed | Across jobs |
Event topology: the fan-out under the specificity law. Fallback text: inside the Meridian boundary (AWS ca-central-1, Canada residency), producers publish to the dispatch-events SQS backplane: the telematics-adapter emits position.observed (vehicle_id, lat, lon, observed_at · RESTRICTED · at-least-once · ordered per vehicle_id) to the durable log; intake, dispatch-api (via the outbox), and the mobile path emit job.ready, assignment.created (assignment_id, technician_id · CONFIDENTIAL · ordered per job_id), override.recorded, and assignment.confirmed to the fan-out topic. The durable log feeds the board (upsert on vehicle_id + observed_at) and the position-store writer (30-day purge); the fan-out topic feeds the board (version-check dedupe), the suggestion trigger, the audit writer (dedupe on event id · append-only), the exception-review view, and the note-embedding hook; notification.requested flows point-to-point to the notification-worker (dedupe on assignment_id + attempt window), which pushes INT-2 to the untrusted notification gateway (vendor API key · SR-027). Every edge names its event, fields, class, and delivery semantic.
| Topic | Semantic · cost | Idempotency strategy |
|---|---|---|
| position.observed | At-least-once inside the platform (receiver acks after enqueue); cost: duplicates on redelivery | Board upserts on vehicle_id + observed_at; a duplicate is a no-op |
| assignment / override topics | At-least-once; cost: duplicates | Audit writer dedupes on event id; the board version-checks (concurrency[3]) |
| notification.requested | At-least-once; a duplicate push is annoying, a dropped one breaks the confirmation flow; the cost went the right way | Worker dedupes on assignment id + attempt window |
Exactly-once: claimed NOWHERE. The practical statement stands: at-least-once plus idempotent consumers. Dual-write law: assignment.created publishes via the OUTBOX: the Assignment row and the outbox row commit in one transaction; the relay publishes async (outbox rows[3]); the gap this closes is the one the edge-case analysis names (concurrency[5]).
Every DLQ is owned and alerted through the observability design, never a second alert system.
| Rule | Value |
|---|---|
| Retries | 3, with backoff; then dead-letter with the failure class stamped (retriable / fixable / poison) |
| Alert | The observability design's existing row: dead-letter rate above zero for 15 min, TICKET, platform engineer (alert catalog[6]) |
| Drain owner | Platform engineer; weekly floor even when quiet |
| Replay | Post-fix only; 10-event batch first; drain to zero. Safe because every consumer above declares idempotency; the position log tolerates full backfill (upsert), the notification path takes bounded replay only; a re-notification storm is user-facing |
History: the truncated INT-3 file's partial load dead-lettered its batch (ISS-2[7], RSK-08[8]); the checksum gate that fixed it lives in the migration runbook (validation[9]), and the drain that day followed this procedure.
| Question | Owner | Answer by | Blocks |
|---|---|---|---|
| Does the position log's retention (currently the 30-day purge window, retention rules[2]) also bound the board-rebuild window, or does the rebuild need a shorter operational guarantee stated separately? | E. Sandoval | Sep 30, 2026 | The topology's replay note only |