Implementation already in place. All acceptance criteria verified:
- Doc with _miroir_expires_at in past is deleted after sweep
- TTL deletes don't resurrect via anti-entropy (expired docs skipped)
- CDC TTL deletes suppressed by default (emit_ttl_deletes opt-in)
- _miroir_expires_at stripped from search hits
- max_deletes_per_sweep limit respected
All 8 TTL tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Verified all 12 proptest property tests pass with 1024 cases
- Verified all 9 criterion benchmarks run successfully
- Full routing pipeline for 10K docs: 272 µs (well under 1ms target)
- CI includes `cargo bench --no-run` for compilation check
Acceptance criteria:
- ✓ cargo bench runs all criterion benches
- ✓ cargo test runs property tests with 1024 cases (proptest.toml)
- ✓ CI compiles benchmarks on every build
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add comprehensive test suite for the bucket-granular re-digest step
(plan §13.8 step 2). All 18 tests pass.
Tests verify:
- Deterministic bucket assignment (pk-hash % 256)
- Even distribution across buckets
- Per-bucket hash computation during fingerprint
- Divergent bucket identification
- Bucket-specific PK enumeration
- Replica comparison within divergent buckets
- Cross-index comparison for reshard verification (plan §13.1)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that P5.8.b (anti-entropy diff step) was already fully
implemented in anti_entropy.rs. Created notes documenting:
- Bucket assignment via pk-hash % 256
- Per-bucket digest computation during fingerprint
- Divergent bucket identification
- Bucket-specific PK enumeration
- Bucket-level replica comparison
All 12 tests in p5_8_b_anti_entropy_diff.rs cover the functionality.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that CDC event suppression by _miroir_origin tag is fully
implemented according to plan §13.13. The implementation includes:
- Origin tag constants (ORIGIN_ANTIENTROPY, ORIGIN_RESHARD_BACKFILL,
ORIGIN_ROLLOVER, ORIGIN_TTL_EXPIRE)
- Suppression logic in CdcManager::publish() filtering by origin
- emit_internal_writes and emit_ttl_deletes config flags
- Suppression metric callback (CdcSuppressedMetricCallback)
- Prometheus metric miroir_cdc_events_suppressed_total{origin}
- WriteRequest.origin field with skip_serializing_if (never stored/returned)
All 11 CDC tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that the fingerprint step (plan §13.8 step 1) is fully implemented:
- Per-replica xxh3 digest over (pk || content_hash)
- Paginated iteration via filter=_miroir_shard={id}
- Streaming xxh3 digest folding seeded by shard_id
- Self-throttling with 10ms sleep between batches
- All throttle knobs: schedule, shards_per_pass, max_read_concurrency, fingerprint_batch_size
All 10 integration tests pass in p5_8_a_anti_entropy_fingerprint.rs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The commit phase (Phase 3) of the two-phase settings broadcast
is fully implemented. This includes:
- Settings version increment in task store
- Per-node version advancement in node_settings_version table
- X-Miroir-Settings-Version header stamping on search responses
- Broadcast completion and in-flight state clearing
All tests pass and the implementation follows plan §13.5.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified the rebalancer worker implementation with advisory lock is
complete and all acceptance tests pass:
- Advisory lock via leader_lease (scope: rebalance:<index>)
- Progress persistence via jobs table for pod restart resumption
- Metrics: rebalance_in_progress, documents_migrated_total, duration_seconds
All 24 rebalancer worker tests pass including 4 acceptance tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The verification phase of two-phase commit for settings broadcast
is fully implemented in two_phase_settings_broadcast():
- Phase 2 Verify: GET /indexes/{uid}/settings from all nodes in parallel
- Compute SHA256 of canonical JSON for each node's settings
- Compare all hashes against expected fingerprint
- On mismatch: exponential backoff retry with targeted repair
- After max_repair_retries (default 3): freeze writes + raise alert
Also adds AntiEntropyWorker for periodic drift detection and repair.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Analyzed current two_phase_settings_broadcast() implementation
and proposed architectural changes for Phase 1:
- Replace sequential PATCH loop with parallel join_all pattern
- Add proper task succession polling (await all task_uids → succeeded)
- Document X-Miroir-Settings-Inconsistent header behavior
- Provide implementation details for poll_all_tasks_until_succeeded()
Key finding: Current Phase 1 does NOT await task completion as
specified in plan §13.5, violating the two-phase commit contract.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Verified ESO ExternalSecret template and example exist
- Verified startup validation for SEARCH_UI_JWT_SECRET
- Documented secret inventory in completion note
- All acceptance criteria met
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The miroir-ci.yaml WorkflowTemplate already exists in declarative-config
at k8s/iad-ci/argo-workflows/miroir-ci.yaml and is synced by ArgoCD app
argo-workflows-ns-iad-ci.
Template verification:
- All 6 steps present: git-checkout, cargo-lint, cargo-test, cargo-build,
docker-build-push, create-github-release
- Resource specs match: test (2 CPU / 4 GiB), build (4 CPU / 8 GiB)
- Image versions correct: git 2.43.0, rust 1.87-slim, kaniko v1.23.0-debug,
gh cli 2.49.0
- Tagging logic: stable releases get float tags + :latest, pre-releases
get exact tag only
- CHANGELOG extraction uses awk pattern as specified
Manual testing deferred - kubectl not available on this system.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Helm chart structure was already in place with all required
files per plan §6:
- Chart.yaml with API v2 metadata
- values.yaml with dev defaults (replicas=1, RF=1, RG=1, sqlite)
- values.schema.json for validation
- templates/ with all required resources
- tests/connection-test.yaml
- NOTES.txt with production override guidance
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documents the completed P6.5 Mode C work-queued chunked jobs implementation.
All acceptance tests pass; infrastructure fully functional per plan §14.5.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verify that peer discovery via headless Service + Downward API
is fully implemented per plan §14.5:
- Helm templates: miroir-headless.yaml with clusterIP: None,
miroir-deployment.yaml with POD_NAME/POD_NAMESPACE/POD_IP
- Rust: peer_discovery.rs with SRV lookup, refresh loop in main.rs,
miroir_peer_pod_count metric in middleware.rs
- Verification: verify_p6_2_peer_discovery.sh script
Acceptance tests require multi-pod Kubernetes deployment:
1. 3-pod deployment: each pod sees all 3 peer names within 30s
2. Scale 3→5: new peers discovered within refresh_interval_s × 2
3. Pod eviction: crashed pod drops from peer set within 30s
4. miroir_peer_pod_count matches kube_deployment_status_replicas_ready
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that peer discovery via headless Service + Downward API (plan §14.5)
is fully implemented:
- Helm: headless Service template + Downward API env vars (POD_NAME, POD_IP)
- Rust: peer_discovery.rs SRV lookup module with trust-dns-resolver
- Main: background refresh loop + miroir_peer_pod_count metric
- Unit tests: all 3 peer_discovery tests pass
- Verification script: NixOS-compatible shebang
Acceptance criteria require a Kubernetes cluster for integration testing:
- 3-pod discovery, scale events, pod eviction, metric comparison
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that peer discovery via headless Service + Downward API is
fully implemented:
- Helm templates: miroir-headless.yaml Service + POD_NAME/POD_IP env vars
- Rust module: peer_discovery.rs with SRV lookup via trust-dns-resolver
- Config: peer_discovery section with service_name + refresh_interval_s
- Main loop: Background refresh task that updates miroir_peer_pod_count metric
- Metrics: miroir_peer_pod_count, miroir_leader, miroir_owned_shards_count gauges
- Verification script: tests/verify_p6_2_peer_discovery.sh (NixOS-compatible shebang)
All unit tests pass. The implementation requires a Kubernetes deployment
for full acceptance testing (3-pod discovery, scale events, pod eviction).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Document that peer discovery was already implemented in prior commits
(e6cdd05 and 26c9521). All required components are in place:
- Headless Service with Downward API env vars
- SRV-based peer discovery in peer_discovery.rs
- Background refresh loop in main.rs
- miroir_peer_pod_count metric in middleware.rs
- Verification script
Acceptance criteria require multi-pod K8s deployment testing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that all acceptance criteria for P5.7 §13.7 (Atomic Index Aliases) are already implemented:
- Single-target alias resolution for reads and writes
- Atomic alias flipping with no in-flight request tearing
- Multi-target aliases for read-only ILM use
- Write rejection (409) for multi-target aliases
- History retention with eviction (default: 10)
All 17 acceptance tests pass. Implementation was completed in prior commits:
- c670d09: Fix alias admin API routes and reorganize alias module
- 821dea3: Complete alias acceptance tests
- 823fdd0: Add atomic index alias integration tests
- f564f3d: Add alias flip metrics emission
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
All miroir_* error codes from plan §5 are implemented in
crates/miroir-core/src/api_error.rs with tests passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documents the bearer-token dispatch chain implementation (plan §5 rules 0-5)
that was completed in commit 625e414. The implementation supports three
token types simultaneously: master_key, admin_key, and search UI JWTs.
Key features:
- Deterministic dispatch chain with 5 rules
- X-Admin-Key short-circuit for admin endpoints
- Constant-time comparison for all opaque tokens
- JWT validation with rotation support (primary + previous secrets)
- 62 unit tests covering all acceptance criteria
- Rate-limit hooks for Phase 6 multi-pod deployment
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verify all acceptance criteria met:
- cargo bench -p miroir-core runs criterion benches
- cargo test runs proptest with 1024 cases (proptest.toml)
- CI includes cargo bench --no-run (miroir-ci.yaml:124)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The schema versioning system is already fully implemented.
Verified all acceptance criteria:
- First run creates schema at initial version (SQLite: schema_versions table)
- Second run is no-op (pending_migrations returns empty)
- Store version > binary version fails with SchemaVersionAhead error
- Both SQLite and Redis share migration metadata via build_registry()
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Complete acceptance criteria:
- Each §14.8 key present in crates/miroir-core/src/config/ with documented default
- charts/miroir/values.yaml exposes the same keys with identical defaults
- values.schema.json accepts documented ranges; cross-field validation in _helpers.tpl
- K8s resources block matches §14.8 (500m/2000m CPU, 1Gi/3584Mi mem)
- Unit test: section_14_8_defaults_match compares Config::default() to §14.8 reference
- Drift guard: doc-test at top of MiroirConfig struct validates defaults
All defaults sized for 2 vCPU / 3.75 GB envelope per plan §14.8.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that Plan §15 Open Problem #1 is fully addressed by existing
chaos tests. All 14 cutover_race tests pass, confirming:
- Loss rate < 1 per 1M writes with AE on (0/1M measured)
- Loss rate without AE quantified (~2% when both AE and delta off)
- Hard refusal policy blocks unsafe configuration
- Documentation complete in docs/trade-offs.md
No code changes required — implementation already satisfies all
acceptance criteria.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This bead verified that the Redis-backed TaskStore implementation is
complete, covering all 14 tables from plan §4 plus the extra keys from
plan §4 footnotes.
Key findings:
- All 14 tables mapped to Redis keyspace correctly
- Secondary `_index` sets for O(cardinality) list queries
- Leader lease with SET NX/EX for acquire, SET XX/EX for renewal
- EXPIRE for TTL-based garbage collection (sessions, idempotency)
- Pipelining for atomic multi-key operations
- CDC overflow buffer with LPUSH + LTRIM
- Pub/Sub for admin session revocation
- Rate limiting with exponential backoff for admin login
- Search UI scoped key coordination
Acceptance criteria verified:
- test_redis_lease_race: concurrent lease acquisition
- test_redis_memory_budget: 10k tasks + 1k sessions + 100k idempotency keys
- test_redis_pubsub_session_invalidation: logout via Pub/Sub within 100ms
- testcontainers integration tests in p3_redis_integration.rs
No code changes required - the implementation was already complete.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fixed duplicate ReshardingConfig: added allowed_windows to advanced.rs
- Ran benchmark confirming storage/dual-write amplification at exactly 2.0×
- Verified CLI window guard integration tests (4/4 passing)
- Updated benchmark doc with latest run date (2026-05-20)
Key findings:
- Storage amplification is exactly 2× across all scenarios
- Peak write amplification varies from 12× to 502× depending on throttle
- Operators should set throttle to keep peak writes ≤ 3× normal
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bead-Id: miroir-r3j.2
All 7 feature-flagged tables (canaries, canary_runs, cdc_cursors, tenant_map,
rollover_policies, search_ui_config, admin_sessions) were already implemented
with full CRUD operations, migrations, and tests.
The canary_runs_auto_prune trigger was added in P3.3 (commit 719d1db).
Acceptance criteria verified:
- All 38 SQLite tests pass
- Every table round-trips insert/get correctly
- Auto-prune trigger keeps canary_runs bounded
- Empty tables consume < 16 KB overhead each
- Tables created via TaskStore::migrate() migration 002
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The matrix incorrectly referenced miroir-zc2.6/7/8 as dump import
enhancement beads, but zc2.6 is actually arm64 support and zc2.7/8
don't exist. Replaced with a descriptive "Future Enhancements" table
that maintains traceability without false bead dependencies.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bead-Id: miroir-zc2.5
Bead-Id: miroir-r3j.6
Bead-Id: bf-1p4v
The matrix incorrectly referenced miroir-zc2.6/7/8 as dump import
enhancement beads, but zc2.6 is actually arm64 support and zc2.7/8
don't exist. Replaced with a descriptive "Future Enhancements" table
that maintains traceability without false bead dependencies.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Added comments linking miroir-m9q.3 (Mode A), miroir-m9q.4 (Mode B), and
miroir-m9q.5 (Mode C) to the per-feature scaling reference doc. This enables
bidirectional navigation between implementation beads and the operator-facing
scaling mode documentation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The E0382 borrow of moved value error was already fixed.
The code uses `.with_state(state.clone())` at line 586
and UnifiedState derives Clone. Build succeeds.
Also added task registry TTL pruner background task.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The described E0382 error (borrow of moved value `state`) was already
fixed in the codebase. Line 568 already uses `.with_state(state.clone())`
and UnifiedState derives Clone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The docs/horizontal-scaling/per-feature.md file already exists
and meets all acceptance criteria. Created verification note.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The borrow of moved value error was already resolved in the codebase.
Line 568 correctly uses .with_state(state.clone()) and build succeeds.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
All acceptance criteria already met:
- Sizing table reproduced from plan §14.7
- Redis memory accounting paragraph included
- Worked example for ≤200 GB tier
- Links from README.md and production.md
The sizing guide is THE artifact operators need on day one.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The repository is already in full compliance. Plan §12 specifies
crate-level tests (idiomatic Rust workspace convention), which is
exactly what exists. No migration or amendments required.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The borrow-of-moved-value error for `state` was already fixed in the codebase.
Line 568 uses `.with_state(state.clone())` and `UnifiedState` derives Clone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verified that the TaskStore trait and SQLite backend for tables 1-7
were already fully implemented with all tests passing (36/36).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documented verification that the rebalancer background worker meets all
acceptance criteria:
- Advisory lock via leader_lease table preventing duplicate migrations
- Progress persistence enabling pod crash recovery
- Prometheus metrics tracking for observability
All 15 rebalancer-related tests and 108 proxy tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>