Implement prototype: venue-driven simulation core, scenarios, tests, and playable entrance scene
CI / headless-tests (push) Canceled after 49s
CI / headless-tests (push) Canceled after 49s
- Godot 4.3 project scaffold with first-person guard, procedural world, interaction HUD, access inspection, radio forms, debug overlay, shift review - Simulation core: ShiftCoordinator, VenueScenario, EventScheduler, NPCController/FSM, AccessVerifier, EscalationManager, RadioSystem, IncidentRecorder, ReputationEvaluator, CrowdSystem, EventBus - Three authored scenarios (Hollywood Blvd building, The Joke Shop, TV studio) - Custom headless test runner (25 tests) replacing editor-dependent GUT, plus GitHub Actions CI - Documentation workflow live: README, PLAN (tech stack), TODO/DONE, MEMORY
This commit is contained in:
1 parent
e23f284ad4
commit
439e0a4281
45 files changed
+4368
-7
No files matched your search
@@ -0,0 +1,120 @@
|
||||
extends RefCounted
|
||||
## Headless tests for AccessVerifier (ADR-0003, Access Policy).
|
||||
|
||||
const Rules := preload("res://src/core/rules.gd")
|
||||
const AccessVerifier := preload("res://src/core/access_verifier.gd")
|
||||
const AccessPolicy := preload("res://src/core/access_policy.gd")
|
||||
const AccessArtifact := preload("res://src/core/access_artifact.gd")
|
||||
|
||||
var verifier := AccessVerifier.new()
|
||||
|
||||
func test_wristband_valid_grants() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.WRISTBAND, Rules.ArtifactStatus.VALID, {"color": "red", "date": "2026-02-13", "event": "gala"}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], true, "valid wristband should grant access")
|
||||
|
||||
func test_wristband_expired_denies() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.WRISTBAND, Rules.ArtifactStatus.EXPIRED, {}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], false, "expired wristband must deny")
|
||||
|
||||
func test_wristband_counterfeit_denies() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.WRISTBAND, Rules.ArtifactStatus.COUNTERFEIT, {}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], false, "counterfeit wristband must deny")
|
||||
|
||||
func test_missing_wristband_denies() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var result := verifier.verify([], policy)
|
||||
return TestUtils.check_eq(result["granted"], false, "missing wristband must deny")
|
||||
|
||||
func test_recognition_grants_without_wristband() -> bool:
|
||||
## PLAN.md: "The guard already knows and recognizes them."
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.RECOGNITION, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], true, "recognition should grant access")
|
||||
|
||||
func test_recognition_expired_does_not_grant() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.WRISTBAND: true }
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.RECOGNITION, Rules.ArtifactStatus.MISSING, {}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], false, "missing recognition should not grant under band policy")
|
||||
|
||||
func test_joke_shop_id_and_ticket() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.ID: true, Rules.AccessKind.TICKET: true }
|
||||
policy.minimum_age = 21
|
||||
var ok: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.ID, Rules.ArtifactStatus.VALID, {"age": 24}),
|
||||
AccessArtifact.new(Rules.AccessKind.TICKET, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var denied_underage: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.ID, Rules.ArtifactStatus.VALID, {"age": 19}),
|
||||
AccessArtifact.new(Rules.AccessKind.TICKET, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var denied_no_ticket: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.ID, Rules.ArtifactStatus.VALID, {"age": 24}),
|
||||
]
|
||||
var ok_result := verifier.verify(ok, policy)
|
||||
var denied_underage_result := verifier.verify(denied_underage, policy)
|
||||
var denied_no_ticket_result := verifier.verify(denied_no_ticket, policy)
|
||||
var a := TestUtils.check_eq(ok_result["granted"], true, "valid ID + ticket grants")
|
||||
var b := TestUtils.check_eq(denied_underage_result["granted"], false, "underage denied")
|
||||
var c := TestUtils.check_eq(denied_no_ticket_result["granted"], false, "no ticket denied")
|
||||
return a and b and c
|
||||
|
||||
func test_joke_shop_requires_wand_screen() -> bool:
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = { Rules.AccessKind.ID: true, Rules.AccessKind.TICKET: true }
|
||||
policy.wand_screening_required = true
|
||||
var artifacts: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.ID, Rules.ArtifactStatus.VALID, {"age": 25}),
|
||||
AccessArtifact.new(Rules.AccessKind.TICKET, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var result := verifier.verify(artifacts, policy)
|
||||
return TestUtils.check_eq(result["granted"], false, "unscreened guest denied when screening required")
|
||||
|
||||
func test_tv_studio_any_valid_grants() -> bool:
|
||||
## OR-admission: any single valid artifact among several kinds grants entry.
|
||||
var policy := AccessPolicy.new()
|
||||
policy.required_artifacts = {
|
||||
Rules.AccessKind.CREDENTIAL: true,
|
||||
Rules.AccessKind.WRISTBAND: true,
|
||||
Rules.AccessKind.TICKET: true,
|
||||
Rules.AccessKind.GUEST_LIST: true,
|
||||
}
|
||||
policy.grant_if_any_required = true
|
||||
var with_wristband: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.WRISTBAND, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var with_guest_list: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.GUEST_LIST, Rules.ArtifactStatus.VALID, {}),
|
||||
]
|
||||
var all_fake: Array[AccessArtifact] = [
|
||||
AccessArtifact.new(Rules.AccessKind.WRISTBAND, Rules.ArtifactStatus.COUNTERFEIT, {}),
|
||||
AccessArtifact.new(Rules.AccessKind.TICKET, Rules.ArtifactStatus.EXPIRED, {}),
|
||||
]
|
||||
var a := TestUtils.check_eq(verifier.verify(with_wristband, policy)["granted"], true, "wristband grants")
|
||||
var b := TestUtils.check_eq(verifier.verify(with_guest_list, policy)["granted"], true, "guest list grants")
|
||||
var c := TestUtils.check_eq(verifier.verify(all_fake, policy)["granted"], false, "all invalid denied")
|
||||
return a and b and c
|
||||
Reference in new issue
Block a user