Replace planning-era names and squash initial schema

Use descriptive test and executable names so implementation surfaces do not depend on journal organization. Consolidate the unreleased migration history into the authoritative initial schema because no deployed database requires an upgrade path.
This commit is contained in:
ms2k 2026-07-19 15:21:24 +09:00
commit 15eb0038d2
4 changed files with 299 additions and 436 deletions

View file

@ -36,19 +36,11 @@ main = do
withDb config $ \database -> do
migrate database "sql" config
migrate database "sql" config
emptyCatalog <- schemaCatalog database
resetSchema database
installLegacySchema database
migrate database "sql" config
migrate database "sql" config
adoptedCatalog <- schemaCatalog database
assertEqual "legacy and empty migration schema equivalence"
emptyCatalog adoptedCatalog
verifySchema database
verifyAdmission database config
store <- newS3 config
verifyStorage config store
putStrLn "WP-04 integration gate passed"
putStrLn "Storage foundation integration gate passed"
verifySchema :: Db -> IO ()
verifySchema database = do
@ -71,71 +63,9 @@ verifySchema database = do
"SELECT filename FROM schema_migrations ORDER BY filename"
:: IO [Only Text]
assertEqual "migration history"
[ "001_schema.sql"
, "002_pool_limit_guard.sql"
, "003_recovery_settlement.sql"
]
["001_initial_schema.sql"]
(map fromOnly migrations)
schemaCatalog :: Db -> IO [Text]
schemaCatalog database = do
rows <- Db.query_ database
"SELECT description FROM ( \
\SELECT 'column|' || table_name || '|' || ordinal_position::text || '|' \
\ || column_name || '|' || data_type || '|' || is_nullable || '|' \
\ || COALESCE(column_default, '') AS description \
\FROM information_schema.columns \
\WHERE table_schema = 'public' \
\UNION ALL \
\SELECT 'constraint|' || c.relname || '|' || con.conname || '|' \
\ || con.contype::text || '|' || pg_get_constraintdef(con.oid) \
\FROM pg_constraint con \
\JOIN pg_class c ON c.oid = con.conrelid \
\JOIN pg_namespace n ON n.oid = c.relnamespace \
\WHERE n.nspname = 'public' \
\UNION ALL \
\SELECT 'index|' || tablename || '|' || indexname || '|' || indexdef \
\FROM pg_indexes WHERE schemaname = 'public' \
\) catalog ORDER BY description"
:: IO [Only Text]
pure (map fromOnly rows)
resetSchema :: Db -> IO ()
resetSchema database = do
_ <- Db.execute_ database
"DROP TABLE IF EXISTS schema_migrations, key_locks, objects_meta, \
\mutations, pools CASCADE"
pure ()
installLegacySchema :: Db -> IO ()
installLegacySchema database = do
mapM_ (Db.execute_ database)
[ "CREATE TABLE pools ( \
\pool_id TEXT PRIMARY KEY, \
\limit_bytes BIGINT NOT NULL CHECK (limit_bytes > 0), \
\used_bytes BIGINT NOT NULL DEFAULT 0 CHECK (used_bytes >= 0), \
\reserved_bytes BIGINT NOT NULL DEFAULT 0 CHECK (reserved_bytes >= 0))"
, "CREATE TABLE mutations ( \
\user_id TEXT NOT NULL, kind TEXT NOT NULL, operation_id TEXT NOT NULL, \
\pool_id TEXT NOT NULL REFERENCES pools (pool_id), object_key TEXT NOT NULL, \
\relative_path TEXT NOT NULL, declared_size BIGINT NOT NULL, \
\content_sha256 TEXT, prior_size BIGINT NOT NULL, prior_sha256 TEXT, \
\growth_bytes BIGINT NOT NULL, state TEXT NOT NULL, \
\external_state TEXT NOT NULL DEFAULT 'idle', \
\created_at TIMESTAMPTZ NOT NULL DEFAULT now(), \
\updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), \
\PRIMARY KEY (user_id, kind, operation_id))"
, "CREATE TABLE key_locks ( \
\object_key TEXT PRIMARY KEY, user_id TEXT NOT NULL, kind TEXT NOT NULL, \
\operation_id TEXT NOT NULL)"
, "CREATE TABLE objects_meta ( \
\object_key TEXT PRIMARY KEY, \
\pool_id TEXT NOT NULL REFERENCES pools (pool_id), \
\size_bytes BIGINT NOT NULL, content_sha256 TEXT NOT NULL, \
\updated_at TIMESTAMPTZ NOT NULL DEFAULT now())"
]
pure ()
verifyAdmission :: Db -> Config -> IO ()
verifyAdmission database config = do
resetAuthority database 100

View file

@ -60,7 +60,7 @@ verifyConformance cfg database store = do
effectScenarios cfg database store
targetContract cfg database store
checkedInvariant "TypeOK"
putStrLn "WP-10 protocol conformance passed"
putStrLn "Protocol conformance passed"
admissionScenarios :: Config -> Db -> IO ()
admissionScenarios cfg database = do
@ -250,7 +250,7 @@ targetContract cfg database store = do
verifyStoreFence :: Config -> Db -> Redis -> S3 -> IO ()
verifyStoreFence cfg database redis store = do
let env = newEnv cfg database redis store
user = SessionUser "wp10" "fence" protocolUser (Just "Protocol")
user = SessionUser "protocol" "fence" protocolUser (Just "Protocol")
expiredDelete <- prepared
=<< admitDelete
cfg database "expired-delete-store-down" "expired-delete-store-down.bin"

View file

@ -217,7 +217,7 @@ recoveryUser = UserId "recovery-user"
recoverySession :: SessionUser
recoverySession =
SessionUser "wp09" "recovery" recoveryUser (Just "Recovery")
SessionUser "recovery" "recovery" recoveryUser (Just "Recovery")
slowSize :: Integer
slowSize = 20 * 1024 * 1024

View file

@ -63,7 +63,7 @@ verifyConfiguration = do
expectRejected
(load
[ ( "NUTHATCH_PUBLIC_BASE_URL"
, Just "https://user:password@wp12.invalid"
, Just "https://user:password@runtime.invalid"
)
])
"credential-bearing URI configuration"
@ -91,10 +91,10 @@ setVariable name = maybe (unsetEnv name) (setEnv name)
verifyAvailable :: Config -> Redis -> IO ()
verifyAvailable config redis = do
cacheSet redis "nuthatch:wp12:ttl" (cfgListCacheTtlSec config) "cached"
cacheGet redis "nuthatch:wp12:ttl" >>= requireEqual (Just "cached")
cacheSet redis "nuthatch:runtime:ttl" (cfgListCacheTtlSec config) "cached"
cacheGet redis "nuthatch:runtime:ttl" >>= requireEqual (Just "cached")
threadDelay (fromInteger ((cfgListCacheTtlSec config + 1) * 1000000))
cacheGet redis "nuthatch:wp12:ttl" >>= requireEqual Nothing
cacheGet redis "nuthatch:runtime:ttl" >>= requireEqual Nothing
let userA = UserId "runtime-user-a"
userB = UserId "runtime-user-b"
sharedBeforeA <- cacheGeneration redis userA Shared
@ -112,8 +112,8 @@ verifyAvailable config redis = do
verifyUnavailable :: Config -> Redis -> IO ()
verifyUnavailable config redis = do
cacheGet redis "nuthatch:wp12:missing" >>= requireEqual Nothing
cacheSet redis "nuthatch:wp12:missing" 1 "ignored"
cacheGet redis "nuthatch:runtime:missing" >>= requireEqual Nothing
cacheSet redis "nuthatch:runtime:missing" 1 "ignored"
cacheInvalidatePrefixes redis (UserId "runtime-user") Shared [""]
throttled <- throttleCheck redis config (UserId "runtime-user") 1
case throttled of