From afca403fcac0e7bc25de43a96c663a14dd9a2755 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 16 Sep 2026 15:31:09 +0200 Subject: [PATCH] Refuse identical lens weights as no change (L1 c2.s1.f1) An owner's SetLensWeights equal to the world's current weights committed: the revision advanced and the digests moved though nothing canonical changed. `reduce` now refuses it with PatchRejected([NoCanonicalChange]) after admission, so the live submit and replay share the rule and nothing commits. The order is capability, owner, draw rule, then equality: a non-owner's identical set stays Unauthorized, and an identical set that never draws stays LensWeightsNeverDraw. The SetLensWeights doc stated the old rule and now states this one. Tests: the in-crate soul test's pin of the old commit becomes the refusal, with the order pinned (non-owner identical is Unauthorized; an identical all-zero set against a hand-built state is LensWeightsNeverDraw) and the store reopened to the same head. external_admission gains identical_lens_weights_from_the_owner_commit_nothing through the public mailbox: revision, state digest, last commit digest and operator log length unchanged, non-owner identical Unauthorized, a different set commits. Co-Authored-By: Claude Opus 5 --- crates/ghostlight/src/lib.rs | 70 ++++++++++++++++--- crates/ghostlight/tests/external_admission.rs | 59 +++++++++++++++- 2 files changed, 119 insertions(+), 10 deletions(-) diff --git a/crates/ghostlight/src/lib.rs b/crates/ghostlight/src/lib.rs index 1937276..98f458d 100644 --- a/crates/ghostlight/src/lib.rs +++ b/crates/ghostlight/src/lib.rs @@ -680,9 +680,10 @@ pub enum CommandBody { }, /// Replaces the world's whole lens weight set. Owner only, in any phase, /// under genesis admission: a set that never draws is refused, and a zero - /// weight is admitted and never draws. Identical weights are still a - /// commit, because the owner's act is canonical. A session that already - /// drew keeps its recorded lens. + /// weight is admitted and never draws. A set equal to the current one + /// changes nothing canonical and is refused with `NoCanonicalChange` + /// after admission, so nothing commits. A session that already drew + /// keeps its recorded lens. SetLensWeights { weights: LensWeights, }, @@ -1682,6 +1683,14 @@ fn reduce(state: &WorldState, command: &CommandEnvelope) -> Result