diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
-# 0.1.0.0
+# 0.2.0 (2021-10-24)
+
+* Downgrade the `unSNumber` field selector to be unidirectional.
+  * It could previously be used with record update syntax to construct invalid
+    `SNumbers` out of valid ones.
+  * Migration: Replace record updates of `unSNumber` with `N#`.
+* Add an `SN` pattern synonym for safely extracting an `SNumber` value without
+  `MagicHash`.
+
+# 0.1.0.0 (2021-09-08)
 
 Initial version.
diff --git a/snumber.cabal b/snumber.cabal
--- a/snumber.cabal
+++ b/snumber.cabal
@@ -1,14 +1,12 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.33.0.
+-- This file has been generated from package.yaml by hpack version 0.34.4.
 --
 -- see: https://github.com/sol/hpack
---
--- hash: 1d0ab9e8374cc94aff152971e0a8de1ddbc04e736cfa1bffd8722cff99b603c6
 
 name:           snumber
-version:        0.1.0.0
-synopsis:       Indexed numeric types linking type-level and value-level numbers.
+version:        0.2.0
+synopsis:       Integer singletons with flexible representation
 description:    This provides singletons-style witnesses for type-level integers, and some
                 limited arithmetic operations on them.  Instead of working with (invisible,
                 implicitly-passed) 'KnownNat' instances, you can work with (visible,
@@ -39,10 +37,9 @@
       Data.SNumber
   other-modules:
       Data.SNumber.Internal
-      Paths_snumber
   hs-source-dirs:
       src
   build-depends:
       base >=4.12 && <4.16
-    , numeric-kinds >=0.1 && <0.2
+    , numeric-kinds ==0.1.*
   default-language: Haskell2010
diff --git a/src/Data/SNumber.hs b/src/Data/SNumber.hs
--- a/src/Data/SNumber.hs
+++ b/src/Data/SNumber.hs
@@ -40,10 +40,13 @@
 
 module Data.SNumber
          ( -- * SNumber
-           SNumber(N#, SNumber, unSNumber), SNumberRepr(..)
+           SNumber(SNumber, N#, SN, unSNumber), SNumberRepr(..)
 
            -- ** Creation
-         , snumber, trySNumber, unsafeUncheckedSNumber
+         , snumber, trySNumber
+
+           -- *** Unsafe
+         , unsafeUncheckedSNumber
          , unsafeMkSNumber, unsafeTryMkSNumber, unsafeUncheckedMkSNumber
 
            -- ** Existentials
@@ -195,8 +198,20 @@
 -- that it isn't actualy a newtype constructor, so having it in scope doesn't
 -- allow unsound coercions across 'SNumber' types.
 pattern N# :: forall (n :: K.Integer) a. a -> SNumber a n
-pattern N# {unSNumber} = MkSNumber# unSNumber
+pattern N# x = MkSNumber# x
 {-# COMPLETE N# #-}
+
+-- | A unidirectional pattern for matching 'SNumber's.
+--
+-- This allows the pseudo-field-selector 'unSNumber' to be exported bundled
+-- with 'SNumber', so it can be imported by @SNumber(..)@ as if it were a
+-- normal field selector of a record definition.  If this were done as part of
+-- 'N#', it'd allow unsafely changing an 'SNumber'\'s representation without
+-- using any identifiers that indicate unsafety, by way of record update
+-- syntax.
+pattern SN :: forall (n :: K.Integer) a. a -> SNumber a n
+pattern SN {unSNumber} <- MkSNumber# unSNumber
+{-# COMPLETE SN #-}
 
 data KnownSNumberDict a n = KnownSNumber a n => KnownSNumberDict
 
