OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / packages / blind-daemon / production-vnext-profile.js

638 lines · javascript ref:
import fs from 'node:fs/promises'
import path from 'node:path'
import b4a from 'b4a'
import { PRIVATE_IPC_V4_STATUS } from '@hiverelay/blind-ipc'
import {
  blake2b256,
  blindServiceDescriptorV1,
  encodeCanonical,
  serviceDescriptorHash
} from '@hiverelay/blind-protocol'
import {
  createBlindCellControlSnapshotSemanticAuthority,
  createBlindCellControlSnapshotSemanticVerifier,
  streamBlindCellControlSnapshotEntries
} from './cell-control-snapshot.js'
import {
  createBlindInboxControlSnapshotSemanticAuthority,
  createBlindInboxControlSnapshotSemanticVerifier,
  streamBlindInboxControlSnapshotEntries
} from './inbox-control-snapshot.js'
import {
  createBlindCellInboxControlSnapshotSemanticAuthority,
  createBlindCellInboxControlSnapshotSemanticVerifier
} from './cell-inbox-control-snapshot.js'
import {
  createBlindCoreControlSnapshotSemanticAuthority,
  createBlindCoreControlSnapshotSemanticVerifier,
  streamBlindCoreControlSnapshotEntries
} from './core-control-snapshot.js'
import {
  createBlindCellInboxCoreControlSnapshotSemanticAuthority,
  createBlindCellInboxCoreEmptyGenesisSnapshotSemanticVerifier
} from './cell-inbox-core-control-snapshot.js'
import { TwoSlotManifestStore } from './manifest-store.js'
import { BlindProfile1StoreGenesisCoordinator } from './profile1-store-genesis.js'

// Bounded vNext direct-HTTPS public-test profile assembly.
//
// This module is the composition surface for the LIMITED_PUBLIC_TEST_V1
// release profile (profile ID 1, operation mask 0x0001ffff — the baseline 17
// DESCRIBE/CELL/INBOX/CORE operations). It GENUINELY assembles the production
// runtime exclusions by wiring the already-accepted modules into the daemon
// entrypoint: the CELL/INBOX/CORE public execution line (assembled inside
// assembleProductionBlindDaemon), the sealed admission redemption adapter, and
// the accepted bounded one-hop FORWARD relay (forward-https-runtime-vnext.js).
//
// Discipline honoured here:
//  - No release-gate override, no BLIND_RUNTIME_TEST_SEAM paths, no hand-written
//    driver. The production release gate stays strict; this module makes each
//    exclusion TRUE-assembled rather than filtering it away.
//  - FORWARD descriptor/readiness/advertised operation bits stay ZERO per the
//    run's forward-activation rule. The accepted FORWARD module already never
//    publishes a bit; this assembly does not change that.
//  - Sealed node-scoped material is consumed only through the existing
//    config/env surface (bootstrap-config.js, production-runtime.js config and
//    the forward env below). No new secret flow is invented.
//
// This module deliberately imports nothing from production-runtime.js so the
// release gate (which lives there) can depend on this module without a cycle.

export const LIMITED_PUBLIC_TEST_V1_PROFILE = 'LIMITED_PUBLIC_TEST_V1'

// The baseline-17 public-test operation mask (release profile ID 1). FORWARD
// bits (18-21) and CORE.OPEN_REPLICATION (bit 17) are reserved and stay zero.
export const LIMITED_PUBLIC_TEST_V1_OPERATION_BITS = 0x0001ffff

export function isVnextPublicTestProfile (profile) {
  return profile === LIMITED_PUBLIC_TEST_V1_PROFILE
}

// The vNext public-test profile enables the complete CELL/INBOX/CORE public
// execution line. FORWARD is a separate bounded one-hop class assembled beside
// it; it never contributes descriptor/readiness bits.
export const VNEXT_PUBLIC_TEST_RUNTIME_FLAGS = Object.freeze({
  enableCellRuntime: true,
  enableInboxRuntime: true,
  enableCoreRuntime: true
})

function configFailure (code, message) {
  const error = new Error(message)
  error.code = code
  throw error
}

function optionalPath (environment, name) {
  const value = environment[name]
  if (value == null || value === '') return null
  if (typeof value !== 'string' || value.includes('\0') || value.length > 4096) {
    configFailure('BLIND_VNEXT_FORWARD_CONFIG_INVALID', `${name} must be one canonical path`)
  }
  return value
}

function optionalHash (environment, name) {
  const raw = environment[name]
  if (raw == null || raw === '') return null
  if (typeof raw !== 'string' || !/^[0-9a-fA-F]{64}$/.test(raw)) {
    configFailure('BLIND_VNEXT_FORWARD_CONFIG_INVALID', `${name} must be an exact 32-byte hash in hex`)
  }
  const value = b4a.from(raw, 'hex')
  if (value.every(byte => byte === 0)) {
    configFailure('BLIND_VNEXT_FORWARD_CONFIG_INVALID', `${name} must be nonzero`)
  }
  return value
}

// Parse and validate the bounded one-hop FORWARD class configuration from the
// signed launch env surface. Returns null when FORWARD is not configured at
// all (the caller then treats FORWARD_PUBLIC_EXECUTION and the profile-2
// external journal witness as not yet assembled). When any FORWARD material is
// present the complete set is required, so a half-configured FORWARD class
// fails closed instead of assembling a partial relay.
export function loadVnextForwardConfig (environment = process.env) {
  const root = optionalPath(environment, 'HIVERELAY_BLIND_FORWARD_STORE_ROOT')
  const manifestKeyFile = optionalPath(environment, 'HIVERELAY_BLIND_FORWARD_MANIFEST_KEY_FILE')
  const atRestKeyFile = optionalPath(environment, 'HIVERELAY_BLIND_FORWARD_ATREST_KEY_FILE')
  const sourceStoreId = optionalHash(environment, 'HIVERELAY_BLIND_FORWARD_SOURCE_STORE_ID')
  const targetStoreId = optionalHash(environment, 'HIVERELAY_BLIND_FORWARD_TARGET_STORE_ID')
  const sourceContinuityHash = optionalHash(environment, 'HIVERELAY_BLIND_FORWARD_SOURCE_CONTINUITY_HASH')
  const targetContinuityHash = optionalHash(environment, 'HIVERELAY_BLIND_FORWARD_TARGET_CONTINUITY_HASH')
  const sourceSocketPath = optionalPath(environment, 'HIVERELAY_BLIND_FORWARD_SOURCE_SOCKET')
  const targetSocketPath = optionalPath(environment, 'HIVERELAY_BLIND_FORWARD_TARGET_SOCKET')

  const present = [root, manifestKeyFile, atRestKeyFile, sourceStoreId, targetStoreId,
    sourceContinuityHash, targetContinuityHash]
  const anyPresent = present.some(value => value != null) || sourceSocketPath != null ||
    targetSocketPath != null
  if (!anyPresent) return null
  if (present.some(value => value == null)) {
    configFailure('BLIND_VNEXT_FORWARD_CONFIG_INVALID',
      'the bounded FORWARD class requires the complete storage identity set when any of it is configured')
  }
  return Object.freeze({
    storage: Object.freeze({
      root,
      manifestKeyFile,
      atRestKeyFile,
      sourceStoreId,
      targetStoreId,
      sourceDurabilityContinuityHash: sourceContinuityHash,
      targetDurabilityContinuityHash: targetContinuityHash
    }),
    sourceSocketPath,
    targetSocketPath,
    // The WIRE v3 ABI and private IPC v4 format hashes are pinned generated
    // authorities, imported (never hardcoded) so a contract drift fails closed.
    wireV3AbiHash: b4a.from(PRIVATE_IPC_V4_STATUS.importedWireV3AbiHash, 'hex'),
    privateIpcV4Hash: b4a.from(PRIVATE_IPC_V4_STATUS.privateIpcFormatHash, 'hex')
  })
}

// ---------------------------------------------------------------------------
// Store-genesis ceremony (vNext serving-path floor material).
//
// runVnextStoreGenesisCeremony seals the node-scoped store-genesis material
// the production serving path consumes: it DRIVES the accepted
// BlindProfile1StoreGenesisCoordinator pipeline (transactionStore WAL genesis
// -> withWalBarrier -> BlindLocalCheckpointStore.initializeGenesis ->
// TwoSlotManifestStore.initialize) against a blind store root and returns the
// sealed manifest floor facts. The pipeline is idempotent: once the two-slot
// manifest exists and the genesis intent is removed, re-running the ceremony
// on the same root skips publication and returns through validated recovery,
// so the sealed bytes stay byte-identical.
//
// Derivation rule for the caller-supplied consistency tokens: bucketMapHash
// and partitionKey are bound through manifest -> checkpoint as opaque tokens;
// the storage engine never independently validates bucketMapHash against a
// live bucket map (verified in the accepted storage paths), so the caller
// derives both deterministically from the sealed identity, e.g.
//   bucketMapHash = blake2b256('hiverelay.blind.bucket-map.v1'    | storeId | u64be(mapGeneration))
//   partitionKey  = blake2b256('hiverelay.blind.partition-key.v1' | storeId | manifestKey)
// so that re-running the ceremony is byte-identical and idempotent.
//
// Secret hygiene: the ceremony makes no secret copies of its own — manifestKey
// and partitionKey are passed through to the driven stores, which copy them
// internally; the verification TwoSlotManifestStore zeroes its internal key
// copy on close. Caller-owned secret buffers stay caller-owned and are never
// logged here.

const STORE_GENESIS_MAX_U64 = (1n << 64n) - 1n

// The exact binding field set the genesis coordinator pins into the sealed
// manifest (mirrors profile1-store-genesis.js expectedBindings); the
// post-ceremony verification load re-verifies the same bindings.
const STORE_GENESIS_MANIFEST_BINDING_FIELDS = Object.freeze([
  'relayPublicKey',
  'storeId',
  'durabilityProfileId',
  'durabilityContinuityHash',
  'durabilityProfileHash',
  'formatMajor',
  'formatMinor',
  'storeFormatHash',
  'specHash',
  'abiHash',
  'mapGeneration',
  'bucketMapHash',
  'writerEpoch',
  'writerFenceTokenHash'
])

function genesisFailure (message) {
  configFailure('BLIND_VNEXT_STORE_GENESIS_INVALID', message)
}

function genesisRoot (value) {
  if (typeof value !== 'string' || value.includes('\0') || !path.isAbsolute(value) ||
      path.normalize(value) !== value) {
    genesisFailure('storeRoot must be one canonical absolute path')
  }
  return value
}

function genesisBytes32 (value, field) {
  if (!value || typeof value.byteLength !== 'number') genesisFailure(`${field} must be bytes`)
  const normalized = b4a.isBuffer(value)
    ? value
    : ArrayBuffer.isView(value)
      ? b4a.from(value.buffer, value.byteOffset, value.byteLength)
      : b4a.from(value)
  if (normalized.byteLength !== 32) genesisFailure(`${field} must be exactly 32 bytes`)
  if (normalized.every(byte => byte === 0)) genesisFailure(`${field} must be nonzero`)
  return normalized
}

function genesisU64 (value, field, nonzero) {
  if (typeof value === 'number') {
    if (!Number.isSafeInteger(value) || value < 0) genesisFailure(`${field} is not an unsigned integer`)
    value = BigInt(value)
  }
  if (typeof value !== 'bigint' || value < 0n || value > STORE_GENESIS_MAX_U64 ||
      (nonzero && value === 0n)) {
    genesisFailure(`${field} is outside its u64 bound`)
  }
  return value
}

function genesisInteger (value, minimum, maximum, field) {
  if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
    genesisFailure(`${field} is outside ${minimum}..${maximum}`)
  }
  return value
}

// Validates the decoded current descriptor (chain head / successor) against
// its canonical bytes and returns the descriptor hash floor pinned into the
// manifest. Fails closed before any filesystem mutation.
function genesisDescriptorFloor (descriptor, descriptorCanonicalBytes) {
  if (!descriptor || typeof descriptor !== 'object' || Array.isArray(descriptor)) {
    genesisFailure('descriptor must be the decoded current service descriptor')
  }
  if (!descriptorCanonicalBytes || typeof descriptorCanonicalBytes.byteLength !== 'number' ||
      descriptorCanonicalBytes.byteLength === 0) {
    genesisFailure('descriptorCanonicalBytes must be nonempty bytes')
  }
  const durability = descriptor.durability
  const build = descriptor.build
  if (!durability || typeof durability !== 'object' || Array.isArray(durability) ||
      !build || typeof build !== 'object' || Array.isArray(build)) {
    genesisFailure('descriptor must carry its durability and build profiles')
  }
  if (durability.profileId !== 1) {
    genesisFailure('store genesis seals durability profile 1 descriptors only')
  }
  for (const [field, value] of [
    ['descriptor.storeId', descriptor.storeId],
    ['descriptor.relayPublicKey', descriptor.relayPublicKey],
    ['descriptor.durabilityContinuityHash', descriptor.durabilityContinuityHash],
    ['descriptor.durabilityProfileHash', descriptor.durabilityProfileHash],
    ['descriptor.durability.storeFormatHash', durability.storeFormatHash],
    ['descriptor.build.specHash', build.specHash],
    ['descriptor.build.abiHash', build.abiHash]
  ]) {
    if (!value || typeof value.byteLength !== 'number' || value.byteLength !== 32) {
      genesisFailure(`${field} must be exactly 32 bytes`)
    }
  }
  for (const [field, value] of [
    ['descriptor.durability.storeFormatMajor', durability.storeFormatMajor],
    ['descriptor.durability.storeFormatMinor', durability.storeFormatMinor],
    ['descriptor.issuedEpoch', descriptor.issuedEpoch]
  ]) {
    if (!Number.isSafeInteger(value) || value < 0) genesisFailure(`${field} must be an unsigned integer`)
  }
  genesisU64(descriptor.descriptorSequence, 'descriptor.descriptorSequence', false)
  let encoded = null
  try {
    encoded = encodeCanonical(blindServiceDescriptorV1, descriptor)
  } catch (error) {
    genesisFailure(`descriptor is not canonically encodable: ${error.message}`)
  }
  if (!b4a.equals(encoded, descriptorCanonicalBytes)) {
    genesisFailure('descriptor does not match its canonical bytes')
  }
  return serviceDescriptorHash(descriptorCanonicalBytes)
}

// The blindStoreManifestV1 template the pipeline canonicalizes: profile 1,
// manifest revision 0, no predecessor, nonzero map/writer generations, zero
// external/migration state. The codec mandates a NONZERO checkpointHash and
// MAC, so the template carries deterministic nonzero placeholders derived
// from the descriptor hash floor; neither survives the pipeline —
// initializeGenesis installs the real checkpoint anchor (WAL sequence 1 and
// the installed checkpoint header hash replace both anchor fields) and
// TwoSlotManifestStore.initialize re-seals the MAC under the launch key, so
// re-running the ceremony stays byte-identical.
function genesisPlaceholderHash (domain, descriptorHashFloor) {
  return blake2b256(b4a.concat([b4a.from(domain, 'ascii'), descriptorHashFloor]))
}

function genesisManifestTemplate (options) {
  const { descriptor, descriptorHashFloor, bucketMapHash, mapGeneration, ownerFenceTokenHash } = options
  const zero = b4a.alloc(32)
  return {
    magic: b4a.from('HRBLIND1', 'ascii'),
    manifestVersion: 1,
    storeId: b4a.from(descriptor.storeId),
    relayPublicKey: b4a.from(descriptor.relayPublicKey),
    durabilityProfileId: descriptor.durability.profileId,
    durabilityContinuityHash: b4a.from(descriptor.durabilityContinuityHash),
    durabilityProfileHash: b4a.from(descriptor.durabilityProfileHash),
    formatMajor: descriptor.durability.storeFormatMajor,
    formatMinor: descriptor.durability.storeFormatMinor,
    storeFormatHash: b4a.from(descriptor.durability.storeFormatHash),
    specHash: b4a.from(descriptor.build.specHash),
    abiHash: b4a.from(descriptor.build.abiHash),
    mapGeneration,
    bucketMapHash: b4a.from(bucketMapHash),
    checkpointWalSequence: 0n,
    checkpointHash: genesisPlaceholderHash(
      'hiverelay.blind.store-genesis-checkpoint-placeholder.v1', descriptorHashFloor),
    epochFloor: descriptor.issuedEpoch,
    writerEpoch: 1n,
    writerFenceTokenHash: b4a.from(ownerFenceTokenHash),
    externalLeaseRevision: 0n,
    externalJournalId: zero,
    externalWitnessPublicKey: zero,
    restoreEvidenceFeedId: zero,
    lastAckWalSequence: 0n,
    lastAckWalHash: zero,
    externalCheckpointRevision: 0n,
    externalCheckpointHash: zero,
    descriptorSequenceFloor: descriptor.descriptorSequence,
    descriptorHashFloor,
    migrationState: 0,
    sourceFormatMajor: 0,
    targetFormatMajor: 0,
    migrationCursorHash: zero,
    previousManifestHash: null,
    manifestRevision: 0n,
    mac: genesisPlaceholderHash(
      'hiverelay.blind.store-genesis-mac-placeholder.v1', descriptorHashFloor)
  }
}

function emptyGenesisCellState (manifest) {
  return {
    relayPublicKey: b4a.from(manifest.relayPublicKey),
    spends: new Map(),
    commitments: new Map(),
    requestResults: new Map(),
    cells: new Map(),
    accounting: {
      storedBytes: 0,
      stagingBytes: 0,
      controlBytes: 0,
      tombstoneBytes: 0,
      reservedCells: 0,
      stagingByProfile: new Map()
    },
    epochFloor: manifest.epochFloor,
    clockUnsafe: false,
    readOnlyReason: null,
    integrityEvidence: []
  }
}

function emptyGenesisInboxState (manifest) {
  return {
    relayPublicKey: b4a.from(manifest.relayPublicKey),
    spends: new Map(),
    commitments: new Map(),
    requestResults: new Map(),
    inboxes: new Map(),
    frames: new Map(),
    retryPins: new Map(),
    accounting: {
      storedFrameBytes: 0,
      stagingFrameBytes: 0,
      controlBytes: 0,
      tombstoneBytes: 0,
      frameIndexBytes: 0,
      reservedFrames: 0,
      stagingByProfile: new Map()
    },
    epochFloor: manifest.epochFloor,
    clockUnsafe: false,
    readOnlyReason: null,
    integrityEvidence: []
  }
}

function emptyGenesisCoreState (manifest) {
  return {
    relayPublicKey: b4a.from(manifest.relayPublicKey),
    storeId: b4a.from(manifest.storeId),
    durabilityContinuityHash: b4a.from(manifest.durabilityContinuityHash),
    recordsByLogical: new Map(),
    recordsBySpend: new Map(),
    controlChannels: new Map(),
    epochFloor: manifest.epochFloor,
    clockUnsafe: false,
    readOnlyReason: null
  }
}

function compareGenesisSnapshotEntries (left, right) {
  return left.entryKind - right.entryKind || b4a.compare(left.key, right.key)
}

// Streams the empty cell/inbox/core states through the six control-snapshot
// semantic authority/verifier factories into the sorted canonical empty
// global fragments, and brands the empty-genesis publication verifier the
// coordinator requires.
async function emptyGenesisSnapshotAuthority (partitionKey, manifest) {
  const cell = createBlindCellControlSnapshotSemanticAuthority({ partitionKey })
  const inbox = createBlindInboxControlSnapshotSemanticAuthority({ partitionKey })
  const core = createBlindCoreControlSnapshotSemanticAuthority({ partitionKey })
  const cellInbox = createBlindCellInboxControlSnapshotSemanticAuthority({
    partitionKey,
    cellVerifier: createBlindCellControlSnapshotSemanticVerifier(cell),
    inboxVerifier: createBlindInboxControlSnapshotSemanticVerifier(inbox)
  })
  const combined = createBlindCellInboxCoreControlSnapshotSemanticAuthority({
    partitionKey,
    cellInboxVerifier: createBlindCellInboxControlSnapshotSemanticVerifier(cellInbox),
    coreVerifier: createBlindCoreControlSnapshotSemanticVerifier(core)
  })
  const entries = []
  for await (const entry of streamBlindCellControlSnapshotEntries(cell, emptyGenesisCellState(manifest))) entries.push(entry)
  for await (const entry of streamBlindInboxControlSnapshotEntries(inbox, emptyGenesisInboxState(manifest))) entries.push(entry)
  for await (const entry of streamBlindCoreControlSnapshotEntries(core, emptyGenesisCoreState(manifest))) entries.push(entry)
  entries.sort(compareGenesisSnapshotEntries)
  return {
    entries,
    verifier: createBlindCellInboxCoreEmptyGenesisSnapshotSemanticVerifier(combined)
  }
}

function genesisManifestBindings (manifest) {
  return Object.freeze(Object.fromEntries(STORE_GENESIS_MANIFEST_BINDING_FIELDS.map(field => {
    const value = manifest[field]
    return [field, value && typeof value.byteLength === 'number' ? b4a.from(value) : value]
  })))
}

function u64beBytes (value) {
  const bytes = b4a.alloc(8)
  bytes.writeBigUInt64BE(value, 0)
  return bytes
}

// The deterministic bucket-map consistency token. The ceremony seals it into
// the manifest; the serving path re-derives the identical value to load and
// enforce the manifest floor. This is the single shared derivation so the two
// can never diverge (see the derivation rule above).
export function deriveVnextBucketMapHash (storeId, mapGeneration) {
  return blake2b256(b4a.concat([
    b4a.from('hiverelay.blind.bucket-map.v1', 'ascii'),
    b4a.from(storeId),
    u64beBytes(mapGeneration)
  ]))
}

// The exact expectedBindings the production serving path uses to open the
// sealed two-slot manifest and enforce its descriptor floor. Built through the
// same genesisManifestTemplate + genesisManifestBindings the ceremony seals, so
// the bindings match the sealed manifest byte-for-byte. The descriptorHashFloor
// is the chain head's serviceDescriptorHash (the serving path's activated head).
export function vnextStoreGenesisExpectedBindings (descriptor, descriptorHashFloor, mapGeneration, ownerFenceTokenHash) {
  const bucketMapHash = deriveVnextBucketMapHash(descriptor.storeId, mapGeneration)
  const template = genesisManifestTemplate({
    descriptor,
    descriptorHashFloor,
    bucketMapHash,
    mapGeneration,
    ownerFenceTokenHash
  })
  return genesisManifestBindings(template)
}

async function ensureGenesisStoreRoot (storeRoot) {
  let stat = null
  try {
    stat = await fs.lstat(storeRoot)
  } catch (error) {
    if (!error || error.code !== 'ENOENT') throw error
  }
  if (stat == null) {
    await fs.mkdir(storeRoot, { recursive: true, mode: 0o700 })
    stat = await fs.lstat(storeRoot)
  }
  if (!stat.isDirectory() || stat.isSymbolicLink() ||
      (typeof process.getuid === 'function' && stat.uid !== process.getuid()) ||
      (stat.mode & 0o700) !== 0o700 || (stat.mode & 0o077) !== 0) {
    genesisFailure('storeRoot is not a private daemon-owned directory')
  }
}

// Encode the exact floorTransitionV1 payload the serving cell engine's WAL
// recovery decodes for a BLIND_CELL_WAL_TYPE.FLOOR_ADVANCE (type 9) frame:
// struct[['version', u8 constant 1], ['oldEpochFloor', u32be],
// ['newEpochFloor', u32be]] (storage-engine.js floorTransitionV1, 9 bytes).
// The genesis floor record must carry this payload so the engine recovers it
// as a valid epoch-floor transition on a manifested store instead of rejecting
// a freeform payload (RECOVERY_GAP_READ_ONLY). Byte parity with the engine is
// proven by recovering the manifested store in the tests.
function floorAdvancePayloadV1 (oldEpochFloor, newEpochFloor) {
  const payload = b4a.alloc(9)
  payload[0] = 1
  payload.writeUInt32BE(oldEpochFloor, 1)
  payload.writeUInt32BE(newEpochFloor, 5)
  return payload
}

function genesisEpochFloor (value) {
  if (!Number.isSafeInteger(value) || value < 0 || value > 0xffffffff) {
    genesisFailure('descriptor.issuedEpoch (the genesis epoch floor) must be one u32 integer')
  }
  return value
}

// Runs the store-genesis ceremony against options.storeRoot and returns a
// frozen result exposing the sealed manifest floor
// (descriptorSequenceFloor/descriptorHashFloor), the manifest revision and
// hash, the checkpoint anchor (checkpointWalSequence) and anchor hash
// (checkpointHash), the validated recovery sequences, and the two-slot
// manifest file paths under <storeRoot>/control.
export async function runVnextStoreGenesisCeremony (options = {}) {
  if (!options || typeof options !== 'object' || Array.isArray(options)) {
    genesisFailure('store genesis ceremony options must be one object')
  }
  const storeRoot = genesisRoot(options.storeRoot)
  const descriptorHashFloor = genesisDescriptorFloor(options.descriptor, options.descriptorCanonicalBytes)
  const manifestKey = genesisBytes32(options.manifestKey, 'manifestKey')
  const ownerFenceTokenHash = genesisBytes32(options.ownerFenceTokenHash, 'ownerFenceTokenHash')
  const partitionKey = genesisBytes32(options.partitionKey, 'partitionKey')
  const bucketMapHash = genesisBytes32(options.bucketMapHash, 'bucketMapHash')
  const mapGeneration = genesisU64(options.mapGeneration, 'mapGeneration', true)
  const maximumSnapshotBytes = genesisInteger(
    options.maximumSnapshotBytes == null ? 256 * 1024 * 1024 : options.maximumSnapshotBytes,
    1024, 0x7fffffff, 'maximumSnapshotBytes')
  const maximumEntries = genesisInteger(
    options.maximumEntries == null ? 0x1000000 : options.maximumEntries,
    3, 0x1000000, 'maximumEntries')
  if (options.faultInjector != null && typeof options.faultInjector !== 'function') {
    genesisFailure('faultInjector must be a function')
  }

  const descriptor = options.descriptor
  const manifestTemplate = genesisManifestTemplate({
    descriptor,
    descriptorHashFloor,
    bucketMapHash,
    mapGeneration,
    ownerFenceTokenHash
  })
  const snapshot = await emptyGenesisSnapshotAuthority(partitionKey, manifestTemplate)
  await ensureGenesisStoreRoot(storeRoot)
  const controlDirectory = path.join(storeRoot, 'control')

  const coordinator = new BlindProfile1StoreGenesisCoordinator({
    root: storeRoot,
    manifestKey,
    partitionKey,
    manifestTemplate,
    genesisRecord: {
      type: 9,
      virtualBucket: 0,
      payload: floorAdvancePayloadV1(0, genesisEpochFloor(descriptor.issuedEpoch))
    },
    genesisSnapshotEntries: snapshot.entries,
    snapshotSemanticVerifier: snapshot.verifier,
    maximumSnapshotBytes,
    maximumEntries,
    faultInjector: options.faultInjector || null
  })
  const recoveredWalSequences = []
  const shadowWalSequences = []
  let runtime = null
  let recoveryAuthority = null
  try {
    runtime = await coordinator.open({
      applyShadowFrame: async frame => { shadowWalSequences.push(frame.sequence) },
      applyRecoveredFrame: async frame => { recoveredWalSequences.push(frame.sequence) }
    })
    recoveryAuthority = runtime.recoveryAuthority
  } finally {
    if (runtime) await runtime.close()
  }

  // Independent post-ceremony proof: the sealed two-slot manifest must
  // MAC-verify under the same launch key and exact bindings the pipeline
  // pinned. The store zeroes its internal key copy on close.
  const manifestStore = new TwoSlotManifestStore({
    controlDirectory,
    manifestKey,
    expectedBindings: genesisManifestBindings(manifestTemplate)
  })
  await manifestStore.open({ validationOnly: true })
  let sealed = null
  try {
    sealed = await manifestStore.load()
  } finally {
    await manifestStore.close()
  }
  const manifest = sealed.manifest
  return Object.freeze({
    storeRoot,
    controlDirectory,
    manifestRevision: sealed.revision,
    manifestHash: b4a.from(sealed.hash),
    checkpointSequence: recoveryAuthority.checkpointSequence,
    checkpointWalSequence: manifest.checkpointWalSequence,
    checkpointHash: b4a.from(manifest.checkpointHash),
    walHeadSequence: recoveryAuthority.walHeadSequence,
    descriptorSequenceFloor: manifest.descriptorSequenceFloor,
    descriptorHashFloor: b4a.from(manifest.descriptorHashFloor),
    recoveredWalSequences: Object.freeze(recoveredWalSequences.slice()),
    shadowWalSequences: Object.freeze(shadowWalSequences.slice()),
    manifestPaths: Object.freeze({
      a: path.join(controlDirectory, 'manifest-a.v1'),
      b: path.join(controlDirectory, 'manifest-b.v1')
    })
  })
}