Files
EVEngine/scripts/architecture_contracts.json

599 lines
30 KiB
JSON

{
"schema_version": 1,
"entries": [
{
"id": "api-shape-policy",
"rule": "api-shape",
"scope": "src/**",
"owner": "engine-maintainers",
"issue": "EVENGINE-QUALITY-API-SHAPES",
"reason": "Changed-line lint rejects new ambiguous operation bools and lastError channels; predicates remain valid bool APIs.",
"expiry": "2027-12-31",
"evidence": [
"docs/dev/Result检查与不得丢弃返回值规范.md",
"scripts/check_nodiscard.py"
],
"tests": [
"scripts/tests/test_architecture_contracts.py",
"scripts/tests/fixtures_architecture_contracts/valid_api.h"
],
"result_policy": "Operation outcomes use Result<T> or a named status enum; predicates may return bool.",
"nodiscard_policy": "Critical handles, subscriptions, scopes and operation Results are [[nodiscard]].",
"pointer_policy": "A public pointer requires Doxygen ownership/lifetime wording or an explicit reviewed adapter contract."
},
{
"id": "gts-terrain-collider-link-contract",
"rule": "link",
"scope": "src/modules/procgen/physics/GtsTerrainColliderRuntime.cpp",
"owner": "procgen_physics::GtsTerrainColliderRuntime and physics::World3D",
"issue": "EVENGINE-ARCH-LINK-CONTRACTS",
"reason": "Optional generated terrain colliders retain only owner-qualified runtime handles across frame and teardown boundaries.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/procgen/physics/GtsTerrainColliderRuntime.h",
"docs/usr/modules/procgen_physics.md"
],
"tests": [
"test/gts_terrain_collider.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"symbols": [
"ColliderLink"
],
"create": "replace creates World3D-owned static bodies and publishes world/body handles only after every tile collider succeeds.",
"ownership": "World3D solely owns bodies and shapes; the runtime owns only typed process-local links.",
"destroy_order": "Runtime-first destroys resolved bodies; world-first removes the world registry entry and all later resolutions return stale null.",
"restore": "Links are never persisted; callers rebuild them by replacing from the restored GtsTerrainLodSet.",
"stale": "World and body generation-qualified handles are both resolved before any access or destruction."
},
{
"id": "physics-link-contract",
"rule": "link",
"scope": "src/modules/physics/PhysicsLink.h",
"owner": "physics::World3D and physics::World",
"issue": "EVENGINE-ARCH-LINK-CONTRACTS",
"reason": "Physics links are process-local projections and must be stale-safe across either destruction order and restore.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/physics/PhysicsLink.h",
"docs/dev/物理系统分层与后端契约.md"
],
"tests": [
"test/physics_artifact_provider.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"symbols": [
"PhysicsLink",
"PhysicsShapeLink",
"PhysicsJointLink"
],
"create": "attach/fromBody/fromShape/fromJoint validate owner-qualified runtime handles",
"ownership": "World owns bodies, shapes and joints; gameplay stores only the typed link projection.",
"destroy_order": "Shape/Joint before Body/World and World before dependants both invalidate to StaleHandle.",
"restore": "Rebuild process-local links from persistent identity after transactional world restore or hot reload.",
"stale": "Generation and owner identity are checked by resolve; encoded validity alone is insufficient."
},
{
"id": "pixelworld-fragment-link-contract",
"rule": "link",
"scope": "src/modules/pixelworld/PixelWorld.h",
"owner": "pixelworld::PixelWorld",
"issue": "EVENGINE-PIXELWORLD-FRAGMENTS",
"reason": "Detached fragment bitmaps need process-local source identity without becoming a second mutable terrain authority.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/pixelworld/PixelWorld.h",
"docs/dev/PixelWorld-Noita技术路线.md"
],
"tests": [
"test/pixelworld.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"symbols": [
"PixelWorldLink"
],
"create": "PixelWorld stamps a world id and epoch into every atomically detached PixelFragment.",
"ownership": "PixelWorld solely owns live terrain; a fragment owns only its detached bitmap and a non-owning source link.",
"destroy_order": "Fragment destruction is independent; world destruction makes rasterization impossible without dereferencing retained world pointers.",
"restore": "Transactional restore and clear increment the world epoch; callers must discard or explicitly recreate stale physics projections.",
"stale": "Rasterization compares both runtime world identity and epoch and returns StaleHandle before any terrain write."
},
{
"id": "rts-link-contract",
"rule": "link",
"scope": "src/modules/rts/RTSTypes.h",
"owner": "RTS ECS world and registered RTS services",
"issue": "EVENGINE-ARCH-LINK-CONTRACTS",
"reason": "RTS cross-domain links distinguish ECS generation handles from service keys and rebuild after restore.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/rts/RTSTypes.h",
"docs/dev/领域短根继承与跨域组合架构.md"
],
"tests": [
"test/rts_composition.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"symbols": [
"EntityLink",
"ServiceLink",
"FactionLink",
"WeaponLink"
],
"create": "EntityLink::bind and ServiceLink::bind return checked links.",
"ownership": "The ECS world or capability registry owns the target; a link never claims target ownership.",
"destroy_order": "Target destruction invalidates generation links; service unregister invalidates key links.",
"restore": "Entity links rebuild from entity identity and service links rebind by stable logical key.",
"stale": "Entity generation and service presence are checked before use."
},
{
"id": "scene-link-contract",
"rule": "link",
"scope": "src/modules/scene/SceneLink.h",
"owner": "scene node owner plus target-module provider",
"issue": "EVENGINE-ARCH-LINK-CONTRACTS",
"reason": "Scene link dispatch stays module-neutral and drops dead targets through provider-owned liveness checks.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/scene/SceneLink.h",
"docs/dev/模块编排与裁剪架构.md"
],
"tests": [
"test/scene.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"symbols": [
"LinkOps",
"SceneLink"
],
"create": "The target module registers LinkOps and the scene stores a typed-kind projection.",
"ownership": "Scene owns link records; the provider owns the target object and callback table.",
"destroy_order": "Target teardown unregisters or reports dead before scene link dispatch; scene teardown drops records.",
"restore": "Provider re-registers operations and scene rebuilds link records from persistent node identity.",
"stale": "alive callback is consulted before push/pull; an absent operation id is not dereferenced."
},
{
"id": "tactics-link-contract",
"rule": "link",
"scope": "src/modules/tactics/*.h",
"owner": "tactics::Tactics facade and ECS world",
"issue": "EVENGINE-ARCH-LINK-CONTRACTS",
"reason": "Tactics membership distinguishes process-local ECS generations from persisted SubjectRef identities.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/tactics/TacticsTypes.h",
"src/modules/tactics/TacticsPersistence.cpp",
"docs/dev/战棋系统设计.md"
],
"tests": [
"test/tactics_turn.cpp",
"test/tactics_replay.cpp",
"test/tactics_script.cpp"
],
"symbols": [
"Membership",
"TacticsBattleSessionRef"
],
"create": "Tactics facade validates battle/side membership before assigning ECS handles; script sessions are allocated through RuntimeObjectRegistry.",
"ownership": "The ECS world owns entities, Tactics owns aggregate destruction responsibility, and scripts own only a generation/epoch proxy.",
"destroy_order": "Units release before sides and battles; either proxy-first or module-first destruction observes generations before release.",
"restore": "Snapshot restore resolves persisted SubjectRef identities against live target entities and never serializes ECS/runtime handles.",
"stale": "Every ECS use calls ecs::try_get and every script call resolves RuntimeHandleRef generation plus module owner epoch."
},
{
"id": "state-owner-policy",
"rule": "state-owner",
"scope": "src/**",
"owner": "engine-maintainers",
"issue": "EVENGINE-ARCH-STATE-OWNERSHIP",
"reason": "Every mutable fact has one owner; adapters, snapshots and links are explicitly non-authoritative projections.",
"expiry": "2027-12-31",
"evidence": [
"docs/dev/重构代码质量与系统完整性规范.md",
"src/engine/common/StateAccess.h"
],
"tests": [
"test/snapshot_envelope.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"state": "Mutable runtime state, persistent snapshot state and cached projections are named separately.",
"authoritative_owner": "The domain registry/container/world named by the contract is the sole writer of the fact.",
"projections": "Links, handles, ECS views and UI/script values are invalidatable projections and cannot become a second store."
},
{
"id": "climbing-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/climbing/**",
"owner": "climbing::ClimbingRuntime",
"issue": "EVENGINE-ARCH-CLIMBING-SYSTEMS",
"reason": "Climbing input and selection publish their deterministic access and commit contracts before ECS integration.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/climbing/ClimbingInput.h",
"docs/dev/superpowers/specs/2026-08-28-climbing-parkour-system.md"
],
"tests": [
"test/climbing_input.cpp",
"test/climbing.cpp",
"test/climbing_anchor_execution.cpp",
"test/climbing_anchor_graph.cpp",
"test/climbing_events.cpp",
"test/climbing_snapshot.cpp"
],
"systems": [
"ClimbingInputSystem",
"ClimbingSelectionSystem"
],
"entity_scope": "characters carrying a ClimbingIntent and an owner-qualified ClimbingRuntime",
"view": "generation-checked character view; Physics is borrowed synchronously during candidate preparation",
"read_set": "ClimbingPose, ClimbingProfileDefinition, ClimbingIntent, ClimbingAnchorGraphDefinition and Physics world geometry",
"write_set": "ClimbingIntent consumption evidence, ClimbingRuntime execution state, and claim-generation-protected graph occupancy reservations only at transaction commit or atomic restore",
"structural_changes": "none; entity/component creation and removal remain the caller's deferred responsibility",
"events": "Started/anchor-transition/contact/terminal facts enter the runtime-owned bounded queue only after authoritative mutation; drain detaches the batch before any callback or script runs",
"services": "injected SimulationTick, last grounded tick and borrowed owner-thread Physics World3D",
"phase": "input buffering in Input; candidate preparation and atomic selection in PrePhysics"
},
{
"id": "inventory-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/inventory/InventorySystem.h",
"owner": "inventory::InventorySystem",
"issue": "EVENGINE-ARCH-INVENTORY-TRANSACTIONS",
"reason": "Inventory mutations and prepared batches publish their access, commit and observer contracts even though Bags are domain containers rather than ECS entities.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/inventory/InventorySystem.h",
"src/modules/inventory/InventorySystem.cpp",
"docs/usr/modules/inventory.md"
],
"tests": [
"test/inventory.cpp",
"test/rpg_quest_reward.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"systems": [
"InventorySystem"
],
"entity_scope": "caller-owned Bag and EquipmentSet domain containers; no ECS entity traversal",
"view": "one owning-thread Bag snapshot captured during preparation and compared in full before commit",
"read_set": "item definitions, Bag configuration, filters, capacity and stack policies, slots and custom properties",
"write_set": "the target Bag slot vector plus the inventory event queue after successful commit",
"structural_changes": "prepared additions mutate only a private candidate; commit swaps the target slot vector once and never changes ECS structure",
"events": "inventory change hooks and poll events publish only after the authoritative slot swap; failed and stale batches publish nothing",
"services": "process-local item registry and named inventory policies on the Bag owning simulation thread",
"phase": "gameplay transaction commit after validation and before downstream inventory presentation polling"
},
{
"id": "npc-ai-ecs-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/npc_ai/NpcAiECS.h",
"owner": "npc_ai::NpcAiWorld",
"issue": "EVENGINE-ARCH-NPC-AI-ECS",
"reason": "NPC AI ECS projection publishes its access contract and closes each view before authoritative world evaluation.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/npc_ai/NpcAiECS.h",
"src/modules/npc_ai/NpcAiECS.cpp",
"docs/dev/superpowers/specs/2026-08-30-npc-ai-framework.md"
],
"tests": [
"test/npc_ai_ecs.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"systems": [
"NpcAiEcsSystem"
],
"entity_scope": "live ECS entities carrying NpcAgentState and optionally NpcAiProjection",
"view": "generation-checked NpcAgentState view for preflight followed by a separate NpcAiProjection view after authoritative evaluation",
"read_set": "NpcAgentState link and NpcAiWorld generation state",
"write_set": "NpcAiProjection presentation cache only; NpcAiWorld remains the sole authoritative behavior-state owner",
"structural_changes": "none while views are open; agent creation and release are explicit caller-owned operations",
"events": "signals and transition trace remain in NpcAiWorld and are not dispatched while an ECS view is open",
"services": "borrowed owner-thread NpcAiWorld plus injected SimulationStep tick and dt",
"phase": "deterministic AI simulation phase after perception ingestion and before animation/presentation consumption"
},
{
"id": "pixelworld-thread-system-contract",
"rule": "ecs-system",
"scope": "src/modules/pixelworld/thread/PixelWorldThread.h",
"owner": "pixelworld::PixelWorld",
"issue": "EVENGINE-PIXELWORLD-PARALLEL",
"reason": "PixelWorld worker scheduling must declare immutable phase reads, isolated candidate writes and canonical commit ordering.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/pixelworld/thread/PixelWorldThread.h",
"docs/dev/PixelWorld-Noita技术路线.md"
],
"tests": [
"test/pixelworld_parallel.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"systems": [
"JobSystem",
"JobSystemPixelScheduler"
],
"entity_scope": "canonical active PixelWorld Chunk indices for one injected SimulationTick",
"view": "immutable post-movement PixelCell phase state plus one owning candidate slot per Chunk index",
"read_set": "PixelCell material and temperature, immutable MaterialCatalog definitions and canonical Chunk order",
"write_set": "index-owned ThermalContribution buffers and transfer counters only; workers never write PixelWorld",
"structural_changes": "none on workers; owner thread performs sorted temperature commits and later Chunk tombstone publication",
"events": "StepStats parallelTasks and deterministic phase counters after synchronous join",
"services": "borrowed running thread::JobSystem through JobSystemPixelScheduler",
"phase": "thermal candidate generation after canonical movement and before owner-thread thermal commit"
},
{
"id": "rpg-ecs-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/rpg/*.h",
"owner": "rpg module systems",
"issue": "EVENGINE-ARCH-ECS-SYSTEM-METADATA",
"reason": "RPG systems publish access contracts; none mutate ECS structure and each names its owning component and thread.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/rpg/LevelSystem.h",
"src/modules/rpg/VitalsSystem.h",
"src/modules/rpg/TraitSystem.h",
"src/modules/rpg/ClassSystem.h",
"src/modules/rpg/QuestSystem.h",
"src/modules/rpg/Battle.h",
"src/modules/rpg/BattleSystem.h",
"src/modules/rpg/EquipmentSystem.h",
"src/modules/rpg/LootSystem.h"
],
"tests": [
"test/rpg_quest.cpp",
"test/rpg_progression.cpp",
"test/rpg_trait.cpp",
"test/rpg_battle.cpp",
"test/rpg_class.cpp",
"test/rpg_equipment.cpp",
"test/rpg_gamestate.cpp"
],
"systems": [
"LevelSystem",
"VitalsSystem",
"TraitSystem",
"ClassSystem",
"QuestSystem",
"Tracker",
"Battle",
"BattleSystem",
"EquipmentSystem",
"LootSystem"
],
"entity_scope": "RPGActor ECS entities registered by RPGActor::createActor / liveActors()",
"view": "no View traversal that mutates while iterated; systems read actor components and run on liveActors()",
"read_set": "Attributes, Statuses, Skills, Progression, Vitals, Traits and ClassInfo components as applicable",
"write_set": "the system's owning component (Vitals/Progression/Traits/ClassInfo/Skills) and event queues only",
"structural_changes": "no structural ECS mutation from within update; actor destruction is explicit and deferred by callers",
"events": "status tick/change, cast, vitals, level-up and battle events polled after update",
"services": "injected dt/turn time and named seed streams; no global mutable time or wall clock",
"phase": "script/game-driven simulation; Battle is turn-based, others are update(dt)-driven"
},
{
"id": "rts-ecs-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/rts/*.h",
"owner": "rts::RTSSystems",
"issue": "EVENGINE-ARCH-ECS-SYSTEM-METADATA",
"reason": "RTS systems publish machine-readable access contracts before view iteration and deferred structural changes.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/rts/RTSSystems.h",
"src/modules/rts/RTSSystems.cpp",
"src/modules/rts/RTSMatch.h",
"src/modules/rts/RTSMatch.cpp",
"src/modules/rts/RTSTech.h",
"src/modules/rts/RTSTech.cpp"
],
"tests": [
"test/rts_composition.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"systems": [
"CommandFanOutSystem",
"MotionSystem",
"OrderActionSystem",
"BuildingProductionSystem",
"EffectSystem",
"MatchSystem",
"TechnologySystem"
],
"entity_scope": "live Unit, Building, ResourceNode, Faction and Match ECS roots in the current world",
"view": "typed generation-checked RTS views; each view closes before deferred creation, destruction or relationship repair",
"read_set": "identity, faction links, motion, orders, production, effects, research definitions, match rules and economy queries as applicable",
"write_set": "motion, orders, lifecycle projections, production queues, faction research state, match participant/state/event components and affected surrender roots",
"structural_changes": "unit production and surrender collect stable handles during traversal, then create or destroy only after the relevant view closes",
"events": "ordered command, production, effect, technology unlock, surrender and victory lifecycle facts are emitted after authoritative mutation",
"services": "injected SimulationStep, definition registry, action executor, resource query and capability services; callbacks are synchronous and not retained",
"phase": "owner-thread deterministic simulation after command ingestion and before presentation; match evaluation follows authoritative economy settlement"
},
{
"id": "tactics-ecs-system-contracts",
"rule": "ecs-system",
"scope": "src/modules/tactics/TacticsBattle.h",
"owner": "tactics::BattleSystem",
"issue": "EVENGINE-ARCH-ECS-SYSTEM-METADATA",
"reason": "Tactics phase systems publish their access contract before operating on battle, side and unit roots.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/tactics/TacticsBattle.h",
"docs/dev/战棋系统设计.md"
],
"tests": [
"test/tactics_board.cpp",
"test/tactics_turn.cpp",
"test/tactics_action.cpp",
"test/tactics_objective.cpp",
"test/tactics_replay.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"systems": [
"BattleSystem"
],
"entity_scope": "Battle, TacticalSide and TacticalUnit roots linked to the supplied module-owned battle",
"view": "generation-checked battle membership handles; systems perform no structural mutation during ECS view traversal",
"read_set": "identity, membership, turn resources and board cell/occupancy facts",
"write_set": "battle revision/turn/events/commands/objectives/reactions/board and tactical unit membership, position, resources and alive state",
"structural_changes": "none inside BattleSystem; Tactics facade creates candidates before checked registration and destroys rejected candidates",
"events": "battle, round, turn, action, reaction, defeat and objective transitions appended in deterministic sequence order",
"services": "injected SimulationStep and the shared ActionRuntime effect-executor contract; no required rendering provider",
"phase": "owner simulation thread after setup/command ingestion and before presentation"
},
{
"id": "time-rng-policy",
"rule": "time-rng",
"scope": "src/**",
"owner": "simulation-maintainers",
"issue": "EVENGINE-ARCH-TIME-RNG-INJECTION",
"reason": "Simulation code receives typed time and named random streams; wall clock access is kept at adapters.",
"expiry": "2027-12-31",
"evidence": [
"src/engine/common/Time.h",
"docs/dev/重构代码质量与系统完整性规范.md"
],
"tests": [
"test/time_contract.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"time_source": "SimulationStep/SimulationTick supplied by the scheduler; wall clock is not read by deterministic systems.",
"rng_stream": "named seed/stream is supplied by the owning simulation context and is not global mutable state.",
"determinism": "same inputs, tick and named streams produce replay/lockstep-identical results where declared deterministic.",
"tolerance": "backend or floating-point paths declare an explicit tolerance rather than silently claiming bit identity."
},
{
"id": "public-api-lifetime-policy",
"rule": "api-lifetime",
"scope": "src/**",
"owner": "engine-maintainers",
"issue": "EVENGINE-QUALITY-API-LIFETIME",
"reason": "Public pointer and callback APIs must state ownership, lifetime, affinity and reentrancy in Doxygen.",
"expiry": "2027-12-31",
"evidence": [
"AGENTS.md",
"docs/dev/重构代码质量与系统完整性规范.md"
],
"tests": [
"scripts/tests/test_architecture_contracts.py",
"scripts/check_nodiscard.py"
],
"thread_affinity": "each public API names caller/owner thread or explicitly states thread-safe access.",
"reentrancy": "callbacks and script calls state whether reentrant and are not invoked while a mutex is held.",
"ownership_contract": "owned, borrowed, observer and transferred values are explicit.",
"lifetime": "borrowed values are bounded by the documented call/frame/task lifetime; handles are stale-safe.",
"lock_callback_policy": "release internal locks before invoking unknown callbacks or scripts."
},
{
"id": "persistence-contract-policy",
"rule": "persistence",
"scope": "src/**",
"owner": "serialization-maintainers",
"issue": "EVENGINE-ARCH-PERSISTENCE-CONTRACTS",
"reason": "Persistent formats are versioned and restore is candidate-first so failures do not publish partial state.",
"expiry": "2027-12-31",
"evidence": [
"src/engine/common/Snapshot.h",
"src/modules/schema/Schema.h",
"docs/dev/Eve-Schema子集与绑定契约.md"
],
"tests": [
"test/snapshot_envelope.cpp",
"test/schema_contract.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"schema": "stable logical schema id and content hash identify the payload.",
"version": "SchemaVersion and snapshot revision/tick are distinct typed fields.",
"migration": "known older versions migrate into a local candidate before validation and commit.",
"unknown_fields": "unknown fields follow the schema's explicit reject, preserve or ignore policy.",
"restore_atomicity": "parse, validate and migrate locally; publish once; failure leaves the observable owner unchanged."
},
{
"id": "tactics-persistence-contract",
"rule": "persistence",
"scope": "src/modules/tactics/TacticsPersistence.h",
"owner": "tactics::Battle",
"issue": "EVENGINE-ARCH-PERSISTENCE-CONTRACTS",
"reason": "Battle snapshots and accepted command logs are deterministic inputs for save, replay and divergence diagnosis.",
"expiry": "2027-12-31",
"evidence": [
"src/modules/tactics/TacticsPersistence.h",
"src/modules/tactics/TacticsPersistence.cpp",
"src/modules/tactics/TacticsReplay.cpp"
],
"tests": [
"test/tactics_replay.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"schema": "SnapshotEnvelope type tactics.battle with LogicalId schema tactics:battle.",
"version": "SchemaVersion 1; battle Revision and SimulationTick remain separate typed envelope fields.",
"migration": "There is no older released tactics schema; version 1 is exact and newer/unknown versions are rejected until an explicit migration is registered.",
"unknown_fields": "Envelope and tactics payload objects reject unknown or missing fields; arrays validate every owning record.",
"restore_atomicity": "Hash, identity, version, complete payload, links and invariants are validated in a local Candidate before one commit to battle/components."
},
{
"id": "optional-capability-policy",
"rule": "optional-capability",
"scope": "src/**",
"owner": "platform-maintainers",
"issue": "EVENGINE-ARCH-OPTIONAL-CAPABILITIES",
"reason": "Capability absence is a tested state, not an implicit soft skip; fallback behavior is observable and classified.",
"expiry": "2027-12-31",
"evidence": [
"cmake/profile_checks.cmake",
"docs/dev/2026-08-26-profile-quality-gates.md"
],
"tests": [
"test/profile/capability_present.cpp",
"test/profile/capability_absent.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"present_test": "provider-present profile builds and runs the capability probe.",
"absent_test": "provider-absent profile builds and runs the explicit absence probe.",
"fallback_observable": "fallback status/diagnostic is exposed to the caller and is not a silent success.",
"fallback_policy": "fallbacks are named, classified and tracked by the bounded quality-debt metadata gate."
},
{
"id": "backend-contract-policy",
"rule": "backend-contract",
"scope": "src/**",
"owner": "runtime-platform-maintainers",
"issue": "EVENGINE-ARCH-BACKEND-CONTRACTS",
"reason": "CPU/GPU and provider implementations share observable contracts and inject failures at lifecycle boundaries.",
"expiry": "2027-12-31",
"evidence": [
"docs/dev/物理系统分层与后端契约.md",
"src/modules/physics/backend/SimulationBackend.h"
],
"tests": [
"test/physics_artifact_provider.cpp",
"test/procgen_artifact_publish.cpp",
"scripts/tests/test_architecture_contracts.py"
],
"contract": "provider implementations expose the same Result/status, ownership, determinism and failure semantics.",
"providers": "CPU reference plus production GPU/Vulkan/WebGPU providers where the profile supplies them.",
"shared_contract_tests": "the same lifecycle and parity assertions run against each available provider.",
"failure_injection": "prepare, commit, rollback, restore and capability-loss failures are injected and assert no partial publication."
},
{
"id": "quality-debt-policy",
"rule": "debt-metadata",
"scope": "scripts/**",
"owner": "engine-maintainers",
"issue": "EVENGINE-QUALITY-DEBT",
"reason": "All explicit debt has owner, issue, reason, expiry and zero net-growth budget; the existing gate remains authoritative.",
"expiry": "2027-12-31",
"evidence": [
"scripts/check_quality_metadata.py",
"scripts/quality_debt_allowlist.json",
"scripts/quality_debt_baseline.json"
],
"tests": [
"scripts/tests/test_quality_metadata.py",
"scripts/tests/test_architecture_contracts.py"
],
"removal_condition": "remove the debt entry when the corresponding migration or documentation is complete; expiry forces review before renewal.",
"max_net_growth": 0
}
]
}