ModelScope
An isolated registry of MetamodelEntity instances.
Construction of any MetamodelEntity (subtypes included) registers the new instance into the current scope for the calling thread — see current and with. Snapshots and the wireup pass (WireModel.wireAll) operate on whichever scope is current at the moment they run.
Two consumers, two usage patterns
Compiled / batch path (Gradle, CLI, engine): no explicit scope is created. Construction registers into the process-global default scope (global), exactly as the registry behaved before scopes existed. WireModel.reset() clears the global scope between runs (e.g. between stigCheckModel invocations within a single Gradle daemon).
Live source / IDE path (:stig-idea-plugin): every materialization run creates a fresh ModelScope, then runs construction + rule evaluation inside with:
val scope = ModelScope().apply { skipDeclaringClassCapture = true }
ModelScope.with(scope) {
// materialize entities from PSI — they auto-register here, not globally
val fm = Failure(name = "...", asil = ASIL.B, ...)
fm.bindToSource(referenceName = "fm1", declaringClassName = "com.x.y.FailuresKt")
// run rules — they see only this scope's entities
val problems = runModelChecks(rules, container)
}
// scope is now eligible for GC; nothing leaked into the global registryThreading
The current scope is held in a ThreadLocal. Each IDE inspection thread can carry its own scope without colliding with others. The global default scope is shared across threads and uses internal synchronization on its registry. Per-scope registries are also synchronized, so a scope can safely be populated from one thread and read from another.
Properties
True only after the caller has loaded every model output in the assessed project.
When true, MetamodelEntity construction will not capture declaringClass via StackWalker. The PSI materializer should set this on its scope — in source-mode the stack-walk would otherwise point at the materializer class itself, which is meaningless for rule evaluation. The materializer instead sets identity explicitly via MetamodelEntity.bindToSource.