Add Rule 0 to values.schema.json enforcing miroir.replicas > 1 when
taskStore.backend is redis (HA mode requires multiple replicas).
This completes the Phase 3 Task Registry + Persistence epic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements the full 14-table task-store schema from plan §4 with both SQLite
and Redis backends sharing the TaskStore trait. Every §13/§14 advanced capability
consumes one or more of these tables.
SQLite backend:
- 3 migrations (001: tables 1-7, 002: tables 8-14, 003: task registry fields)
- WAL mode + busy_timeout for single-process concurrency
- Schema version tracking with SchemaVersionAhead guard
- Full CRUD + proptest round-trips on all 14 tables
- Restart resilience test: all data survives close/reopen cycle
Redis backend:
- Hash + _index SET pattern for O(cardinality) iteration (no SCAN)
- TTL-based expiration for sessions, idempotency, admin_sessions
- SET NX/XX for leader lease CAS operations
- Sorted sets for canary_runs with auto-prune
- Rate limiting keys for search_ui and admin_login
- CDC overflow buffer with byte-budget trimming
- Scoped key rotation coordination (observe/check pattern)
- Pub/sub for admin session revocation propagation
- testcontainers integration tests for all 14 tables + extras
Helm chart:
- values.schema.json enforces redis backend when replicas > 1
- ESO ExternalSecret template for OpenBao integration
- Updated values with secret inventory and rate limiting config
Config validation:
- replication_factor/replica_groups > 1 requires redis
- HPA enabled requires redis
- CDC overflow=redis requires redis task store
- Leader election required when replica_groups > 1
- CSP/CORS wildcard rejection
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Wire readinessProbe to /_miroir/ready (returns 503 until covering
quorum reachable) instead of /health (always 200)
- Fix MiroirPeerDiscoveryGap alert to use miroir_peer_pod_count metric
instead of non-existent miroir_peer_known
- Align MiroirHighSearchLatency, MiroirSettingsDivergence, and
MiroirAntientropyMismatch alert expressions with registered metric
names per plan §10
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements plan §13.21 leader-based rotation of per-index scoped search
keys with zero-403 overlap guarantees:
- Leader lease (Redis, Mode B §14.5) serializes rotation across pods
- Per-pod beacon with 60s TTL refreshed on every search request
- Revocation safety gate: leader checks all live peers observed new
generation before DELETE /keys/{previous_uid}
- Drain wait (default 120s) for stragglers before revocation
- Auto-rotation trigger: scoped_key_rotate_before_expiry_days (30d)
before scoped_key_max_age_days (60d)
- Manual trigger: POST /_miroir/ui/search/{index}/rotate-scoped-key
with force:true to bypass timing gate
- Config validation rejects rotate_before >= max_age at startup
- Helm _helpers.tpl render-time guard against rotation loop
- values.schema.json schema validation for scoped key config fields
Also includes session management routes (admin login/logout/session,
search UI JWT session) and auth middleware CSRF protection needed
by the admin-gated rotation endpoint.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Expand eso-external-secret.yaml with full secret inventory (plan §9) —
documents all 8 keys with consumer, rotation strategy, and env var mapping.
Wire ADMIN_SESSION_SEAL_KEY, SEARCH_UI_JWT_SECRET,
SEARCH_UI_JWT_SECRET_PREVIOUS, and SEARCH_UI_SHARED_KEY into the Helm
deployment template as optional secretKeyRef env vars. Add startup
validation that refuses to start if search_ui is enabled but
SEARCH_UI_JWT_SECRET is missing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add collapsed Resharding (§13.1) feature-gated row with phase gauge,
in-progress stat, and backfill rate panel. Fix overlapping y=74 on
Anti-Entropy and Settings Broadcast rows by shifting subsequent rows.
Sync charts/miroir/dashboards/ copy with root dashboard.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PVC template conditional on cdc.buffer.primary=="pvc" or cdc.buffer.overflow=="pvc"
- Redis deployment conditional on redis.enabled with auth via auto-generated or ESO secret
- ESO ExternalSecret example pulling from kv/search/miroir via openbao-backend ClusterSecretStore
- Deployment mounts CDC PVC at /data/cdc and injects Redis password when enabled
- ConfigMap generates taskStore.url and cdc.buffer.pvc_path from helpers
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Simplify values.schema.json if/then patterns for rules 3-4 (removed
verbose allOf in favor of direct enum constraint in then branch),
drop unsupported errorMessage fields, and add run-tests.sh for
automated CI validation of all 12 schema/template test cases.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Full chart structure with 14 templates, values.schema.json, and NOTES.txt.
Dev defaults: 1 replica, 64 shards, RF=1, RG=1, sqlite task store, HPA off.
Production upgrade path documented in NOTES.txt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ServiceMonitor scrapes the metrics port (9090) at 30s intervals.
PrometheusRule ships all 12 alerts: 7 availability (degraded shards,
node down, high latency, stuck tasks, stuck rebalance, settings
divergence, anti-entropy mismatch) + 5 resource pressure (memory,
request queue, background queue, peer discovery, no leader).
Both gated behind serviceMonitor.enabled / prometheusRule.enabled
(defaults: false — requires prometheus-operator in cluster).
Also adds metrics port to the miroir Service so ServiceMonitor can
select it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>