Digital Twin - Implementation Checklist¶
Package: mineproductivity.digital_twin
Governing specification: docs/architecture/08_Digital_Twin_Design_Specification.md
Architecture Decision Record: docs/adr/ADR-0008-Digital-Twin.md
Status: Not started
Binding, locked implementation contract for digital_twin - the third package built on top of the Foundation Layer, sitting directly above the now-locked decision. Nothing described here may be implemented before this checklist and its governing specification exist in reviewed form, and nothing may be implemented that is not represented by an item on this list. Complete in order; every box must be checked or explicitly deferred with a linked issue and Chief Software Architect sign-off before merge.
Pre-Implementation Gate¶
- Design specification (
08_Digital_Twin_Design_Specification.md) read in full by the implementer, including every cross-reference to specs 01–07. - ADR-0008 read in full; the rationale for
digital_twinexisting as a separate, stateful package abovedecision(and forTwinsubclassingcore.BaseEntityrather than being a plain mutable object) is understood, not merely accepted. -
core,events,ontology,registry,plugins,connectors,kpis,analytics,decisionavailable and importable, exactly as released; no lower package file is modified as a side effect of this work. - Confirmed:
digital_twinwill not importsimulation,optimization,agents, orvisualizationunder any circumstance - none of those packages exist yet (design spec §5). - Confirmed: no lower package (
corethroughdecision) will be modified to import or otherwise referencedigital_twin(design spec §5, §3.6).
Package Structure¶
-
src/mineproductivity/digital_twin/created matching design spec §6 exactly:abstractions.py,metadata.py,categories.py,lifecycle.py,state.py,snapshot.py,synchronization.py,telemetry.py,simulation.py,discovery.py,persistence.py,caching.py,result.py,_registry.py,exceptions.py,__init__.py,README.md. -
digital_twin/README.mdwritten following thecore/README.mdtemplate. - Confirmed
simulation.pycontains zero concrete, non-test subclasses ofTwinSimulationModel(mechanical grep/AST check - design spec §14, §32's interface-purity proof). - Confirmed
telemetry.pycontains no direct import of, or reference to, anyconnectors-package class - telemetry integration composes over already-event-sourced data only (design spec §16).
Public API¶
-
digital_twin/__init__.pyexports exactly the symbol list in design spec §7, alphabetized__all__. -
test_public_api.pymirrorstests/unit/core/test_public_api.pyand every existing package's own copy of it. -
TestNoForbiddenDependenciesAST-walks everydigital_twinsubmodule for a forbidden import (simulation,optimization,agents,visualization) - mirrors every existing package's own copy of this test (design spec §5). - A second, reverse-direction test asserts no file under
src/mineproductivity/{core,ontology,events,registry,plugins,connectors,kpis,analytics,decision}/importsmineproductivity.digital_twin(design spec §5, §3.6) - theanalytics/decision-package precedent for this test (spec 06/07 checklists) extended one layer up.
Twin Abstractions and Identity (§8, §9)¶
-
Twin(§8) - subclassescore.BaseEntity[str]directly;meta: ClassVar[TwinMetadata],scope: Mapping[str, str],state: TwinState,status: TwinStatus;_apply()abstract;with_state()non-overridden, produces a new instance viadataclasses.replace, never mutatesself. -
TwinContext(§8) -event_store,kpi_results,analytics_results,decision_results, optionalas_of. - Identity/equality proven:
Twin.__eq__/__hash__inherited unchanged fromBaseEntity(identity-based onid, ignoringstate/status); no override anywhere in the package. - All eleven twin category base classes (§9) implemented:
MineTwin,EquipmentTwin,PlantTwin,ConveyorTwin,HaulageTwin,FleetTwin,ProcessingPlantTwin,GeologicalTwin,VentilationTwin,StockpileTwin,ProductionTwin- each contributing only a namespace/category-check convention, no additional behavior. - Confirmed
scopeis set once at construction and never re-assigned in place anywhere in the codebase (design spec §9, §31's recorded anti-pattern).
Lifecycle (§10)¶
-
TwinStatusenum (§10) - exactlyProvisioned/Synchronized/Stale/Degraded/Retired. - Lifecycle transitions proven to match design spec §10's state diagram exactly;
Retiredproven terminal (no transition out of it) and a retiredidproven never reusable.
Synchronization, Event Integration, Telemetry (§11, §15, §16)¶
-
SyncPolicy(§11) -mode("realtime"/"scheduled"),event_filter(a plainevents.EventFilter), optionalpoll_interval. -
TwinSynchronizer.synchronize()(§11) - fetches currentTwinfromTwinRepository, calls_apply, writes back thewith_state()-produced replacement, returnsSyncResult; confirmed to never mutate theTwininstance it reads. - Live synchronization via
events.EventBus.subscribe(sync_policy.event_filter, handler)implemented and tested (§15). - Cold-start reconstruction via
events.EventStore.replay(as_of)implemented and tested, proven to converge on the identicalTwinStateincremental synchronization would produce for the same event history (§15, §32's replay-consistency proof). -
TelemetryReading(§16) implemented as a plain value object; confirmed constructed only from already-event-sourced payload fields, never from a vendor SDK or wire protocol directly.
State, Snapshot, Simulation Interface (§12, §13, §14)¶
-
TwinState(§12) -attributes: Mapping[str, Any],captured_at,schema_version;validate()rejects emptyattributes. -
TwinSnapshot(§13) -twin_id,state,status,as_of; confirmed distinct from and never confused withevents.EventSnapshotin code or tests. -
TwinSimulationModel(§14) -_simulate(twin, hypothesis, as_of) -> TwinSimulationResultsignature only; zero concrete subclasses shipped. -
TwinSimulationResult(§14, §25) implemented even though no producer of it ships in this release.
Twin Registry and Discovery (§17, §18)¶
-
digital_twin._registry.REGISTRY/register(§17) -Registry[str, type[Twin]], raisingTwinValidationErrorfor an empty code andTwinVersionConflictErrorfor a materially-different re-registration under an existing code. -
EntryPointSpec(group="mineproductivity.digital_twin", target_registry="digital_twin")discovery wired viaregistry.EntryPointDiscovery(§28). -
by_category()/by_scope()(§18) - plaincore.PredicateSpecificationfactories; composed withTwinRepository.list(); confirmed to return an empty sequence (never raise) for a filter matching nothing.
Serialization and Persistence (§19, §20)¶
- Every
TwinState/TwinSnapshot/TwinResultsubclass andTwinitself confirmed to serialize viacore.serialization(DataclassSerializer/to_dict) with no bespoke per-type serializer. -
TwinRepositoryimplemented astype TwinRepository = BaseRepository[Twin, str]- a type alias, not a new ABC or subclass. - Reference implementation uses
core.InMemoryRepository[Twin, str]()directly, with zero new persistence code. - Test suite for
TwinRepositorybehavior written against thecore.BaseRepository[Twin, str]contract alone, never againstInMemoryRepository-specific internals (§32's repository-substitutability proof).
Versioning (§21)¶
-
TwinMetadata.version(type-level SemVer),TwinStatus(instance lifecycle), andTwinState.schema_version(data-shape version) confirmed to vary independently - no code path derives one from another. -
TwinVersionConflictErrorraised at registration time for a materially-different re-registration under an existingTwinMetadata.code, never deferred.
Caching (§22)¶
-
TwinStateCache.get()/put()(§22) implemented, keyed by(twin_id, as_of). - Confirmed not a reuse of
kpis.ResultCache- cache key shape independently designed for twin-evidence bundles, not KPI-result semantics. - Confirmed a cache miss (
get()returningNone) never raises and always falls back to direct re-assembly fromkpis.KPIEngine/analytics.BatchAnalyticsRunner/decision.BatchDecisionRunner. - Confirmed
TwinSynchronizernever treatsTwinStateCacheas authoritative for "what is the twin's current state" - onlyTwinRepositoryis (§31's recorded anti-pattern).
Validation¶
-
TwinMetadata.validate()- non-emptycode, category matches the closedTwinCategorynamespace. -
TwinState.validate()- non-emptyattributes. - Each category base's namespace-convention check implemented (e.g. a
ConveyorTwinasserting itsmeta.codefalls in the conveyor namespace). -
Twin._apply()confirmed to never raise for a legitimately emptyeventsbatch - returnsself.stateunchanged instead.
Error Handling¶
- Full exception hierarchy (design spec §6
exceptions.py):TwinValidationError,TwinNotFoundError,TwinSyncError,TwinVersionConflictError,TwinStateConflictError- each subclassing the matchingcoreexception. -
SyncResult.warningsconfirmed to be the primary "why didn't state change" signal;TwinSyncErrorreserved for genuinely exceptional conditions only, never for a legitimately-unchanged sync outcome.
Result Models and Metadata (§25, §26)¶
-
TwinResultbase (twin_id,computed_at,warnings) and both concrete subclasses (SyncResult,TwinSimulationResult) implemented as frozencore.BaseValueObjects. - Confirmed
TwinState/TwinSnapshotare notTwinResultsubclasses (they represent the twin itself, not an outcome of an orchestration call about it). -
TwinCategoryenum (eleven members) andTwinMetadata(code,category,description,version) implemented;validate()rejects an emptycode.
Thread Safety & Concurrency¶
-
Twininstances confirmed immutable and safe to share/read across threads with no locking. -
TwinRepository's per-id write serialization contract documented and tested against any production-grade implementation candidate; confirmed the barecore.InMemoryRepositoryreference implementation provides no locking of its own (design spec §29) - any concurrent-write test against it must add external synchronization itself. -
digital_twin.REGISTRYconfirmed read-only and thread-safe after startup discovery, inheritingRegistry's own contract. - Independent twins (different
ids) proven to synchronize fully in parallel without contention; concurrentsynchronize()calls for the sametwin_idproven to serialize correctly (no lost update) once a conforming productionTwinRepositoryis used. -
TwinStateCachereads/writes keyed by(twin_id, as_of)proven non-contending across independent keys.
Tests¶
-
tests/unit/digital_twin/mirrorssrc/mineproductivity/digital_twin/1:1. - Coverage ≥95%.
- Unit tests per concrete twin category, each against a scripted event sequence with a known expected
TwinState(§32). - Identity/equality tests proving
BaseEntity-inherited__eq__/__hash__behave correctly forTwin(§32). - Synchronization correctness tests, cold-start reconstruction tests, and snapshot round-trip tests (§32).
- Registry/discovery isolation tests mirroring
tests/integration/test_registry_plugin_discovery.py's healthy/broken fixture-plugin pattern, specialized forTwin(§32). - Interface-only ABC contract test for
TwinSimulationModel(bare-ABC instantiation raisesTypeError) - no algorithmic-correctness test exists for it (§32). - Concurrency stress tests: same-
twin_idserialization and different-twin_idnon-interference (§32). - The seven package acceptance proofs in design spec §32 (no-fact-recomputation, immutability, interface-purity, no-architectural-drift, replay-consistency, scope-immutability, repository-substitutability) each independently verified and recorded in the PR description.
Documentation¶
-
digital_twin/README.mdcomplete. - Every registered
Twintype's docstring restates itsTwinMetadata.descriptionfor source-level readability.
Examples¶
-
examples/digital_twin/01_provision_and_sync.py- the design spec §15 worked example (cold-start aConveyorTwin, then live-subscribe), end-to-end. -
examples/digital_twin/02_discovery.py-by_category/by_scopecomposed lookups over a populatedTwinRepository. -
examples/digital_twin/03_snapshot_and_serialize.py-TwinSnapshotcapture,core.serializationround-trip. -
examples/digital_twin/04_plugin_twin_type.py- a third-party-styleTwintype registered via entry points, mirroringexamples/registry/01_register_and_discover.py's pattern. - All examples pass
mypy --strict+ruff.
Benchmarks¶
-
TwinRepository.get()/list()latency at representative twin-population scale, recorded inbenchmark/reports/digital_twin/. - Cold-start replay cost vs. event history length, with and without
EventSnapshotacceleration, recorded.
Certification¶
- Design spec §32's seven package acceptance proofs pass and are recorded in the PR description (duplicated here from Tests for merge-gate visibility).
Type Hints, Mypy, Ruff, Coverage¶
- 100% type-hinted;
mypy --strictclean. -
ruff checkandruff format --checkclean. - Coverage report attached; ≥95%.
Release¶
-
CHANGELOG.mdupdated. - Root README dependency diagram cross-checked - confirm no forbidden import (
simulation,optimization,agents,visualization) was introduced, and confirm no lower package gained a newdigital_twinimport. - Version bump proposed and reviewed.
- Design spec §32's acceptance proofs re-verified as final merge gate.
Derived from 08_Digital_Twin_Design_Specification.md. Keep in sync with the governing specification and with ADR-0008-Digital-Twin.md.