## Summary Homogenize all 23 ADRs to a single canonical header format, and rewrite `adr/README.md` to match the actual state of the corpus. This is **Tâche 7** of the ARCODANGE Phase 1 migration (Claude Code → Mistral Vibe). Independent from PR #17 (Tâche 6 — restructure AGENTS.md) — both can merge in any order. No code changes; only documentation. ## Changes ### 1. Homogenize 21 ADR headers (commit `db09d0a`) The audit (Tâche 6 Phase A, Mistral intent-router agent, 2026-05-02) had identified **3 inconsistent header formats** : - **F1** — list bullets (`* Status:` / `* Date:` / `* Deciders:`) : 11 ADRs (0001-0008, 0011, 0014, 0023) - **F2** — bold fields (`**Status:**` / `**Date:**` / `**Authors:**`) : 9 ADRs (0009, 0010, 0012, 0013, 0015, 0016, 0017, 0018, 0019) - **F3** — dedicated section (`## Status\n**Value** ✅`) : 5 ADRs (0020, 0021, 0022, 0024, 0025) Plus mixed metadata names (Authors / Deciders / Decision Date / Implementation Date / Implementation Status / Last Updated) and decorative emojis on status values made the corpus hard to scan or template against. **Canonical format adopted** (see `adr/README.md` for full template) : ```markdown # NN. Title **Status:** <Proposed | Accepted | Implemented | Partially Implemented | Approved | Rejected | Deferred | Deprecated | Superseded by ADR-NNNN> **Date:** YYYY-MM-DD **Authors:** Name(s) [optional **Field:** ... lines] ## Context... ``` **Transformations applied** (via `/tmp/homogenize-adrs.py` script, 23 files scanned, 21 modified — 0010 and 0012 were already conform) : - F1 list bullets → bold fields - F2 cleanup : `**Deciders:**` → `**Authors:**`, strip status emojis - F3 sections : `## Status\n**Value** ✅` → `**Status:** Value` (single line) - Strip decorative emojis from `**Status:**` and `**Implementation Status:**` - Convert `* Last Updated:` / `* Implementation Status:` / `* Decision Drivers:` / `* Decision Date:` to bold - Date typo fix : `2024-04-XX` → `2026-04-XX` for ADRs 0018, 0019 (off-by-2-years in original) - Normalize multiple blank lines after header (max 1) **ADR body content is preserved unchanged.** Only headers transformed. ### 2. Rewrite `adr/README.md` (commit `d64ab02`) Previous README had multiple inconsistencies : - Index table listed wrong titles for ADRs 0010-0021 (looked like an aspirational forecast that never matched reality — e.g. "0011 = Trunk-Based Development" but real 0011 is absent and Trunk-Based Development is actually 0017) - Listed entries for ADRs 0011 (validation library) and 0014 (gRPC) but **these files do not exist** in the repo - 0024 (BDD Test Organization) was missing from the detail list - Template still showed the obsolete F1 format (`* Status:`) - Decorative emojis on every status entry Rewrite : - Index table **regenerated from actual file contents** (title from H1, status from `**Status:**` line) — emoji-free, accurate - Notes that 0011 / 0014 are not currently in use (reserved) - Updated template block matches the canonical format - Status Legend extended with `Approved`, `Partially Implemented`, `Deferred` - Added note that 0026 is the next free number for new ADRs ## Test plan - [x] All 23 ADRs follow `**Status:**` / `**Date:**` / `**Authors:**` (verified via grep) - [x] No more occurrences of `* Status:` (F1) or `## Status` (F3) in any ADR header - [x] No more emojis on `**Status:**` lines - [x] `adr/README.md` index links resolve to existing files (no more 0011 / 0014 dead links) - [x] Pre-commit hooks pass (`go mod tidy`, `go fmt`, `swag fmt`) ## Migration context Part of Phase 1 of the ARCODANGE migration from Claude Code to Mistral Vibe. Tâche 7 of the curriculum. Independent from PR #17 (which restructures `AGENTS.md`). The two PRs touch disjoint files — no merge conflict expected when both are merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) (Opus 4.7, 1M context). Mistral Vibe (intent-router agent / mistral-medium-3.5) did the original audit identifying the 3 formats during Tâche 6 Phase A. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Mistral Vibe (devstral-2 / mistral-medium-3.5) Reviewed-on: #18 Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
3.4 KiB
3.4 KiB
Implement graceful shutdown with readiness endpoints
Status: Accepted Authors: Gabriel Radureau, AI Agent Date: 2026-04-03
Context and Problem Statement
We needed to implement a shutdown mechanism for dance-lessons-coach that provides:
- Clean resource cleanup
- Proper handling of in-flight requests
- Kubernetes/service mesh compatibility
- Minimal downtime for users
- Proper orchestration signaling
Decision Drivers
- Need for zero-data-loss shutdowns
- Desire for Kubernetes compatibility
- Requirement for proper resource cleanup
- Need for minimal user impact
- Desire for proper orchestration integration
Considered Options
- Graceful shutdown with readiness endpoints - Kubernetes-style shutdown
- Immediate shutdown - Simple but disruptive
- Delayed shutdown with queue draining - Complex but thorough
- Signal-based shutdown only - Basic graceful shutdown
Decision Outcome
Chosen option: "Graceful shutdown with readiness endpoints" because it provides the best combination of Kubernetes compatibility, proper resource cleanup, minimal user impact, and follows industry best practices for containerized services.
Pros and Cons of the Options
Graceful shutdown with readiness endpoints
- Good, because Kubernetes/service mesh compatible
- Good, because minimal user impact
- Good, because proper resource cleanup
- Good, because follows industry best practices
- Good, because allows proper orchestration
- Bad, because more complex to implement
- Bad, because requires additional endpoints
Immediate shutdown
- Good, because simplest to implement
- Bad, because disruptive to users
- Bad, because can lose in-flight requests
- Bad, because no resource cleanup
Delayed shutdown with queue draining
- Good, because very thorough
- Good, because minimal data loss
- Bad, because very complex
- Bad, because overkill for simple services
Signal-based shutdown only
- Good, because better than immediate shutdown
- Good, because allows some cleanup
- Bad, because not Kubernetes-compatible
- Bad, because still somewhat disruptive
Implementation Details
// Readiness context management
readyCtx, readyCancel := context.WithCancel(context.Background())
// Readiness endpoint handler
func (s *Server) handleReadiness(w http.ResponseWriter, r *http.Request) {
select {
case <-s.readyCtx.Done():
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(`{"ready":false}`))
default:
w.Write([]byte(`{"ready":true}`))
}
}
// Shutdown sequence
func (s *Server) shutdown() {
// Cancel readiness - stop accepting new requests
readyCancel()
// Wait for shutdown timeout
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Graceful server shutdown
s.server.Shutdown(shutdownCtx)
}
Links
Monitoring and Verification
# Check readiness during shutdown
while true; do curl -s http://localhost:8080/api/ready | jq; sleep 1; done
# Expected output during shutdown:
# {"ready":true}
# {"ready":true}
# {"ready":false} # When shutdown starts
# {"ready":false}
# ... (connection refused) # When server fully stopped