*/ private function draft(): array { return ['modality' => 'company_sale', 'classification' => 'confidential', 'reason' => 'Synthetic draft created', 'payload' => ['title' => 'Private synthetic business']]; } public function test_draft_is_encrypted_and_history_is_versioned_with_stale_writes_rejected(): void { $owner = User::factory()->create(); $service = app(ExistingBusinessDrafts::class); $business = $service->save($owner, $this->draft()); $this->assertSame('draft', $business->status); $this->assertArrayNotHasKey('payload', $business->toArray()); $raw = DB::table('existing_businesses')->where('id', $business->id)->value('payload'); $this->assertStringNotContainsString('Private synthetic', $raw); $this->assertStringContainsString('Private synthetic', Crypt::decryptString($raw)); $service->save($owner, [...$this->draft(), 'version_no' => 1], $business->id); $this->assertDatabaseCount('existing_business_revisions', 2); try { $service->save($owner, [...$this->draft(), 'version_no' => 1], $business->id); $this->fail('Stale update accepted'); } catch (HttpException $e) { $this->assertSame(409, $e->getStatusCode()); } $this->assertDatabaseCount('existing_business_revisions', 2); $service->archive($owner, $business->id, 2, 'Synthetic archive reason'); $this->assertNull(ExistingBusiness::find($business->id)); $this->assertSame(3, ExistingBusiness::withTrashed()->findOrFail($business->id)->version_no); $this->assertDatabaseCount('existing_business_revisions', 3); } public function test_other_user_including_manager_cannot_edit_reserved_business(): void { $service = app(ExistingBusinessDrafts::class); $business = $service->save(User::factory()->create(), $this->draft()); $other = User::factory()->create(); config(['portal.managers' => [$other->email]]); $this->expectException(AuthorizationException::class); $service->save($other, [...$this->draft(), 'version_no' => 1], $business->id); } public function test_unverified_account_cannot_create_business(): void { $this->expectException(AuthorizationException::class); app(ExistingBusinessDrafts::class)->save(User::factory()->unverified()->create(), $this->draft()); } public function test_database_prevents_publication_and_history_changes(): void { $business = app(ExistingBusinessDrafts::class)->save(User::factory()->create(), $this->draft()); foreach (['publish', 'history'] as $operation) { DB::statement('SAVEPOINT business_constraint'); try { if ($operation === 'publish') { DB::table('existing_businesses')->where('id', $business->id)->update(['status' => 'published']); } else { DB::table('existing_business_revisions')->where('business_id', $business->id)->delete(); } $this->fail('Database invariant was not enforced'); } catch (QueryException) { DB::statement('ROLLBACK TO SAVEPOINT business_constraint'); $this->assertTrue(true); } } $this->assertDatabaseCount('existing_business_revisions', 1); } public function test_empty_rollback_is_reversible_and_populated_rollback_is_refused(): void { $migration = require database_path('migrations/2026_09_28_130000_existing_business_foundation.php'); $intake = require database_path('migrations/2026_09_28_140000_existing_business_intake.php'); $marketplace = require database_path('migrations/2026_09_30_120000_extend_existing_business_marketplace.php'); $draftContinuity = require database_path('migrations/2026_10_04_120000_add_simulation_draft_continuity.php'); $draftContinuity->down(); $marketplace->down(); $intake->down(); $migration->down(); $migration->up(); $intake->up(); $marketplace->up(); $draftContinuity->up(); app(ExistingBusinessDrafts::class)->save(User::factory()->create(), $this->draft()); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('destructive rollback refused'); $migration->down(); } }