Keep CMake module names and trim switches, but stop flattening editing/editor and runtime bridges as top-level src/modules directories. Parent scans skip nested facets so runtime-3d can drop authoring by directory leaf. Co-authored-by: Cursor <cursoragent@cursor.com>
574 lines
29 KiB
JSON
574 lines
29 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": "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/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
|
|
}
|
|
]
|
|
}
|