Core Components Distinction Guide

This document aims to clarify the distinction between the different “Core” components within the SecInterp project to avoid confusion for both human developers and AI agents.

⚠️ The Fundamental Distinction

Two “Core” entities coexist in this development environment:

  1. SecInterp Core (The Project’s Kernel):

    • Location: /core directory within the project root.

    • Purpose: Contains pure business logic, geological algorithms, processing services, and domain models (DTOs) specific to SecInterp.

    • Current State: Decoupled. As of version 2.8.0, this module has been sanitized to have no direct dependencies on QGIS live classes during heavy processing (Thread-Safe).

  2. QGIS Core (The QGIS API):

    • Reference: qgis.core Python package.

    • Purpose: Provides the underlying geospatial infrastructure (geometries, layers, projects, CRS).

    • Interaction: SecInterp uses qgis.core to extract data in the main thread, but the SecInterp Core processes this data using agnostic types (WKT, dictionaries, primitives).


🧭 Guidelines for Developers and AI

To maintain architectural integrity, follow these directives:

1. Do not assume “Core” always means QGIS

If asked to “review the core”, it almost exclusively refers to the /core directory of this plugin. Do not attempt to search for or modify internal files of the QGIS engine.

2. Data Boundaries (Decoupling)

  • Inside /core: Agnostic domain types must be used. Avoid instantiating QgsVectorLayer or accessing QgsProject.instance() within kernel services. Use DomainGeometry (WKT) and attribute dictionaries.

  • Inside /gui: This is where the translation between the real QGIS API (qgis.core) and the SecInterp Core takes place. Geometries are extracted and DTOs are prepared here.

3. File Naming and Imports

  • Local Files: Files in core/ (e.g., core/services/geology_service.py) are the SecInterp Brain.

  • External API: Imports starting with qgis.core, qgis.gui, or qgis.utils are External Dependencies.

  • Naming Rule: In discussions or code comments, use “Internal Core” to refer to /core and “PyQGIS API” for the software’s API.

4. The “Extract-then-Compute” Pattern

To avoid future complications, the data flow MUST follow this pattern:

  1. GUI/Task Interface Layer: Receives QGIS objects (QgsVectorLayer, QgsFeature). Extracts what is necessary (WKT geometry, attribute dictionaries).

  2. Core Layer: Receives only the extracted data (strings, dicts, floats). Performs heavy geometric calculations.

  3. Result: The Core returns DTOs (Data Transfer Objects) defined in core/types.py. The GUI layer is responsible for converting these back to QGIS layers if necessary.

5. Golden Rules for Thread-Safety

  • Prohibited: Importing qgis.gui inside core/. Background threads will crash if they attempt to touch any widget or window.

  • Restriction: Minimize the use of qgis.core inside core/. While some classes like QgsGeometry are thread-safe, it is preferable to operate on WKT to guarantee total independence.

  • Application Context: Never use iface or QgsProject.instance() inside core/. If project data is needed, pass it as pre-extracted arguments.


🧪 Differentiated Testing Strategy

  • Core Tests (tests/core/): Must be able to run without a full QGIS installation. They use lightweight mocks. They are the thermometer of geological logic.

  • Integration Tests (tests/integration/): Require real QGIS. They test that our “Core” correctly communicates with the “QGIS API”.


🛠️ Decoupling Summary (January 2026)

A major effort has been completed to ensure:

  • GeologyService does not use live QGIS layers in its processing method.

  • DrillholeService uses dictionaries instead of QgsFeature objects during trace calculation.

  • 3D projection logic accepts tuples and primitive types.

In summary: Keep our Core “pure”. Treat QGIS as an external service provider. Do not let the roots of one enter the logic of the other.