OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / packages / blind-daemon / test / forward-https-storage-authority-v3.test.js

469 lines · javascript ref:
import b4a from 'b4a'
import fs from 'node:fs/promises'
import path from 'node:path'
import test from 'brittle'
import { blake2b256 } from '@hiverelay/blind-protocol'
import {
  createBlindBoundaryScratch,
  removeBlindBoundaryScratch
} from '../../../test/blind-boundary-scratch.js'
import {
  FORWARD_HTTPS_AGGREGATE_QUOTA_ROLE_V3,
  openForwardHttpsAggregateQuotaV3,
  mintForwardHttpsAggregateQuotaCapabilitiesV3,
  closeForwardHttpsAggregateQuotaV3,
  beginForwardHttpsAggregateQuotaRecoveryV3,
  absorbForwardHttpsAggregateQuotaRecoveryFrameV3,
  finishForwardHttpsAggregateQuotaRecoveryV3
} from '../forward-https-replay-journal-v4.js'
import {
  FORWARD_HTTPS_STORAGE_V3_LIMITS,
  FORWARD_HTTPS_STORAGE_V3_STATUS,
  FORWARD_HTTPS_STORAGE_V3_ERROR_CODE,
  FORWARD_HTTPS_STORAGE_V3_FAULT_POINT,
  openForwardHttpsStorageAuthorityV3,
  sourceForwardHttpsStorageAuthorityV3,
  targetForwardHttpsStorageAuthorityV3,
  consumeForwardHttpsStorageReplayV3,
  forwardHttpsStorageAuthorityV3Status,
  verifyForwardHttpsStorageAuthorityV3,
  closeForwardHttpsStorageAuthorityV3
} from '../forward-https-storage-authority-v3.js'
import {
  prepareForwardHttpsSourceTurnV3,
  forwardHttpsSourceStoreV3Status
} from '../forward-https-source-store-v3.js'

const SOURCE = FORWARD_HTTPS_AGGREGATE_QUOTA_ROLE_V3.SOURCE_STORE
const ZERO32 = b4a.alloc(32)

function fixed (byte) {
  return b4a.alloc(32, byte)
}

async function quota (t, role) {
  const base = await createBlindBoundaryScratch('fhq-')
  t.teardown(async () => { await removeBlindBoundaryScratch(base) })
  const roots = {}
  for (const name of ['source-replay', 'target-replay', 'source-store', 'target-store']) {
    roots[name] = path.join(base, name)
    await fs.mkdir(roots[name], { mode: 0o700 })
    await fs.chmod(roots[name], 0o700)
  }
  const authority = await openForwardHttpsAggregateQuotaV3({
    sourceReplayRoot: roots['source-replay'],
    targetReplayRoot: roots['target-replay'],
    sourceStoreRoot: roots['source-store'],
    targetStoreRoot: roots['target-store'],
    maximumDurableBytesPerStore: 8589934592,
    maximumForwardStorageBytesAggregate: 17179869184,
    monotonicMillis: () => Date.now(),
    callbackTimeoutMillis: 15000,
    faultInjector: null
  })
  t.teardown(async () => { await closeForwardHttpsAggregateQuotaV3(authority).catch(() => {}) })
  const capabilities = mintForwardHttpsAggregateQuotaCapabilitiesV3(authority)
  return { authority, capabilities, capability: role === SOURCE ? capabilities.sourceStoreQuotaCapability : capabilities.targetStoreQuotaCapability, roots }
}

async function absorbOne (capability, walType, payload) {
  const sink = beginForwardHttpsAggregateQuotaRecoveryV3(capability)
  try {
    return await absorbForwardHttpsAggregateQuotaRecoveryFrameV3(sink, {
      frame: { type: walType, payload, payloadHash: blake2b256(payload), sequence: 1n, previousWalHash: ZERO32, walHash: blake2b256(b4a.concat([b4a.from('wal'), payload])), frameBytes: payload.byteLength + 224 }
    })
  } finally {
    await finishForwardHttpsAggregateQuotaRecoveryV3(sink).catch(() => {})
  }
}

function writeU64be (output, offset, value) {
  let current = BigInt(value)
  for (let index = 7; index >= 0; index--) { output[offset + index] = Number(current & 0xffn); current >>= 8n }
  return offset + 8
}

// Test-side FTM9 payload builder (frozen 192-byte layout; caller-supplied
// exact payloads, the requested-terminal-arm shape).
function buildFtm9 (input) {
  const output = b4a.alloc(192)
  let offset = 0
  b4a.copy(b4a.from('FTM9', 'ascii'), output, offset); offset += 4
  output[offset++] = 1
  output[offset++] = input.role === 'TARGET' ? 2 : 1
  output.writeUInt16BE(input.flags, offset); offset += 2
  b4a.copy(input.stableSessionId, output, offset); offset += 32
  offset = writeU64be(output, offset, input.sequence)
  for (const value of input.buckets || [0, 0, 0, 0, 0]) { output.writeUInt16BE(value, offset); offset += 2 }
  output.writeUInt16BE(input.transportTurnsSpent || 0, offset); offset += 2
  output.writeUInt32BE(input.transportBytesSpent || 0, offset); offset += 4
  offset = writeU64be(output, offset, input.priorSessionRevision || 0n)
  output.writeUInt32BE(input.newTrustedEpochHighWatermark || 0, offset); offset += 4
  const reason = b4a.from(input.reason, 'ascii')
  output[offset++] = reason.byteLength
  b4a.copy(reason, output, offset); offset += 64
  if (input.flags === 1) {
    output.writeUInt32BE(input.expiresAtEpoch, offset); offset += 4
    output.writeUInt32BE(input.retainedUntilEpoch, offset); offset += 4
    b4a.copy(input.exactRequestCommitment, output, offset); offset += 32
  }
  return output
}

// The exact minimal-terminal authority commitment preimage (v13): M is
// always recomputed, so tests recompute it the same way.
function minimalTerminalM (roleByte, id, sequence, requestCommitment, expiresAtEpoch, retainedUntilEpoch, watermark, reason) {
  const sequenceBytes = b4a.alloc(8)
  let current = BigInt(sequence)
  for (let index = 7; index >= 0; index--) { sequenceBytes[index] = Number(current & 0xffn); current >>= 8n }
  const scalars = b4a.alloc(13)
  scalars.writeUInt32BE(expiresAtEpoch, 0)
  scalars.writeUInt32BE(retainedUntilEpoch, 4)
  scalars.writeUInt32BE(watermark, 8)
  scalars[12] = reason.byteLength
  return blake2b256(b4a.concat([
    b4a.from('hiverelay.blind.forward-https-minimal-terminal-authority.v3', 'ascii'),
    b4a.from([roleByte]), id, sequenceBytes, requestCommitment, scalars, reason
  ]))
}

test('FTM9 flags0 golden: exact192 payload, zero tail, nonzero prior revision', async t => {
  const id = fixed(0x51)
  const payload = buildFtm9({
    role: 'SOURCE',
    flags: 0,
    stableSessionId: id,
    sequence: 7n,
    priorSessionRevision: 4n,
    newTrustedEpochHighWatermark: 1234,
    reason: 'CHAIN_INVALID',
    buckets: [1, 2, 3, 1, 90],
    transportTurnsSpent: 97,
    transportBytesSpent: 97 * 131072
  })
  t.is(payload.byteLength, 192)
  t.is(b4a.toString(payload.subarray(0, 4), 'ascii'), 'FTM9')
  t.is(payload[4], 1)
  t.is(payload[5], 1)
  t.is(payload.readUInt16BE(6), 0)
  t.ok(b4a.equals(payload.subarray(8, 40), id))
  t.is(payload.readUInt16BE(48), 1)
  t.is(payload.readUInt16BE(58), 97)
  t.is(payload.readUInt32BE(60), 97 * 131072)
  t.is(payload.readUInt32BE(72), 1234)
  t.is(payload[76], 13)
  t.is(b4a.toString(payload.subarray(77, 90), 'ascii'), 'CHAIN_INVALID')
  for (let index = 90; index < 192; index++) t.is(payload[index], 0)
  t.is(192 + 224, 416)
  t.is(192 + 416, 608)
})

test('FTM9 flags1 golden: minimal absent-sequence terminal, exact clock and commitment', async t => {
  const id = fixed(0x52)
  const expiresAtEpoch = 300000
  const payload = buildFtm9({
    role: 'TARGET',
    flags: 1,
    stableSessionId: id,
    sequence: 11n,
    priorSessionRevision: 0n,
    newTrustedEpochHighWatermark: 999,
    reason: 'FORWARD_HTTPS_TARGET_STORE_V3_SEQUENCE_INVALID',
    exactRequestCommitment: fixed(0x53),
    expiresAtEpoch,
    retainedUntilEpoch: expiresAtEpoch + 900
  })
  t.is(payload.byteLength, 192)
  t.is(payload[5], 2)
  t.is(payload.readUInt16BE(6), 1)
  t.is(payload.readUInt32BE(141), expiresAtEpoch)
  t.is(payload.readUInt32BE(145), expiresAtEpoch + 900)
  // The frozen minimal tail carries the exact request commitment at 149..181;
  // M is recomputed from the payload fields, never stored in the tail.
  t.ok(b4a.equals(payload.subarray(149, 181), fixed(0x53)))
  for (let index = 181; index < 192; index++) t.is(payload[index], 0)
  // M recomputation is exact and deterministic
  const M = minimalTerminalM(2, id, 11n, fixed(0x53), expiresAtEpoch, expiresAtEpoch + 900, 999, b4a.from('FORWARD_HTTPS_TARGET_STORE_V3_SEQUENCE_INVALID', 'ascii'))
  const c7 = blake2b256(b4a.concat([b4a.from('hiverelay.blind.forward-https-retention-lookup.v3', 'ascii'), M]))
  const c9 = blake2b256(b4a.concat([b4a.from('hiverelay.blind.forward-https-terminal-state.v3', 'ascii'), M]))
  t.absent(b4a.equals(c7, ZERO32))
  t.absent(b4a.equals(c9, ZERO32))
  t.absent(b4a.equals(c7, c9))
})

test('FTM9 decode horizon: expiry above 4294966394 is INTEGRITY; boundary admits', async t => {
  const id = fixed(0x54)
  const base = {
    role: 'SOURCE',
    flags: 1,
    stableSessionId: id,
    sequence: 1n,
    priorSessionRevision: 0n,
    newTrustedEpochHighWatermark: 1,
    reason: 'FORWARD_HTTPS_SOURCE_STORE_V3_SEQUENCE_INVALID',
    exactRequestCommitment: fixed(0x55),
    retainedUntilEpoch: 4294966394 + 900
  }
  const { capability } = await quota(t, SOURCE)
  await t.exception.all(absorbOne(capability, 99, buildFtm9({ ...base, expiresAtEpoch: 4294966395 })), /horizon|INTEGRITY/)
  const ok = buildFtm9({ ...base, expiresAtEpoch: 4294966394 })
  t.is(ok.readUInt32BE(145), 4294966394 + 900)
  const { entry } = await absorbOne(capability, 99, ok)
  t.is(entry.terminalLogicalCharge, 608)
  t.is(entry.authorityBitmap, 640)
})

test('FTM9 flags1 decode rejects nonzero counters, wrong reason, nonzero revision', async t => {
  const id = fixed(0x56)
  const base = {
    role: 'SOURCE',
    flags: 1,
    stableSessionId: id,
    sequence: 1n,
    priorSessionRevision: 0n,
    newTrustedEpochHighWatermark: 1,
    reason: 'FORWARD_HTTPS_SOURCE_STORE_V3_SEQUENCE_INVALID',
    exactRequestCommitment: fixed(0x57),
    expiresAtEpoch: 100,
    retainedUntilEpoch: 1000
  }
  const { capability } = await quota(t, SOURCE)
  await t.exception.all(absorbOne(capability, 99, buildFtm9({ ...base, buckets: [1, 0, 0, 0, 0] })), /FTM9/)
  await t.exception.all(absorbOne(capability, 99, buildFtm9({ ...base, reason: 'CHAIN_INVALID' })), /FTM9/)
  await t.exception.all(absorbOne(capability, 99, buildFtm9({ ...base, priorSessionRevision: 1n })), /FTM9/)
})

test('storage constants: exact production liabilities, headroom and ceilings', async t => {
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.slotLiabilityUnconsumedLogicalBytes, 1344)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.slotLiabilityUnconsumedPhysicalBytes, 896)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.slotLiabilityConsumedUnprunedLogicalBytes, 736)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.slotLiabilityConsumedUnprunedPhysicalBytes, 480)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionHeadroomLogicalPerRole, 88080384)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionHeadroomPhysicalPerRole, 58720256)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionHeadroomLogicalAggregate, 176160768)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionHeadroomPhysicalAggregate, 117440512)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionOrdinaryLogicalCeilingPerStoreAtFreshRoot, 8501854208)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.productionOrdinaryPhysicalCeilingPerStoreAtFreshRoot, 8531214336)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.terminalLogicalBytes, 608)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.pruneLogicalBytes, 736)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.readinessOperationBits, 0)
  t.is(FORWARD_HTTPS_STORAGE_V3_LIMITS.runtimeReady, false)
  t.is(FORWARD_HTTPS_STORAGE_V3_STATUS.runtimeReady, false)
})

test('export surfaces: exact set equality on all four modules, removed names absent', async t => {
  const source = await import('../forward-https-source-store-v3.js')
  const target = await import('../forward-https-target-store-v3.js')
  const storage = await import('../forward-https-storage-authority-v3.js')
  const replay = await import('../forward-https-replay-journal-v4.js')
  t.alike(Object.keys(source).sort(), [
    'FORWARD_HTTPS_SOURCE_STORE_V3_ERROR_CODE',
    'FORWARD_HTTPS_SOURCE_STORE_V3_FAULT_POINT',
    'FORWARD_HTTPS_SOURCE_STORE_V3_LIMITS',
    'FORWARD_HTTPS_SOURCE_STORE_V3_STATUS',
    'FORWARD_HTTPS_SOURCE_WAL_TYPE',
    'ForwardHttpsSourceStoreV3Error',
    'closeForwardHttpsSourceStoreV3',
    'forwardHttpsSourceStoreV3Status',
    'forwardHttpsSourceTurnStateV3',
    'openForwardHttpsSourceStoreV3',
    'persistForwardHttpsSourceResultV3',
    'prepareForwardHttpsSourceTurnV3'
  ].sort())
  t.alike(Object.keys(target).sort(), [
    'FORWARD_HTTPS_TARGET_STORE_V3_ERROR_CODE',
    'FORWARD_HTTPS_TARGET_STORE_V3_FAULT_POINT',
    'FORWARD_HTTPS_TARGET_STORE_V3_LIMITS',
    'FORWARD_HTTPS_TARGET_STORE_V3_STATUS',
    'FORWARD_HTTPS_TARGET_WAL_TYPE',
    'ForwardHttpsTargetStoreV3Error',
    'acceptForwardedHttpsTargetTurnV3',
    'closeForwardHttpsTargetStoreV3',
    'forwardHttpsTargetStoreV3Status',
    'forwardHttpsTargetTurnStateV3',
    'openForwardHttpsTargetStoreV3',
    'runNextForwardHttpsTargetProcessorWorkV3'
  ].sort())
  t.alike(Object.keys(storage).sort(), [
    'FORWARD_HTTPS_STORAGE_V3_ERROR_CODE',
    'FORWARD_HTTPS_STORAGE_V3_FAULT_POINT',
    'FORWARD_HTTPS_STORAGE_V3_LIMITS',
    'FORWARD_HTTPS_STORAGE_V3_STATUS',
    'ForwardHttpsStorageAuthorityV3Error',
    'closeForwardHttpsStorageAuthorityV3',
    'consumeForwardHttpsStorageReplayV3',
    'forwardHttpsStorageAuthorityV3Status',
    'openForwardHttpsStorageAuthorityV3',
    'sourceForwardHttpsStorageAuthorityV3',
    'targetForwardHttpsStorageAuthorityV3',
    'verifyForwardHttpsStorageAuthorityV3'
  ].sort())
  t.is(Object.keys(replay).length, 39, 'replay module carries the frozen 39 exports')
  t.absent(Object.keys(replay).includes('beginForwardHttpsAggregateQuotaWalAttemptV3'), 'begin is module-private')
  t.ok(Object.keys(replay).includes('applyForwardHttpsAggregateQuotaWalFrameV3'), 'composite apply present')
  t.absent(Object.keys(replay).includes('FORWARD_HTTPS_STORE_WAL_QUOTA_REGISTRY_V3'), 'registry never exported')
  // Removed names are gone from the surfaces
  for (const removed of ['prepareForwardHttpsSourceSessionV3', 'appendForwardHttpsSourceSessionV3', 'terminalizeForwardHttpsSourceSessionV3', 'terminalizeForwardHttpsSourceAbsentSequenceV3', 'pruneForwardHttpsSourceSessionV3', 'FORWARD_HTTPS_SOURCE_STORE_V3_WAL_TYPE']) {
    t.absent(removed in source, `source no longer exports ${removed}`)
  }
  for (const removed of ['openForwardHttpsTargetSessionV3', 'appendForwardHttpsTargetSessionV3', 'terminalizeForwardHttpsTargetSessionV3', 'terminalizeForwardHttpsTargetAbsentSequenceV3', 'pruneForwardHttpsTargetSessionV3', 'FORWARD_HTTPS_TARGET_STORE_V3_WAL_TYPE', 'FORWARD_HTTPS_TARGET_STORE_V3_HISTORIC_IDENTITY']) {
    t.absent(removed in target, `target no longer exports ${removed}`)
  }
  for (const removed of ['encodeForwardHttpsSessionTerminalV3', 'createForwardHttpsChargeRegistryV3', 'streamForwardHttpsChargeCommitmentV3', 'verifyForwardHttpsTerminalHeadroomV3', 'verifyForwardHttpsTerminalInvarianceV3', 'checkForwardHttpsProtectedAdmissionV3', 'classifyForwardHttpsHistoricIdentityV3', 'deriveForwardHttpsMinimalTerminalAuthorityCommitmentV3', 'deriveForwardHttpsMinimalTerminalAuthorityClassesV3', 'FORWARD_HTTPS_STORAGE_AUTHORITY_V3_ERROR_CODE', 'FORWARD_HTTPS_STORAGE_AUTHORITY_V3_LIMITS', 'FORWARD_HTTPS_STORAGE_SLOT_STATE_V3', 'FORWARD_HTTPS_STORAGE_HISTORIC_IDENTITY_V3']) {
    t.absent(removed in storage, `storage no longer exports ${removed}`)
  }
})

test('composite storage authority: exact open order, exposed children, status, verify, consume replay negative, close', async t => {
  const root = await createBlindBoundaryScratch('fhcomp-')
  t.teardown(async () => { await removeBlindBoundaryScratch(root) })
  const options = {
    root,
    manifestKey: fixed(0x30),
    atRestKey: fixed(0x31),
    wireV3AbiHash: fixed(0x32),
    privateIpcV4Hash: fixed(0x33),
    signedLaunchTopologyHash: fixed(0x34),
    sourceStoreId: fixed(0x35),
    targetStoreId: fixed(0x36),
    mapGeneration: 1n,
    ownerFenceTokenHash: fixed(0x37),
    sourceDurabilityContinuityHash: fixed(0x38),
    targetDurabilityContinuityHash: fixed(0x39),
    targetSignerPublicKey: fixed(0x3a),
    targetSignerDescriptorSequence: 1n,
    targetSignerDescriptorHash: fixed(0x3b),
    signResult: async () => b4a.alloc(64),
    createResponderState: () => ({}),
    advanceResponderIngress: () => {},
    advanceResponderOutcome: () => {},
    epochSeconds: () => 1000000,
    monotonicMillis: () => Date.now()
  }
  const authority = await openForwardHttpsStorageAuthorityV3(options)
  t.teardown(async () => { await closeForwardHttpsStorageAuthorityV3(authority).catch(() => {}) })
  // Children are exposed only after successful initialization
  const source = sourceForwardHttpsStorageAuthorityV3(authority)
  const target = targetForwardHttpsStorageAuthorityV3(authority)
  t.ok(source && target)
  const status = forwardHttpsStorageAuthorityV3Status(authority)
  t.is(status.state, 'OPEN')
  t.ok(status.localOperational)
  t.is(status.descriptorOperationBits, 0)
  // The exposed child store is fully operational through its own API
  const prepared = await prepareForwardHttpsSourceTurnV3(source, { stableSessionId: fixed(0x3c), body: b4a.alloc(8, 0x41) })
  t.is(prepared.walSequence, 1n)
  t.is(forwardHttpsSourceStoreV3Status(source).unconsumedSlots, forwardHttpsSourceStoreV3Status(source).slotCapacity - 1)
  // Exact authority verification passes and carries both heads
  const verified = verifyForwardHttpsStorageAuthorityV3(authority)
  t.ok(verified.consistent)
  t.is(verified.source.walHeadSequence, 1n)
  // consume replay: a forged consumed capability rejects, no mutation
  await t.exception.all(() => consumeForwardHttpsStorageReplayV3(authority, {
    consumed: Object.freeze({}),
    role: 'SOURCE_ORIGIN',
    record: b4a.alloc(292)
  }), /forged|CONSUMED_INVALID|INVALID/)
  // Missing/unknown open keys reject
  const missing = { ...options }
  delete missing.manifestKey
  await t.exception.all(openForwardHttpsStorageAuthorityV3(missing), /manifestKey/)
  await t.exception.all(openForwardHttpsStorageAuthorityV3({ ...options, bogusKey: 1 }), /unknown field/)
  // Close is exact reverse order and idempotent; foreign authority rejects
  await closeForwardHttpsStorageAuthorityV3(authority)
  t.is(forwardHttpsStorageAuthorityV3Status(authority).state, 'CLOSED')
  await closeForwardHttpsStorageAuthorityV3(authority)
  await t.exception.all(closeForwardHttpsStorageAuthorityV3(Object.freeze({})), /forged|AUTHORITY_INVALID/)
  await t.exception.all(() => sourceForwardHttpsStorageAuthorityV3(authority), /closed|CLOSED/)
})

function compositeOptions (root, faultInjector) {
  return {
    root,
    manifestKey: fixed(0x30),
    atRestKey: fixed(0x31),
    wireV3AbiHash: fixed(0x32),
    privateIpcV4Hash: fixed(0x33),
    signedLaunchTopologyHash: fixed(0x34),
    sourceStoreId: fixed(0x35),
    targetStoreId: fixed(0x36),
    mapGeneration: 1n,
    ownerFenceTokenHash: fixed(0x37),
    sourceDurabilityContinuityHash: fixed(0x38),
    targetDurabilityContinuityHash: fixed(0x39),
    targetSignerPublicKey: fixed(0x3a),
    targetSignerDescriptorSequence: 1n,
    targetSignerDescriptorHash: fixed(0x3b),
    signResult: async () => b4a.alloc(64),
    createResponderState: () => ({}),
    advanceResponderIngress: () => {},
    advanceResponderOutcome: () => {},
    epochSeconds: () => 1000000,
    monotonicMillis: () => Date.now(),
    faultInjector
  }
}

test('composite fault registry: lifecycle points fire and injector failures are coded INTEGRITY', async t => {
  // The composite lifecycle subset fires over one open/close, alongside the
  // quota, replay and store points the same injector observes downstream.
  const r1 = await createBlindBoundaryScratch('fhcomp-fault-')
  t.teardown(async () => { await removeBlindBoundaryScratch(r1) })
  const observed = []
  const contexts = []
  const authority = await openForwardHttpsStorageAuthorityV3(compositeOptions(r1, async (point, context) => { observed.push(point); contexts.push(context) }))
  for (const point of ['OPEN_AFTER_ROOT_VERIFY', 'OPEN_AFTER_QUOTA_AUTHORITY', 'OPEN_AFTER_SOURCE_STORE', 'OPEN_AFTER_TARGET_STORE', 'OPEN_AFTER_QUOTA_INITIALIZE']) {
    t.ok(observed.includes(point), `${point} fired`)
  }
  await closeForwardHttpsStorageAuthorityV3(authority)
  t.ok(observed.includes(FORWARD_HTTPS_STORAGE_V3_FAULT_POINT.CLOSE_AFTER_QUOTA), 'close fault point fired')
  t.ok(contexts.every(context => context === undefined), 'no context is passed at any layer')
  // An open-side injector failure rejects the open with coded INTEGRITY.
  const r2 = await createBlindBoundaryScratch('fhcomp-fault-')
  t.teardown(async () => { await removeBlindBoundaryScratch(r2) })
  await t.exception.all(openForwardHttpsStorageAuthorityV3(compositeOptions(r2, async point => {
    if (point === FORWARD_HTTPS_STORAGE_V3_FAULT_POINT.OPEN_AFTER_QUOTA_INITIALIZE) throw new Error('injected composite fault')
  })), /fault injector failed at OPEN_AFTER_QUOTA_INITIALIZE|INTEGRITY/)
  // A non-undefined injector return maps to coded INTEGRITY as well.
  const r2b = await createBlindBoundaryScratch('fhcomp-fault-')
  t.teardown(async () => { await removeBlindBoundaryScratch(r2b) })
  await t.exception.all(openForwardHttpsStorageAuthorityV3(compositeOptions(r2b, async point => {
    if (point === FORWARD_HTTPS_STORAGE_V3_FAULT_POINT.OPEN_AFTER_QUOTA_INITIALIZE) return 'injected'
    return undefined
  })), /returned a value|INTEGRITY/)
  // A close-side injector failure is reported once with coded INTEGRITY; the
  // exact-owner repeat resolves because every child already closed.
  const r3 = await createBlindBoundaryScratch('fhcomp-fault-')
  t.teardown(async () => { await removeBlindBoundaryScratch(r3) })
  const authority3 = await openForwardHttpsStorageAuthorityV3(compositeOptions(r3, async point => {
    if (point === FORWARD_HTTPS_STORAGE_V3_FAULT_POINT.CLOSE_AFTER_QUOTA) throw new Error('injected close fault')
  }))
  let closeError = null
  try {
    await closeForwardHttpsStorageAuthorityV3(authority3)
  } catch (error) {
    closeError = error
  }
  t.ok(closeError, 'the first close reports the fault')
  t.is(closeError.code, 'FORWARD_HTTPS_STORAGE_AUTHORITY_V3_INTEGRITY')
  await closeForwardHttpsStorageAuthorityV3(authority3)
  t.is(forwardHttpsStorageAuthorityV3Status(authority3).state, 'CLOSED')
})

test('readiness flags and error codes: storage STATUS is not implementation-ready and AUTHORITY_INVALID is defined', async t => {
  t.is(FORWARD_HTTPS_STORAGE_V3_STATUS.implementationReady, false)
  t.is(FORWARD_HTTPS_STORAGE_V3_STATUS.runtimeReady, false)
  t.is(FORWARD_HTTPS_STORAGE_V3_STATUS.releaseReady, false)
  t.is(FORWARD_HTTPS_STORAGE_V3_STATUS.authorizesRelease, false)
  t.is(FORWARD_HTTPS_STORAGE_V3_ERROR_CODE.AUTHORITY_INVALID, 'FORWARD_HTTPS_STORAGE_AUTHORITY_V3_AUTHORITY_INVALID')
  // A forged authority close rejects with the exact coded AUTHORITY_INVALID.
  let forged = null
  try {
    await closeForwardHttpsStorageAuthorityV3(Object.freeze({}))
  } catch (error) {
    forged = error
  }
  t.ok(forged)
  t.is(forged.code, 'FORWARD_HTTPS_STORAGE_AUTHORITY_V3_AUTHORITY_INVALID')
})