Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.7.0] — 2026-07-15

**Replication GA for multi-shard masters.** Moon now supports real Redis-compatible
asynchronous replication with `WAIT`/`ACK` acknowledgement semantics: a multi-shard
master (`--shards N`) streams a merged, exactly-once command feed to a single-shard
streaming replica across all data planes — KV, vector/text index, graph, workspace (WS),
message-queue (MQ), and temporal. Every write plane is crash-durable and survives
`kill -9` on either side, validated by a 24h continuous-load kill-9 soak (alternating
master/replica restarts every 12 min) that asserts zero loss of any `WAIT`-acknowledged
write. Also folds in the full v0.6.1 hardening scope (WAL v3 storage-kernel M1–M4:
cross-plane crash matrix, unified per-shard WAL-recycle floor, atomic durable writes,
FTS term-dict durability) and a supply-chain CI gate (`cargo audit` + `cargo deny`).

Soak evidence (release gate REPL-SOAK-01): `SOAK-PASS duration=86400s cycles=114
acked=82044 inflight=7 master_kills=57 replica_kills=57` — 82,044 WAIT-acked writes
preserved across 114 alternating kill-9 cycles, zero acked-write loss (2026-07-15,
run dir `moon-soak/runs/20260714-141946`, RC `e2d87893`).
Comment on lines +22 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

The soak is documented as a tag gate, but the supplied release workflow does not enforce it for v0.7.0.

  • CHANGELOG.md#L22-L25: either wire REPL-SOAK-01 into an enforcing release step or describe it as completed/manual evidence.
  • docs/PRODUCTION-CONTRACT.md#L129-L129: remove the claim that the row gates the v0.7.0 tag unless the workflow is changed to block that tag.
📍 Affects 2 files
  • CHANGELOG.md#L22-L25 (this comment)
  • docs/PRODUCTION-CONTRACT.md#L129-L129
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 22 - 25, Update CHANGELOG.md lines 22-25 to
describe REPL-SOAK-01 as completed/manual evidence, unless the release workflow
is changed to enforce it for v0.7.0. Update docs/PRODUCTION-CONTRACT.md line 129
to remove the claim that this evidence gates the v0.7.0 tag unless such
enforcement is added.


Known limitation: the streaming replica is single-shard only (`--shards 1`) — the
multi-shard work in this release is master-side (merged N-shard PSYNC feed). Multi-shard
replicas are roadmapped for v0.8/v0.9.

Replica TTL semantics (disclosure): relative-expire commands (`EXPIRE`, `SETEX`, `PEXPIRE`,
`GETEX` with a relative TTL) currently replicate verbatim rather than being rewritten to
absolute `PEXPIREAT` on the master, and replicas run their own active-expiry cycle
regardless of role. In practice keys expire correctly on both sides under normal clock
sync, but a master/replica clock skew can shift a relative-TTL key's expiry moment between
the two by up to that skew. Absolute-expiry rewrite + role-gated passive expiry land in
v0.7.1 (task #71b). Applications needing exact cross-node expiry parity should set
absolute deadlines with `PEXPIREAT` until then.

### Fixed — `segment_plane_scan` missed v0.6.0's nested-Command plane framing, risking WS/MQ/temporal data loss on upgrade (task #69)

`WalWriterV3::recycle_aggressive`/`recycle_segments_before` gate deletion of
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "moon"
version = "0.6.0"
version = "0.7.0"
edition = "2024"
rust-version = "1.94"
description = "A high-performance Redis-compatible server written in Rust"
Expand Down
5 changes: 5 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Releases

## v0.7.0 — 2026-07-15
milestones: v0.7.0 "Replication GA for multi-shard masters" (soak-gated tag; v0.6.1 hardening folded in)
waivers: none — the v0.6.0 `shardslice-migration` waiver (was: expires 2026-08-01) is **retired**; lock-free cross-shard read work is now tracked as an open GA gap (`XSHARD-READ-01`, ROADMAP R4), not a time-boxed waiver.
Comment on lines +3 to +5

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Synchronize the waiver status with the production-contract ledger.

This release entry says the shardslice-migration waiver is retired, but docs/PRODUCTION-CONTRACT.md Line 132 still says it expires on August 1, 2026 and remains unstarted. Update one ledger so both documents consistently represent whether XSHARD-READ-01 is a retired waiver or an active open obligation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@RELEASES.md` around lines 3 - 5, Synchronize the production-contract ledger
with the v0.7.0 release entry: update the XSHARD-READ-01/shardslice-migration
status in the ledger so it no longer shows an active August 1, 2026 waiver and
instead matches the release’s retired-waiver, open-GA-gap state.

evidence: Real async replication with WAIT/ACK across all six data planes (KV, vector/text, graph, WS, MQ, temporal); multi-shard master → single-shard streaming replica; every plane crash-durable under kill -9. Plus full v0.6.1 hardening (WAL v3 storage-kernel M1–M4) and a supply-chain CI gate (cargo audit + cargo deny). Release gate — 24h replication kill-9 soak (REPL-SOAK-01), zero acked-write loss: `SOAK-PASS duration=86400s cycles=114 acked=82044 inflight=7 master_kills=57 replica_kills=57` (2026-07-15; run dir moon-dev:~/moon-soak/runs/20260714-141946; RC main e2d87893; 114 alternating master/replica kill -9 cycles, 82,044 WAIT-acked writes preserved). Known limitation: streaming replica is single-shard only. Replica relative-TTL semantics: verbatim replication (no PEXPIREAT rewrite) + role-agnostic active expiry — absolute-rewrite lands in v0.7.1 (task #71b).

## v0.6.0 — 2026-07-08
milestones: v0.6.0-release (PR #249, six workstreams)
waivers: shardslice-migration (expires 2026-08-01; retirement planned with v0.7 L4 cross-shard-read work)
Expand Down
4 changes: 2 additions & 2 deletions docs/PRODUCTION-CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ per the CI gate · Blocking `—` = tracked but never blocks a tag (see Out of S
| ✅ | CHANGELOG-01 | CHANGELOG.md CI gate on every PR (skip-changelog label escape hatch) | `ci.yml` step `CHANGELOG check` | GA |
| ✅ | REL-LEDGER-01 | Release tag requires a matching `RELEASES.md` entry | `release.yml` step `Require RELEASES.md entry for this tag` | GA |
| ✅ | CONTRACT-01 | This document is a checked ledger with a CI-wired gate | `scripts/check-production-contract.sh`, `release.yml` | GA |
| | SUPPLY-01 | `cargo audit` + `cargo deny` CI-blocking | `deny.toml` exists but no CI job runs the tools. Dedicated `supply-chain.yml` workflow in flight (task #63, 2026-07-14) — tick when merged and green. | GA |
| | SUPPLY-01 | `cargo audit` + `cargo deny` CI-blocking | Shipped (task #63, PR #326): `.github/workflows/supply-chain.yml` runs `cargo audit` + `cargo deny` on push/PR with `deny.toml` policy. Folded into v0.7.0. | GA |

### B. Correctness Hardening

Expand Down Expand Up @@ -126,7 +126,7 @@ per the CI gate · Blocking `—` = tracked but never blocks a tag (see Out of S
| ✅ | REPL-MULTISHARD-01 | Multi-shard master replication (a `--shards N>1` master can be replicated at all) | R2 (task #20): `ShardMessage::PrepareReplicaSync` per-shard atomic snapshot legs + merged Redis-format RDB + per-record SELECT framing on the merged wire. monoio only; replicas run `--shards 1`; partial resync degrades to full at N>1. `tests/replication_multishard.rs` (2/4/8-shard resync, interleaved multi-db parity, graph, partial→full). | GA |
| ✅ | WAIT-01 | `WAIT` reflects real replica ACK state | R1 (task #19, PR #282): replica 1s `REPLCONF ACK` ticker on the split PSYNC socket; master `ack_read_loop` + `drain_ack_offsets` record into `ReplicaInfo.ack_offsets`; connection-layer `try_handle_wait` blocks until ACK ≥ target or timeout. `wait_returns_acked_replica_count` e2e; exact on multi-shard masters too (summed snapshot offset). | GA |
| ✅ | REPL-PLANES-01 | Every write plane replicates, not just KV: eviction/expiry DELs, Lua effects, graph, vector/text index defs+contents, WS.*, MQ.*, TEMPORAL.* | Wave A (PR #285): eviction/expiry DELs + Lua effects to both planes (EVAL was previously durable in neither). Wave B (PR #294 + task #34): WS/MQ deterministic records + replica apply + PSYNC registry blob. Graph plane (task #25): live GRAPH.* streaming + snapshot backfill. Suites: `tests/replication_planes.rs`, `replication_graph.rs`, `replication_mq.rs`, `replication_readonly_ws_mq.rs`. Unified poison-record policy for replica apply (task #48). | GA |
| | REPL-SOAK-01 | 24h replication soak: kill -9 either side under WAIT-confirmed load, zero acked-write loss | Harness in flight (task #61: `scripts/soak-replication-24h.sh`); the run (task #62) gates the v0.7.0 tag. | GA |
| | REPL-SOAK-01 | 24h replication soak: kill -9 either side under WAIT-confirmed load, zero acked-write loss | **PASSED 2026-07-15** — `SOAK-PASS duration=86400s cycles=114 acked=82044 inflight=7 master_kills=57 replica_kills=57`; 82,044 WAIT-acked writes preserved across 114 alternating kill-9 cycles, zero acked-loss. Run dir `moon-soak/runs/20260714-141946`, RC `e2d87893`. Gates the v0.7.0 tag (task #65). | GA |
| ⬜ | KEYSPACE-NOTIF-01 | `notify-keyspace-events` keyspace notifications | No implementation found in `src/`. ROADMAP v0.7.0 workstream R5 — deferred to v0.7.1 (one-headline rule). | GA |
| ⬜ | MONITOR-01 | `MONITOR` command | No implementation found in `src/command/`. ROADMAP v0.7.0 workstream R5. | GA |
| ⬜ | XSHARD-READ-01 | Lock-free cross-shard read path (retire the shardslice waiver) | Waiver **expires 2026-08-01** per `RELEASES.md` v0.6.0 entry and ROADMAP §5; L4 redesign (`tmp/MULTISHARD-REDESIGN.md`) unstarted. ROADMAP v0.7.0 workstream R4. | GA |
Expand Down
Loading