field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraAddStoreTests.swift (43091B)


      1 import CryptoKit
      2 import RadrootsKit
      3 @testable import TeraApp
      4 import XCTest
      5 
      6 final class TeraAddStoreTests: XCTestCase {
      7   func testBackgroundUploadResumesReceiptRetriesAndCompletedStateWithoutDuplicateEnqueue()
      8     async throws
      9   {
     10     let fixture = try BackgroundUploadFixture()
     11     defer { fixture.remove() }
     12     let transfer = BackgroundTransferHarness()
     13     let coordinator = fixture.coordinator(transfer: transfer)
     14 
     15     let first = try await coordinator.uploadInBackground(
     16       job: fixture.job(revision: 2, operation: String(repeating: "a", count: 32)),
     17       media: fixture.media
     18     )
     19     XCTAssertEqual(first.expectedRevision, 2)
     20     let snapshots = try await transfer.snapshots()
     21     let snapshot = try XCTUnwrap(snapshots.first)
     22     XCTAssertEqual(snapshot.request.remoteURL.absoluteString, "http://127.0.0.1:3000/upload")
     23     var counts = await transfer.counts
     24     XCTAssertEqual(counts.enqueue, 1)
     25 
     26     let replayed = try await coordinator.uploadInBackground(
     27       job: fixture.job(revision: 3, operation: String(repeating: "b", count: 32)),
     28       media: fixture.media
     29     )
     30     XCTAssertEqual(replayed.identifier, first.identifier)
     31     XCTAssertEqual(replayed.expectedRevision, 2)
     32     counts = await transfer.counts
     33     XCTAssertEqual(counts.enqueue, 1)
     34 
     35     try await coordinator.settleBackgroundUpload(identifier: replayed.identifier, accepted: true)
     36     let completed = try await coordinator.uploadInBackground(
     37       job: fixture.job(revision: 4, operation: String(repeating: "c", count: 32)),
     38       media: fixture.media
     39     )
     40     XCTAssertEqual(completed.identifier, first.identifier)
     41     counts = await transfer.counts
     42     XCTAssertEqual(counts.enqueue, 1)
     43     try await coordinator.settleBackgroundUpload(identifier: completed.identifier, accepted: true)
     44     counts = await transfer.counts
     45     XCTAssertEqual(counts.acceptedSettlement, 1)
     46 
     47     try await transfer.setState(.interrupted)
     48     let retried = try await coordinator.uploadInBackground(
     49       job: fixture.job(revision: 5, operation: String(repeating: "d", count: 32)),
     50       media: fixture.media
     51     )
     52     XCTAssertEqual(retried.identifier, first.identifier)
     53     counts = await transfer.counts
     54     XCTAssertEqual(counts.retry, 1)
     55     XCTAssertEqual(counts.enqueue, 1)
     56   }
     57 
     58   func testBackgroundUploadRejectsMismatchedAndAmbiguousPersistedRequests() async throws {
     59     let fixture = try BackgroundUploadFixture()
     60     defer { fixture.remove() }
     61     let transfer = BackgroundTransferHarness()
     62     let coordinator = fixture.coordinator(transfer: transfer)
     63     let job = fixture.job(revision: 2, operation: String(repeating: "a", count: 32))
     64     let request = try fixture.request(job: job)
     65     let mismatched = try fixture.request(
     66       job: job,
     67       remoteURL: "http://127.0.0.1:3000/not-the-authorized-object.png"
     68     )
     69     try await transfer.seed(request: mismatched, state: .running)
     70 
     71     do {
     72       _ = try await coordinator.uploadInBackground(job: job, media: fixture.media)
     73       XCTFail("expected persisted-request mismatch")
     74     } catch let failure as TeraRuntimeFailure {
     75       XCTAssertEqual(failure.code, "ios.add.background_upload_mismatch")
     76     }
     77     var counts = await transfer.counts
     78     XCTAssertEqual(counts.enqueue, 0)
     79 
     80     await transfer.removeAll()
     81     let future = try fixture.request(
     82       job: fixture.job(revision: 3, operation: String(repeating: "f", count: 32))
     83     )
     84     try await transfer.seed(request: future, state: .running)
     85     do {
     86       _ = try await coordinator.uploadInBackground(job: job, media: fixture.media)
     87       XCTFail("expected future transfer identity rejection")
     88     } catch let failure as TeraRuntimeFailure {
     89       XCTAssertEqual(failure.code, "ios.add.background_upload_mismatch")
     90     }
     91 
     92     await transfer.removeAll()
     93     try await transfer.seed(request: request, state: .running)
     94     let second = try fixture.request(
     95       job: fixture.job(revision: 1, operation: String(repeating: "e", count: 32))
     96     )
     97     try await transfer.seed(request: second, state: .running)
     98     do {
     99       _ = try await coordinator.uploadInBackground(job: job, media: fixture.media)
    100       XCTFail("expected ambiguous persisted state")
    101     } catch let failure as TeraRuntimeFailure {
    102       XCTAssertEqual(failure.code, "ios.add.background_upload_ambiguous")
    103     }
    104     counts = await transfer.counts
    105     XCTAssertEqual(counts.enqueue, 0)
    106   }
    107 
    108   func testBackgroundUploadCancellationLeavesDurableWorkForRelaunch() async throws {
    109     let fixture = try BackgroundUploadFixture()
    110     defer { fixture.remove() }
    111     let transfer = BackgroundTransferHarness(enqueueState: .running)
    112     let coordinator = fixture.coordinator(transfer: transfer)
    113     let firstJob = fixture.job(revision: 2, operation: String(repeating: "a", count: 32))
    114 
    115     let task = Task {
    116       try await coordinator.uploadInBackground(job: firstJob, media: fixture.media)
    117     }
    118     let reachedSnapshot = await Self.waitUntil { await transfer.snapshotCount > 0 }
    119     XCTAssertTrue(reachedSnapshot)
    120     task.cancel()
    121     do {
    122       _ = try await task.value
    123       XCTFail("expected cancellation")
    124     } catch is CancellationError {}
    125 
    126     var counts = await transfer.counts
    127     XCTAssertEqual(counts.cancel, 0)
    128     XCTAssertEqual(counts.enqueue, 1)
    129     try await transfer.setState(.awaitingVerification)
    130     let replayed = try await coordinator.uploadInBackground(
    131       job: fixture.job(revision: 3, operation: String(repeating: "b", count: 32)),
    132       media: fixture.media
    133     )
    134     XCTAssertEqual(replayed.identifier, firstJob.transferIdentifier)
    135     counts = await transfer.counts
    136     XCTAssertEqual(counts.enqueue, 1)
    137   }
    138 
    139   func testBackgroundUploadCancellationBeforeEnqueueHasNoTransferSideEffect() async throws {
    140     let fixture = try BackgroundUploadFixture()
    141     defer { fixture.remove() }
    142     let transfer = BackgroundTransferHarness(pause: .discovery)
    143     let coordinator = fixture.coordinator(transfer: transfer)
    144     let task = Task {
    145       try await coordinator.uploadInBackground(
    146         job: fixture.job(revision: 2, operation: String(repeating: "a", count: 32)),
    147         media: fixture.media
    148       )
    149     }
    150     let reachedDiscovery = await Self.waitUntil { await transfer.isPaused }
    151     XCTAssertTrue(reachedDiscovery)
    152     task.cancel()
    153     do {
    154       _ = try await task.value
    155       XCTFail("expected cancellation")
    156     } catch is CancellationError {}
    157 
    158     let counts = await transfer.counts
    159     let state = await transfer.state
    160     XCTAssertEqual(counts.enqueue, 0)
    161     XCTAssertNil(state)
    162   }
    163 
    164   func testBackgroundUploadCancellationAtReceiptBoundaryReplaysOnRelaunch() async throws {
    165     let fixture = try BackgroundUploadFixture()
    166     defer { fixture.remove() }
    167     let transfer = BackgroundTransferHarness(pause: .snapshot)
    168     let coordinator = fixture.coordinator(transfer: transfer)
    169     let firstJob = fixture.job(revision: 2, operation: String(repeating: "a", count: 32))
    170     let task = Task {
    171       try await coordinator.uploadInBackground(job: firstJob, media: fixture.media)
    172     }
    173     let reachedReceipt = await Self.waitUntil { await transfer.isPaused }
    174     XCTAssertTrue(reachedReceipt)
    175     task.cancel()
    176     do {
    177       _ = try await task.value
    178       XCTFail("expected cancellation")
    179     } catch is CancellationError {}
    180 
    181     var counts = await transfer.counts
    182     XCTAssertEqual(counts.enqueue, 1)
    183     XCTAssertEqual(counts.cancel, 0)
    184     await transfer.releasePause()
    185     let replayed = try await coordinator.uploadInBackground(
    186       job: fixture.job(revision: 3, operation: String(repeating: "b", count: 32)),
    187       media: fixture.media
    188     )
    189     XCTAssertEqual(replayed.identifier, firstJob.transferIdentifier)
    190     counts = await transfer.counts
    191     XCTAssertEqual(counts.enqueue, 1)
    192   }
    193 
    194   @MainActor
    195   func testProductSurfaceSnapshotAndSchemaInventoryAreExact() async throws {
    196     XCTAssertEqual(
    197       TeraProductSurfaceContract.snapshot,
    198       "today=update,photoUpdate,ask,event,foodAvailability|add=createUpdate,createPhotoUpdate,createAsk,createEvent,createFoodAvailability|support=context_picker,search,me,settings"
    199     )
    200 
    201     let validBackend = AddBackend()
    202     let validClient = try await Self.startedClient(validBackend)
    203     let validStore = TeraAddStore(runtimeClient: validClient)
    204     await validStore.configure(snapshot: validBackend.snapshot())
    205     await validStore.start()
    206     XCTAssertEqual(validStore.state, .ready)
    207     XCTAssertEqual(validStore.schemas.map(\.commandType), TeraAddCommandType.allCases)
    208     XCTAssertTrue(validStore.isProductReady)
    209 
    210     let unicodeIdentifierStore = TeraAddStore(
    211       runtimeClient: validClient,
    212       initialType: .createFoodAvailability,
    213       identifier: { String(repeating: "٠", count: 16) }
    214     )
    215     XCTAssertNil(unicodeIdentifierStore.form.identifier)
    216     _ = try await validClient.stop()
    217 
    218     let exact = TeraAddSchemaFixtures.schemas()
    219     var missingField = exact
    220     let food = exact[4]
    221     missingField[4] = TeraAddSchema(
    222       schemaVersion: food.schemaVersion,
    223       commandType: food.commandType,
    224       label: food.label,
    225       fields: Array(food.fields.dropLast())
    226     )
    227     let invalidInventories = [
    228       Array(exact.reversed()),
    229       Array(exact.dropLast()),
    230       exact + [exact[0]],
    231       missingField,
    232     ]
    233     for inventory in invalidInventories {
    234       let invalidBackend = AddBackend(schemas: inventory)
    235       let invalidClient = try await Self.startedClient(invalidBackend)
    236       let invalidStore = TeraAddStore(runtimeClient: invalidClient)
    237       await invalidStore.configure(snapshot: invalidBackend.snapshot())
    238       await invalidStore.start()
    239       XCTAssertEqual(
    240         invalidStore.state,
    241         .failed(TeraUserMessages.text(.addOperationFailed))
    242       )
    243       XCTAssertFalse(invalidStore.isProductReady)
    244       XCTAssertFalse(invalidStore.canSave)
    245       XCTAssertFalse(invalidStore.canSubmit)
    246       _ = try await invalidClient.stop()
    247     }
    248   }
    249 
    250   @MainActor
    251   func testOfflineSubmitPersistsQueuedSnapshotForRetryAndReopen() async throws {
    252     let backend = AddBackend(advanceOffline: true)
    253     let client = try await Self.startedClient(backend)
    254     let store = TeraAddStore(runtimeClient: client)
    255     await store.configure(snapshot: backend.snapshot())
    256     await store.start()
    257     store.updateForm(\.content, "Saved while the farm is offline")
    258     await store.submit()
    259     let queued = try XCTUnwrap(store.submissions.status)
    260     XCTAssertEqual(queued.state, .queued)
    261     XCTAssertEqual(queued.captured.form.content, "Saved while the farm is offline")
    262     XCTAssertTrue(store.submissions.message?.contains("Original request retained") == true)
    263     store.updateForm(\.content, "Newer editing")
    264     let page = try await client.listSubmissions(scope: queued.request.scope)
    265     guard case let .submission(summary) = page.entries.first else { return XCTFail("Missing submission") }
    266     await store.submissions.select(summary)
    267     XCTAssertEqual(store.form.content, "Newer editing")
    268     XCTAssertEqual(store.submissions.status, queued)
    269     XCTAssertTrue(store.isFormEditable)
    270     _ = try await client.stop()
    271   }
    272 
    273   @MainActor
    274   func testRevisionUsesLosslessRustOwnedReplacementPlan() async throws {
    275     let backend = AddBackend(advanceOffline: true)
    276     let client = try await Self.startedClient(backend)
    277     let store = TeraAddStore(runtimeClient: client)
    278     await store.configure(snapshot: backend.snapshot())
    279     await store.start()
    280     store.selectType(.createFoodAvailability)
    281     configure(store, type: .createFoodAvailability)
    282     let legacy = try await backend.saveAddIntent(input: TeraAddRuntimeInput(form: store.form, media: []),
    283                                                  existingDraftID: nil, expectedRevision: nil)
    284     store.reopen(legacy)
    285     await TeraScopeFixtures.eventually { !store.protection.isWorking }
    286     await store.submit()
    287     let source = try XCTUnwrap(store.activeDraft)
    288 
    289     await store.retractAndRevise(Self.card(localOperationID: source.id))
    290 
    291     XCTAssertNil(store.activeDraft)
    292     XCTAssertEqual(store.form, source.form)
    293     store.updateForm(\.content, "Corrected harvest details")
    294     await store.submit()
    295     XCTAssertTrue(store.activeDraft?.isRevision == true)
    296     XCTAssertEqual(store.activeDraft?.state, .complete)
    297     let revisionPlanCount = await backend.revisionPlanCount()
    298     XCTAssertEqual(revisionPlanCount, 1)
    299     XCTAssertNil(store.drafts.first(where: { $0.kind == .retraction }))
    300     _ = try await client.stop()
    301   }
    302 
    303   @MainActor
    304   func testRetractionUsesTypedTargetAndCompletesThroughTheDurableOutbox() async throws {
    305     let backend = AddBackend()
    306     let client = try await Self.startedClient(backend)
    307     let store = TeraAddStore(
    308       runtimeClient: client,
    309       identifier: { String(repeating: "f", count: 32) },
    310       clock: .fixed(unixSeconds: 1_800_000_200)
    311     )
    312     await store.configure(snapshot: backend.snapshot())
    313     await store.start()
    314 
    315     await store.retract(Self.card())
    316 
    317     XCTAssertEqual(store.activeDraft?.id, String(repeating: "f", count: 32))
    318     XCTAssertEqual(store.activeDraft?.kind, .retraction)
    319     XCTAssertEqual(store.activeDraft?.state, .complete)
    320     XCTAssertFalse(store.isFormEditable)
    321     XCTAssertFalse(store.canSave)
    322     let recordedRetraction = await backend.lastRetraction()
    323     let retraction = try XCTUnwrap(recordedRetraction)
    324     XCTAssertEqual(retraction.commandType, .createFoodAvailability)
    325     XCTAssertEqual(retraction.targetKind, 30402)
    326     XCTAssertEqual(retraction.targetCardID, String(repeating: "c", count: 64))
    327     XCTAssertEqual(retraction.targetEventID, String(repeating: "e", count: 64))
    328     XCTAssertEqual(retraction.targetAddress, Self.card().sourceAddress)
    329     XCTAssertEqual(retraction.reason, "Removed by author.")
    330     _ = try await client.stop()
    331   }
    332 
    333   @MainActor
    334   func testStopFencesSaveQueueAndAdvanceAndPermitsCleanRestart() async throws {
    335     for phase in AddDelayPhase.allCases {
    336       let backend = AddBackend(delayedPhase: phase)
    337       let client = try await Self.startedClient(backend)
    338       let store = TeraAddStore(runtimeClient: client)
    339       await store.configure(snapshot: backend.snapshot())
    340       await store.start()
    341       store.updateForm(\.content, "Restart after \(phase)")
    342 
    343       let submit = Task { await store.submit() }
    344       try await Task.sleep(nanoseconds: 2_000_000)
    345       let visibleAtStop = store.submissions.status
    346       store.stop()
    347       await submit.value
    348 
    349       XCTAssertEqual(store.submissions.status, visibleAtStop)
    350       XCTAssertFalse(store.isWorking)
    351 
    352       await store.start()
    353       XCTAssertEqual(store.state, .ready)
    354       await store.submit()
    355       XCTAssertEqual(store.submissions.status?.state, .complete)
    356       XCTAssertFalse(store.submissions.isWorking)
    357       let count = await backend.submissionBackend.operationCount
    358       XCTAssertEqual(count, 1)
    359       _ = try await client.stop()
    360     }
    361   }
    362 
    363   @MainActor
    364   func testStopDuringBackgroundUploadPermitsDurableRestart() async throws {
    365     let backend = AddBackend()
    366     let client = try await Self.startedClient(backend)
    367     let store = TeraAddStore(
    368       runtimeClient: client,
    369       media: AddMediaHarness(delayFirstUpload: true)
    370     )
    371     await store.configure(snapshot: backend.snapshot())
    372     await store.start()
    373     store.selectType(.createPhotoUpdate)
    374     store.updateForm(\.content, "Restart the background upload")
    375     await store.importPhotos()
    376 
    377     let submit = Task { await store.submit() }
    378     try await Task.sleep(nanoseconds: 2_000_000)
    379     let visibleAtStop = store.submissions.status
    380     store.stop()
    381     await submit.value
    382 
    383     XCTAssertEqual(store.submissions.status, visibleAtStop)
    384     XCTAssertFalse(store.isWorking)
    385 
    386     await store.start()
    387     await store.submit()
    388     XCTAssertEqual(store.submissions.status?.state, .complete)
    389     XCTAssertEqual(store.submissions.status?.media.first?.progress.stage, .verified)
    390     _ = try await client.stop()
    391   }
    392 
    393   @MainActor
    394   func testCancellationAfterDurableRustVerificationDoesNotRejectReceipt() async throws {
    395     let backend = AddBackend(delayAfterBackgroundCompletion: true)
    396     let client = try await Self.startedClient(backend)
    397     let media = AddMediaHarness()
    398     let store = TeraAddStore(runtimeClient: client, media: media)
    399     await store.configure(snapshot: backend.snapshot())
    400     await store.start()
    401     store.selectType(.createPhotoUpdate)
    402     store.updateForm(\.content, "Unknown Rust completion outcome")
    403     await store.importPhotos()
    404 
    405     let submit = Task { await store.submit() }
    406     let persistedCompletion = await Self.waitUntil {
    407       await backend.submissionBackend.completionPersisted
    408     }
    409     XCTAssertTrue(persistedCompletion)
    410     store.stop()
    411     await submit.value
    412 
    413     var settlements = await media.settlementValues()
    414     XCTAssertEqual(settlements, [])
    415     await store.start()
    416     XCTAssertEqual(store.submissions.status?.state, .readyToSign)
    417     XCTAssertEqual(store.submissions.status?.media.first?.progress.stage, .verified)
    418     settlements = await media.settlementValues()
    419     let reconciliations = await media.reconciliationCount()
    420     XCTAssertEqual(settlements, [])
    421     XCTAssertEqual(reconciliations, 2)
    422     _ = try await client.stop()
    423   }
    424 
    425   @MainActor
    426   func testCancellationDuringSettlementReconcilesVerifiedDraftOnRelaunch() async throws {
    427     let backend = AddBackend()
    428     let client = try await Self.startedClient(backend)
    429     let media = AddMediaHarness(delaySettlement: true)
    430     let store = TeraAddStore(runtimeClient: client, media: media)
    431     await store.configure(snapshot: backend.snapshot())
    432     await store.start()
    433     store.selectType(.createPhotoUpdate)
    434     store.updateForm(\.content, "Unknown settlement outcome")
    435     await store.importPhotos()
    436 
    437     let submit = Task { await store.submit() }
    438     let reachedSettlement = await Self.waitUntil { await media.didBeginSettlement() }
    439     XCTAssertTrue(reachedSettlement)
    440     store.stop()
    441     await submit.value
    442 
    443     let settlements = await media.settlementValues()
    444     XCTAssertEqual(settlements, [])
    445     await store.start()
    446     XCTAssertEqual(store.submissions.status?.media.first?.progress.stage, .verified)
    447     let reconciliations = await media.reconciliationCount()
    448     XCTAssertEqual(reconciliations, 2)
    449     _ = try await client.stop()
    450   }
    451 
    452   @MainActor
    453   func testPhotoServiceProbeSurfacesCanonicalEvidence() async throws {
    454     let backend = AddBackend()
    455     let client = try await Self.startedClient(backend)
    456     let store = TeraAddStore(runtimeClient: client, media: AddMediaHarness())
    457     await store.configure(snapshot: backend.snapshot())
    458 
    459     await store.checkPhotoService()
    460 
    461     XCTAssertEqual(store.blossomEvidence?.state, "reachable")
    462     XCTAssertEqual(store.blossomEvidence?.configFingerprint, String(repeating: "f", count: 64))
    463     XCTAssertEqual(store.mediaSupport, .init(library: true, camera: true))
    464     XCTAssertEqual(store.message, "Photo service is reachable.")
    465     _ = try await client.stop()
    466   }
    467 
    468   @MainActor
    469   func testPhotoLimitRejectsTwentyFirstImportAndCapture() async throws {
    470     let backend = AddBackend()
    471     let client = try await Self.startedClient(backend)
    472     let store = TeraAddStore(runtimeClient: client, media: AddMediaHarness())
    473     await store.configure(snapshot: backend.snapshot())
    474     await store.start()
    475     store.selectType(.createPhotoUpdate)
    476 
    477     for _ in 0 ..< 20 {
    478       await store.importPhotos()
    479     }
    480     XCTAssertEqual(store.form.media.count, 20)
    481     XCTAssertFalse(store.canAddMedia)
    482 
    483     await store.importPhotos()
    484     await store.capturePhoto()
    485     XCTAssertEqual(store.form.media.count, 20)
    486     _ = try await client.stop()
    487   }
    488 
    489   @MainActor
    490   func testSuspendAndResumePreserveLateDurableDraftCompletion() async throws {
    491     let backend = AddBackend(delayedPhase: .save)
    492     let client = try await Self.startedClient(backend)
    493     let store = TeraAddStore(runtimeClient: client)
    494     await store.configure(snapshot: backend.snapshot())
    495     await store.start()
    496     store.updateForm(\.content, "Background draft")
    497 
    498     let save = Task { await store.save() }
    499     try await Task.sleep(nanoseconds: 2_000_000)
    500     store.suspend()
    501     await store.start()
    502     await save.value
    503 
    504     XCTAssertEqual(store.savedComposer?.form.content, "Background draft")
    505     XCTAssertEqual(store.message, "Draft saved on this device.")
    506     XCTAssertFalse(store.isWorking)
    507     _ = try await client.stop()
    508   }
    509 
    510   @MainActor
    511   func testSubmitWithoutWritableRelayPreservesSourceBeforeAnyUpload() async throws {
    512     let backend = AddBackend(includeWritableRelay: false)
    513     let client = try await Self.startedClient(backend)
    514     let store = TeraAddStore(
    515       runtimeClient: client,
    516       media: AddMediaHarness()
    517     )
    518     await store.configure(snapshot: backend.snapshot())
    519     await store.start()
    520     store.selectType(.createPhotoUpdate)
    521     store.updateForm(\.content, "Carrots from today")
    522     await store.importPhotos()
    523 
    524     await store.submit()
    525 
    526     XCTAssertNil(store.submissions.status)
    527     let request = try XCTUnwrap(store.submissions.request)
    528     let captured = try await client.loadComposer(scope: request.scope, id: request.composerID)
    529     XCTAssertEqual(captured.form.content, "Carrots from today")
    530     XCTAssertEqual(captured.revision, request.expectedRevision)
    531     XCTAssertEqual(store.submissions.failureCode, "submission_policy_unavailable")
    532     let uploads = await backend.submissionBackend.uploadCount
    533     XCTAssertEqual(uploads, 0)
    534     XCTAssertTrue(store.isFormEditable)
    535     _ = try await client.stop()
    536   }
    537 
    538   @MainActor
    539   func testSubmitRetainsRedactedFailureCodeForSupportAndAccessibility() async throws {
    540     let failure = TeraRuntimeFailure(
    541       schemaVersion: 1,
    542       code: "media_handle_unavailable",
    543       category: "validation",
    544       retryable: false,
    545       recoveryActions: [],
    546       operationID: "add.save",
    547       capabilityID: nil,
    548       safeMessage: "The request is invalid."
    549     )
    550     let backend = AddBackend(saveFailure: failure)
    551     let client = try await Self.startedClient(backend)
    552     let store = TeraAddStore(runtimeClient: client)
    553     await store.configure(snapshot: backend.snapshot())
    554     await store.start()
    555     store.updateForm(\.content, "Prepared media failure")
    556 
    557     await store.submit()
    558 
    559     XCTAssertTrue(store.submissions.message?.contains(TeraUserMessages.text(.addOperationFailed)) == true)
    560     XCTAssertEqual(store.submissions.failureCode, failure.code)
    561     XCTAssertNil(store.activeDraft)
    562     _ = try await client.stop()
    563   }
    564 
    565   @MainActor
    566   func configure(_ store: TeraAddStore, type: TeraAddCommandType) {
    567     switch type {
    568     case .createUpdate:
    569       store.updateForm(\.content, "Harvest update")
    570     case .createPhotoUpdate:
    571       store.updateForm(\.content, "Carrots from today")
    572     case .createAsk:
    573       store.updateForm(\.content, "Who has seed potatoes?")
    574     case .createEvent:
    575       XCTAssertEqual(store.form.identifier?.count, 32)
    576       XCTAssertNotNil(store.form.eventStartUnixSeconds)
    577       XCTAssertNotNil(store.form.eventEndUnixSeconds)
    578       XCTAssertNotNil(store.form.eventStartDate)
    579       XCTAssertNotNil(store.form.eventEndDate)
    580       store.updateForm(\.title, Optional("Market day"))
    581       store.updateForm(\.eventTiming, Optional(TeraEventTiming.timed))
    582       store.updateForm(\.location, Optional("Town square"))
    583     case .createFoodAvailability:
    584       XCTAssertEqual(store.form.identifier?.count, 32)
    585       store.updateForm(\.title, Optional("Carrots"))
    586       store.updateForm(\.summary, Optional("Fresh carrots"))
    587       store.updateForm(\.content, "Freshly picked")
    588       store.updateForm(\.location, Optional("Town square"))
    589       store.updateForm(\.priceAmount, Optional("3"))
    590       store.updateForm(\.currency, Optional("CAD"))
    591       store.updateForm(\.unit, Optional("lb"))
    592     }
    593   }
    594 
    595   private static func waitUntil(
    596     _ predicate: @escaping @Sendable () async -> Bool
    597   ) async -> Bool {
    598     for _ in 0 ..< 1000 {
    599       if await predicate() {
    600         return true
    601       }
    602       try? await Task.sleep(nanoseconds: 1_000_000)
    603     }
    604     return false
    605   }
    606 
    607   static func startedClient(_ backend: AddBackend) async throws -> TeraRuntimeClient {
    608     let client = TeraRuntimeClient { _ in
    609       await TeraRuntimeBackendStart(backend: backend, snapshot: backend.snapshot())
    610     }
    611     _ = try await client.start(configuration: configuration())
    612     return client
    613   }
    614 
    615   static func configuration() -> TeraRuntimeLaunchConfiguration {
    616     TeraRuntimeLaunchConfiguration(
    617       applicationSupportDirectory: "/tmp/radroots-add-tests",
    618       publicKeyHex: String(repeating: "ab", count: 32),
    619       sourceGenerationHex: String(repeating: "cd", count: 32),
    620       sourceGenerationCreatedAtUnixMilliseconds: 1,
    621       protectedData: .available,
    622       networkProfile: .simulator,
    623       writableRelays: ["ws://127.0.0.1:7447"],
    624       blossom: TeraBlossomEndpointConfiguration(
    625         hostKind: .simulator,
    626         endpointAuthority: .loopbackDevelopment,
    627         primaryOrigin: "http://127.0.0.1:3000",
    628         fallbackOrigins: []
    629       ),
    630       app: TeraRuntimeAppMetadata(
    631         bundleIdentifier: "org.radroots.add-tests",
    632         version: "0.1.0-alpha",
    633         buildNumber: "1",
    634         buildSHA: nil
    635       ),
    636       signerGeneration: "add-tests",
    637       signer: AddSigner(),
    638       adoptBootstrapSettings: false
    639     )
    640   }
    641 
    642   static func card(localOperationID: String? = nil) -> TeraTodayCard {
    643     TeraTodayCard(
    644       id: String(repeating: "c", count: 64),
    645       type: .foodAvailability,
    646       sourceEventID: String(repeating: "e", count: 64),
    647       sourceAddress: "30402:\(String(repeating: "ab", count: 32)):carrots",
    648       authorPublicKey: String(repeating: "ab", count: 32),
    649       contractID: "radroots.food_availability.v1",
    650       title: "Carrots",
    651       content: "Freshly picked",
    652       authoredAtUnixSeconds: 1_800_000_000,
    653       effectiveAtUnixSeconds: 1_800_000_000,
    654       calendarTiming: nil,
    655       location: "Town square",
    656       priceAmount: "3",
    657       priceCurrency: "CAD",
    658       priceUnit: "lb",
    659       quantity: "12",
    660       foodSummary: "Fresh carrots",
    661       foodPublishedAtUnixSeconds: 1_799_999_900,
    662       foodStatus: "active",
    663       contextRank: 1,
    664       inclusionReason: "local",
    665       media: [],
    666       lifecycle: .active,
    667       rankDigest: nil,
    668       authorProfile: nil,
    669       thread: [],
    670       localOperationID: localOperationID,
    671       localOperationState: nil
    672     )
    673   }
    674 }
    675 
    676 enum AddDelayPhase: String, CaseIterable, Sendable {
    677   case save
    678   case queue
    679   case advance
    680 }
    681 
    682 actor AddBackend: TeraRuntimeBackend {
    683   private let composerStorage = ComposerTestStorage()
    684   let submissionBackend: SubmissionTestBackend
    685   private let savePause: ResourceTestPause?
    686   private let advanceOffline: Bool
    687   private let saveFailure: TeraRuntimeFailure?
    688   private let includeWritableRelay: Bool
    689   private let delayedPhase: AddDelayPhase?
    690   private let delayAfterBackgroundCompletion: Bool
    691   private let schemaInventory: [TeraAddSchema]
    692   var values: [String: TeraDraftStatus] = [:]
    693   private var uploadedMedia = false
    694   var revisionPlans = 0
    695   var failRevisionReceipt = false
    696   func failNextRevisionReceipt() {
    697     failRevisionReceipt = true
    698   }
    699 
    700   private var delayConsumed = false
    701   private var backgroundCompletionPersisted = false
    702   private var recordedRetraction: TeraRetractionDraftInput?
    703   private var closed = false
    704 
    705   init(
    706     savePause: ResourceTestPause? = nil,
    707     advanceOffline: Bool = false,
    708     saveFailure: TeraRuntimeFailure? = nil,
    709     includeWritableRelay: Bool = true,
    710     delayedPhase: AddDelayPhase? = nil,
    711     delayAfterBackgroundCompletion: Bool = false,
    712     schemas: [TeraAddSchema] = TeraAddSchemaFixtures.schemas()
    713   ) {
    714     submissionBackend = SubmissionTestBackend(composer: composerStorage, writable: includeWritableRelay,
    715                                               offline: advanceOffline, delayedPhase: delayedPhase, delayAfterCompletion: delayAfterBackgroundCompletion)
    716     self.advanceOffline = advanceOffline
    717     self.savePause = savePause
    718     self.saveFailure = saveFailure
    719     self.includeWritableRelay = includeWritableRelay
    720     self.delayedPhase = delayedPhase
    721     self.delayAfterBackgroundCompletion = delayAfterBackgroundCompletion
    722     schemaInventory = schemas
    723   }
    724 
    725   func todayPage(request _: TeraTodayPageRequest) throws -> TeraTodayPage {
    726     throw unsupported()
    727   }
    728 
    729   func refreshToday(
    730     context _: TeraLocalNetwork,
    731     nowUnixSeconds _: UInt64,
    732     update _: TeraTodayProjectionUpdate, backfillCursor _: String?
    733   ) throws -> TeraTodaySyncReceipt {
    734     throw unsupported()
    735   }
    736 
    737   func addSchemas() -> [TeraAddSchema] {
    738     schemaInventory
    739   }
    740 
    741   func saveAddIntent(
    742     input: TeraAddRuntimeInput,
    743     existingDraftID: String?,
    744     expectedRevision: UInt64?
    745   ) async throws -> TeraDraftStatus {
    746     await savePause?.wait()
    747     if let saveFailure {
    748       throw saveFailure
    749     }
    750     try await delayOnce(at: .save)
    751     let id = existingDraftID ?? String(format: "%032x", values.count + 1)
    752     let savedMedia = input.form.media.map {
    753       TeraPreparedMedia(
    754         opaqueReference: $0.opaqueReference,
    755         remoteURL: "http://127.0.0.1:3000/\($0.sha256).png",
    756         sha256: $0.sha256,
    757         mediaType: $0.mediaType,
    758         byteSize: $0.byteSize,
    759         width: $0.width,
    760         height: $0.height,
    761         alt: $0.alt,
    762         preparedAtUnixSeconds: $0.preparedAtUnixSeconds
    763       )
    764     }
    765     var storedForm = input.form
    766     storedForm.media = savedMedia
    767     let status = makeStatus(
    768       id: id,
    769       revision: (expectedRevision ?? 0) + 1,
    770       kind: .add,
    771       commandType: input.form.commandType,
    772       form: storedForm,
    773       state: savedMedia.isEmpty ? .draft : .mediaPreparing,
    774       updatedAt: 1_800_000_000_000 + UInt64(values.count),
    775       media: savedMedia.map {
    776         TeraDraftMediaStatus(
    777           url: $0.remoteURL!,
    778           stage: .pending,
    779           uploadAttempts: 0,
    780           verifiedAtUnixMilliseconds: nil,
    781           possibleOrphan: false,
    782           orphanReasonCode: nil,
    783           orphanRecordedAtUnixMilliseconds: nil
    784         )
    785       }
    786     )
    787     values[id] = status
    788     return status
    789   }
    790 
    791   func probeBlossom() -> TeraBlossomEvidence {
    792     TeraBlossomEvidence(
    793       schemaVersion: 2,
    794       origin: "http://127.0.0.1:3000",
    795       configFingerprint: String(repeating: "f", count: 64),
    796       state: "reachable",
    797       lastSuccessfulState: "probe",
    798       transportSecurity: "loopback_plaintext",
    799       observedAtUnixMilliseconds: 1_800_000_000_000,
    800       httpStatus: 404,
    801       errorCode: nil,
    802       serverErrorCode: nil,
    803       errorPhase: nil,
    804       retryable: false,
    805       possibleOrphan: false,
    806       attempts: 1
    807     )
    808   }
    809 
    810   func saveRetractionDraft(
    811     id: String,
    812     input: TeraRetractionDraftInput,
    813     authoredAtUnixSeconds _: UInt64,
    814     persistedAtUnixMilliseconds: UInt64
    815   ) -> TeraDraftStatus {
    816     recordedRetraction = input
    817     let status = makeStatus(
    818       id: id,
    819       revision: 1,
    820       kind: .retraction,
    821       commandType: input.commandType,
    822       form: nil,
    823       state: .draft,
    824       updatedAt: persistedAtUnixMilliseconds,
    825       media: []
    826     )
    827     values[id] = status
    828     return status
    829   }
    830 
    831   func lastRetraction() -> TeraRetractionDraftInput? {
    832     recordedRetraction
    833   }
    834 
    835   func draftStatus(id: String) throws -> TeraDraftStatus {
    836     try storedDraft(id: id)
    837   }
    838 
    839   func draftHeads(limit: UInt16) -> [TeraDraftStatus] {
    840     Array(values.values.prefix(Int(limit)))
    841   }
    842 
    843   func queueAddIntent(
    844     id: String,
    845     expectedRevision: UInt64
    846   ) async throws -> TeraDraftStatus {
    847     try await delayOnce(at: .queue)
    848     guard includeWritableRelay else {
    849       throw TeraRuntimeFailure(
    850         schemaVersion: 1,
    851         code: "writable_relay_unavailable",
    852         category: "relay",
    853         retryable: true,
    854         recoveryActions: ["configure_relay", "retry"],
    855         operationID: id,
    856         capabilityID: "nostr_sink",
    857         safeMessage: "No writable relay is configured."
    858       )
    859     }
    860     let current = try storedDraft(id: id)
    861     guard current.revision == expectedRevision else { throw unsupported() }
    862     let value = replacing(
    863       current, revision: current.revision + 1, state: .queued,
    864       updatedAt: current.updatedAtUnixMilliseconds + 1
    865     )
    866     values[id] = value
    867     return value
    868   }
    869 
    870   func recoverAddIntent(id: String) throws -> TeraDraftStatus {
    871     let current = try draftStatus(id: id)
    872     let value = replacing(
    873       current, revision: current.revision + 1, state: .queued,
    874       updatedAt: current.updatedAtUnixMilliseconds + 1
    875     )
    876     values[id] = value
    877     return value
    878   }
    879 
    880   func uploadAddMediaIntent(input: TeraBlossomUploadIntent) throws -> TeraDraftStatus {
    881     uploadedMedia = true
    882     let current = try storedDraft(id: input.draftID)
    883     let verified = current.media.map {
    884       TeraDraftMediaStatus(
    885         url: $0.url,
    886         stage: .verified,
    887         uploadAttempts: $0.uploadAttempts + 1,
    888         verifiedAtUnixMilliseconds: current.updatedAtUnixMilliseconds + 1,
    889         possibleOrphan: false,
    890         orphanReasonCode: nil,
    891         orphanRecordedAtUnixMilliseconds: nil
    892       )
    893     }
    894     let value = replacing(
    895       current,
    896       revision: current.revision + 1,
    897       state: .readyToSign,
    898       updatedAt: current.updatedAtUnixMilliseconds + 1,
    899       media: verified
    900     )
    901     values[current.id] = value
    902     return value
    903   }
    904 
    905   func prepareAddMediaBackground(
    906     input: TeraBlossomUploadIntent
    907   ) throws -> TeraNativeUploadJob {
    908     let current = try draftStatus(id: input.draftID)
    909     let uploading = replacing(
    910       current,
    911       revision: current.revision + 1,
    912       state: .mediaUploading,
    913       updatedAt: current.updatedAtUnixMilliseconds + 1
    914     )
    915     values[current.id] = uploading
    916     return TeraNativeUploadJob(
    917       operationID: String(repeating: "a", count: 32),
    918       draft: uploading,
    919       remoteURL: "http://127.0.0.1:3000/\(input.media.media.sha256).png",
    920       uploadURL: "http://127.0.0.1:3000/upload",
    921       authorizationHeader: "Nostr test",
    922       expectedSHA256: input.media.media.sha256,
    923       mediaType: input.media.media.mediaType,
    924       byteSize: input.media.media.byteSize
    925     )
    926   }
    927 
    928   func completeAddMediaBackground(
    929     input: TeraNativeUploadCompletion
    930   ) async throws -> TeraDraftStatus {
    931     uploadedMedia = true
    932     let current = try storedDraft(id: input.draftID)
    933     let verified = current.media.map {
    934       TeraDraftMediaStatus(
    935         url: $0.url,
    936         stage: .verified,
    937         uploadAttempts: $0.uploadAttempts + 1,
    938         verifiedAtUnixMilliseconds: current.updatedAtUnixMilliseconds + 1,
    939         possibleOrphan: false,
    940         orphanReasonCode: nil,
    941         orphanRecordedAtUnixMilliseconds: nil
    942       )
    943     }
    944     let value = replacing(
    945       current,
    946       revision: current.revision + 1,
    947       state: .readyToSign,
    948       updatedAt: current.updatedAtUnixMilliseconds + 1,
    949       media: verified
    950     )
    951     values[current.id] = value
    952     backgroundCompletionPersisted = true
    953     if delayAfterBackgroundCompletion {
    954       try await Task.sleep(nanoseconds: 50_000_000)
    955     }
    956     return value
    957   }
    958 
    959   func didPersistBackgroundCompletion() -> Bool {
    960     backgroundCompletionPersisted
    961   }
    962 
    963   func didUploadMedia() -> Bool {
    964     uploadedMedia
    965   }
    966 
    967   func revisionPlanCount() -> Int {
    968     revisionPlans
    969   }
    970 
    971   func advanceDraft(id: String, expectedRevision: UInt64) async throws -> TeraDraftStatus {
    972     try await delayOnce(at: .advance)
    973     if advanceOffline {
    974       throw TeraRuntimeFailure(
    975         schemaVersion: 1,
    976         code: "test.offline",
    977         category: "relay",
    978         retryable: true,
    979         recoveryActions: ["retry"],
    980         operationID: id,
    981         capabilityID: "nostr_sink",
    982         safeMessage: "The relay is offline."
    983       )
    984     }
    985     let current = try storedDraft(id: id)
    986     let value = replacing(
    987       current, revision: expectedRevision, state: .complete,
    988       updatedAt: current.updatedAtUnixMilliseconds
    989     )
    990     values[id] = value
    991     return value
    992   }
    993 
    994   func cancelAddIntent(
    995     id: String,
    996     expectedRevision _: UInt64
    997   ) throws -> TeraDraftStatus {
    998     let current = try draftStatus(id: id)
    999     let value = replacing(
   1000       current, revision: current.revision + 1, state: .cancelled,
   1001       updatedAt: current.updatedAtUnixMilliseconds + 1
   1002     )
   1003     values[id] = value
   1004     return value
   1005   }
   1006 
   1007   func subscribe(
   1008     bufferCapacity _: Int,
   1009     receive _: @escaping @Sendable (TeraRuntimeChange) async -> Void
   1010   ) -> any TeraRuntimeSubscriptionToken {
   1011     AddSubscriptionToken()
   1012   }
   1013 
   1014   func shutdown() -> TeraRuntimeShutdownReceipt {
   1015     let wasClosed = closed
   1016     closed = true
   1017     return TeraRuntimeShutdownReceipt(state: "closed", alreadyClosed: wasClosed)
   1018   }
   1019 
   1020   func makeStatus(
   1021     id: String,
   1022     revision: UInt64,
   1023     kind: TeraDraftKind,
   1024     commandType: TeraAddCommandType,
   1025     form: TeraAddForm?,
   1026     state: TeraOutboxState,
   1027     updatedAt: UInt64,
   1028     media: [TeraDraftMediaStatus],
   1029     isRevision: Bool = false
   1030   ) -> TeraDraftStatus {
   1031     TeraDraftStatus(
   1032       id: id,
   1033       revision: revision,
   1034       authorPublicKey: String(repeating: "ab", count: 32),
   1035       kind: kind,
   1036       commandType: commandType,
   1037       form: form,
   1038       state: state,
   1039       cardID: String(repeating: "c", count: 64),
   1040       operationID: state == .draft ? nil : String(repeating: "d", count: 32),
   1041       createdAtUnixMilliseconds: updatedAt,
   1042       updatedAtUnixMilliseconds: updatedAt,
   1043       media: media,
   1044       settlement: state == .complete ? settlement() : nil,
   1045       isRevision: isRevision
   1046     )
   1047   }
   1048 
   1049   func replacing(
   1050     _ value: TeraDraftStatus,
   1051     revision: UInt64,
   1052     state: TeraOutboxState,
   1053     updatedAt: UInt64,
   1054     media: [TeraDraftMediaStatus]? = nil
   1055   ) -> TeraDraftStatus {
   1056     TeraDraftStatus(
   1057       id: value.id,
   1058       revision: revision,
   1059       authorPublicKey: value.authorPublicKey,
   1060       kind: value.kind,
   1061       commandType: value.commandType,
   1062       form: value.form,
   1063       state: state,
   1064       cardID: value.cardID,
   1065       operationID: state == .draft ? nil : String(repeating: "d", count: 32),
   1066       createdAtUnixMilliseconds: value.createdAtUnixMilliseconds,
   1067       updatedAtUnixMilliseconds: updatedAt,
   1068       media: media ?? value.media,
   1069       settlement: state == .complete ? settlement() : nil,
   1070       isRevision: value.isRevision
   1071     )
   1072   }
   1073 
   1074   private func settlement() -> TeraOperationSettlement {
   1075     TeraOperationSettlement(
   1076       artifacts: 1,
   1077       signed: 1,
   1078       admitted: 1,
   1079       pending: 0,
   1080       retryable: 0,
   1081       indeterminate: 0,
   1082       failedTerminal: 0,
   1083       cancelled: 0,
   1084       deliveryPlans: 1,
   1085       deliverySatisfied: 1,
   1086       deliveryPending: 0,
   1087       deliveryRetryable: 0,
   1088       deliveryExhausted: 0,
   1089       deliveryFailedTerminal: 0,
   1090       deliveryCancelled: 0
   1091     )
   1092   }
   1093 
   1094   private func delayOnce(at phase: AddDelayPhase) async throws {
   1095     guard delayedPhase == phase, !delayConsumed else { return }
   1096     delayConsumed = true
   1097     try await Task.sleep(nanoseconds: 50_000_000)
   1098   }
   1099 
   1100   func unsupported() -> TeraRuntimeFailure {
   1101     .local(
   1102       operation: "test.add", code: "test.unsupported", safeMessage: "Unsupported test operation."
   1103     )
   1104   }
   1105 }
   1106 
   1107 private actor AddSubscriptionToken: TeraRuntimeSubscriptionToken {
   1108   func cancel() {}
   1109 }
   1110 
   1111 extension TeraAddStoreTests {
   1112   @MainActor
   1113   func testMutationAdmissionKeepsOneAddOperationBeforeItsBackendWait() async throws {
   1114     let pause = ResourceTestPause()
   1115     let backend = AddBackend(savePause: pause)
   1116     let client = try await Self.startedClient(backend)
   1117     let store = TeraAddStore(runtimeClient: client)
   1118     await store.configure(snapshot: backend.snapshot())
   1119     await store.start()
   1120     store.updateForm(\.content, "One admitted draft")
   1121     let owner = Task { await store.save() }
   1122     await admissionPauseEntered(pause)
   1123     XCTAssertTrue(store.isWorking)
   1124     await store.save()
   1125     await store.submit()
   1126     XCTAssertTrue(store.isWorking)
   1127     XCTAssertNil(store.activeDraft)
   1128     await pause.resume.open()
   1129     await owner.value
   1130     XCTAssertTrue(store.drafts.isEmpty)
   1131     XCTAssertEqual(store.savedComposer?.revision, 1)
   1132     XCTAssertEqual(store.savedComposer?.form.content, "One admitted draft")
   1133     XCTAssertFalse(store.isWorking)
   1134     _ = try await client.stop()
   1135   }
   1136 
   1137   @MainActor
   1138   func testMutationAdmissionIgnoresAnAddCallerCancelledWhileQueued() async throws {
   1139     let backend = AddBackend()
   1140     let client = try await Self.startedClient(backend)
   1141     let store = TeraAddStore(runtimeClient: client)
   1142     await store.configure(snapshot: backend.snapshot())
   1143     await store.start()
   1144     store.updateForm(\.content, "Only save after explicit admission")
   1145     let pause = ResourceTestPause()
   1146     let queued = Task { await pause.wait(); await store.save() }
   1147     await admissionPauseEntered(pause)
   1148     queued.cancel()
   1149     await pause.resume.open()
   1150     await queued.value
   1151     XCTAssertTrue(store.drafts.isEmpty)
   1152     XCTAssertFalse(store.isWorking)
   1153     await store.save()
   1154     XCTAssertEqual(store.savedComposer?.form.content, "Only save after explicit admission")
   1155     _ = try await client.stop()
   1156   }
   1157 
   1158   @MainActor
   1159   private func admissionPauseEntered(_ pause: ResourceTestPause) async {
   1160     let entered = expectation(description: "Entered the explicit Add pause")
   1161     let observer = Task { await pause.entered.wait(); entered.fulfill() }
   1162     await fulfillment(of: [entered], timeout: 2)
   1163     await pause.entered.open()
   1164     await observer.value
   1165   }
   1166 }
   1167 
   1168 extension AddBackend {
   1169   func reserveComposerID() async -> String {
   1170     await composerStorage.reserve()
   1171   }
   1172 
   1173   func saveComposer(request: TeraComposerSaveRequest) async throws -> TeraComposerSaveReceipt {
   1174     await savePause?.wait()
   1175     if let saveFailure {
   1176       throw saveFailure
   1177     }
   1178     try await delayOnce(at: .save)
   1179     return try await composerStorage.save(request)
   1180   }
   1181 
   1182   func loadComposer(scope: TeraComposerScope, id: String) async throws -> TeraComposerDraft {
   1183     try await composerStorage.load(scope, id: id)
   1184   }
   1185 
   1186   private func storedDraft(id: String) throws -> TeraDraftStatus {
   1187     guard let value = values[id] else { throw unsupported() }
   1188     return value
   1189   }
   1190 }
   1191 
   1192 extension AddBackend {
   1193   func snapshot() -> TeraRuntimeSnapshot {
   1194     TeraRuntimeSnapshot(
   1195       identity: TeraRuntimeIdentity(
   1196         publicKeyHex: String(repeating: "ab", count: 32),
   1197         hostSignerConfigured: true
   1198       ),
   1199       relay: TeraRelayStatus(
   1200         profile: "simulator",
   1201         state: "configured",
   1202         readAvailability: "unobserved",
   1203         writeAvailability: "unobserved",
   1204         relays: includeWritableRelay
   1205           ? [
   1206             TeraRelayEndpointStatus(
   1207               url: "ws://127.0.0.1:7447",
   1208               access: .readWrite,
   1209               readState: "unobserved",
   1210               writeState: "unobserved",
   1211               readLastAttemptUnixMilliseconds: nil,
   1212               writeLastAttemptUnixMilliseconds: nil,
   1213               readNextAttemptUnixMilliseconds: nil,
   1214               writeNextAttemptUnixMilliseconds: nil
   1215             ),
   1216           ] : []
   1217       ),
   1218       blossomConfiguration: TeraBlossomConfigurationStatus(
   1219         schemaVersion: 1,
   1220         hostKind: "simulator",
   1221         endpointAuthority: "loopback_development",
   1222         primaryOrigin: "http://127.0.0.1:3000",
   1223         fallbackOrigins: [],
   1224         configFingerprint: String(repeating: "f", count: 64)
   1225       ),
   1226       blossomEvidence: nil,
   1227       crateName: "tera_ffi",
   1228       crateVersion: "0.1.0-alpha",
   1229       isClosed: closed
   1230     )
   1231   }
   1232 }