feat(city): add city landmarks, stores, luminous signs, and ATC echo guard

Add university and fire station civic buildings plus 7 new store types,
each with facade and luminous blade signs. Extend landmark material
colors and sign accents. Fix ATC dispatch to reject prompt-echoing AI
responses via heuristic guard. Add CityPlacesTest for collision and
roadway avoidance, and extend AirportTest and SignLabelsTest.
This commit is contained in:
2026-10-31 22:22:44 -03:00
parent e7498e1566
commit 46b15ec7be
14 changed files with 297 additions and 13 deletions
+25
View File
@@ -231,4 +231,29 @@ class AirportTest extends TestCase
$this->assertSame('xiaomi/mimo-v2.6-flash', $models[2]);
$this->assertSame('xiaomi/mimo-v2.6-flash', config('ai.fallback_model'));
}
/**
* A model that echoes the prompt instead of speaking as the tower is
* rejected and the chain falls through to the next model.
*/
public function test_dispatch_rejects_prompt_echo_replies(): void
{
config(['ai.openrouter.api_key' => 'test-key']);
Http::fake([
'openrouter.ai/*' => Http::sequence()
->push(['choices' => [['message' => ['content' => 'The user wants a single short sentence in Portuguese, ATC style, authorizing takeoff of flight C10-138 (Pampa Air) on runway 36. Must respond only with the sentence, no quotes.']]]], 200)
->push(['choices' => [['message' => ['content' => 'C10-138, Pampa Air, autorizado para decolagem na pista 36.']]]], 200),
]);
$this->postJson('/city/airport/dispatch')
->assertStatus(202)
->assertJsonPath('accepted', true);
$clearance = cache()->get('airport.clearance');
$this->assertNotNull($clearance);
$this->assertSame('model', $clearance['source']);
$this->assertSame('C10-138, Pampa Air, autorizado para decolagem na pista 36.', $clearance['text']);
Http::assertSentCount(2);
}
}