24 KiB
C++ Object-Oriented Modular Refactoring Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:subagent-driven-development(recommended) orsuperpowers:executing-plansto implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.In FESA, those task-by-task semantics are mediated by the project Harness. Do not invoke an implementation skill or select a Step directly; a separate user request must start
scripts/execute.py, which selects exactly one pending Step.
Goal: Preserve the current B33, MITC4, and linear-static numerical and external contracts while converting the FESA C++ production code to explicit object-oriented boundaries, focused modules, shared utilities, Google C++ style, and production-only Doxygen documentation.
Architecture: Domain owns immutable polymorphic semantic definitions through
std::unique_ptr and stable EntityIndex positions. ElementDefinition remains
separate from runtime numerical Element, and load, boundary-condition, analysis,
material, and property abstractions each have independent hierarchies. Existing
deterministic assembly, result identity, HDF5 schema, and reference comparison
contracts remain unchanged.
Tech Stack: C++17, MSVC x64 Debug, CMake, CTest, GoogleTest, Intel oneMKL, Intel oneTBB, HDF5, clang-format, clang-tidy, and optional Doxygen configuration.
Global Constraints
- Follow
/docs/CODINGSTYLE.mdand the official Google C++ Style Guide baseline. - Use PascalCase for every C++ function and accessor; use
.hproduction headers with full-path include guards; retain.cppas the FESA source-file exception. - Add Doxygen comments only to production code. Do not add Doxygen coverage to tests.
- Keep C++17 and MSVC x64 Debug compatibility and add no compiler warnings under
/W4 /WX. - Preserve the approved B33 and MITC4 formulations, signs, units, coordinate systems, reduction order, result row identity, HDF5 schema, tolerances, and reference files.
- Do not implement MITC3, solid elements, dynamics, eigenvalue analysis, response spectrum, random vibration, density, plasticity, anisotropy, distributed load, body force, or MPC behavior.
- Do not expose MKL, TBB, HDF5, Win32, or vendor integer types from public solver-core headers.
- Every C++ production change requires a related C++ test and an in-Step
RED -> observed failure -> minimal GREEN -> focused/full VERIFYcycle. - Do not run
scripts/execute.pyuntil the user gives a separate explicit execution request. - Doxygen comments and
Doxyfileconfiguration are in scope; generated Doxygen output is deferred and is not a blocking command for this phase.
1. Metadata
| Field | Value |
|---|---|
feature_id |
cpp-object-oriented-modular-refactoring |
source_requirement |
/docs/superpowers/specs/2026-08-16-cpp-object-oriented-modular-refactoring-design.md |
source_research |
Existing repository duplication and ownership audit captured by the approved design; no new FEM research is required |
source_formulation |
/docs/linear-static-3d-euler-beam/formulation.md; /docs/linear-static-mitc4-shell/formulation.md |
source_numerical_review |
/docs/linear-static-3d-euler-beam/numerical-review.md; /docs/linear-static-mitc4-shell/numerical-review.md |
source_io_definition |
/docs/linear-static-3d-euler-beam/io.md; /docs/linear-static-mitc4-shell/io.md |
source_reference_models |
/docs/linear-static-3d-euler-beam/reference-model.md; /docs/linear-static-mitc4-shell/reference-model.md |
status |
ready-for-implementation |
owner_agent |
implementation-planning-agent |
date |
2026-08-16 |
2. Readiness Check
- The written refactoring design and the 25-Step draft were explicitly approved on 2026-08-16.
- B33 and MITC4 requirements, formulations, numerical reviews, I/O projections, and reference contracts already exist and remain upstream read-only inputs.
- Required reference inputs and CSVs are present under
/reference/cantilever beam/and/reference/shell/. clang-format.exeandclang-tidy.exeare present atC:/Program Files/LLVM/bin/; the current long-lived process PATH need not contain that directory because the plan uses the absolute paths.- Doxygen generation is intentionally deferred by user decision. The implementation
still adds production comments and a warning-strict
Doxyfilefor later use. - No missing formulation, tolerance, HDF5 projection, or artifact decision prevents implementation planning.
3. Implementation Scope
Included
- Repository policy/tooling and Implementation Agent enforcement.
- Mechanical
.hppto.h, header guard, PascalCase, formatting, and production Doxygen conversion in reviewable module slices. - Shared
Vector3, dense-BLAS internal adapter, ASCII utilities,SourceTargetResolver, and owner-based DOF invariant validation. - Independent abstract boundaries for material, element property, semantic element definition, runtime element, load, boundary condition, and analysis.
- Current concrete B33, MITC4, isotropic linear elasticity, beam/shell property, concentrated nodal load, prescribed displacement, and linear-static behavior.
- Responsibility-based splits of domain mapping, result recovery, and HDF5 writing.
- Full MSVC/CTest and existing B33/MITC4 external reference verification.
Excluded and non-goals
- New physics, input keywords, output datasets, tolerances, reference artifacts, or runtime performance optimization.
- A common root base shared by unrelated element, load, material, and analysis types.
- A giant material interface containing density, plasticity, and anisotropy options.
- Registry/plugin frameworks, global static registration, speculative
Clone(), or unnecessary shared ownership.
4. Refactoring Requirements
| ID | Requirement |
|---|---|
R-PRESERVE-001 |
Current B33/MITC4/linear-static numerical and external results shall remain unchanged within their approved contracts. |
R-STYLE-001 |
Production and test C++ shall use approved Google-style naming and formatting; production headers shall use .h and header guards. |
R-DOC-001 |
Production functions and classes shall carry useful Doxygen contracts; tests shall not require Doxygen comments. |
R-DUP-001 |
Repeated fixed-size 3D vector operations shall be implemented once by Vector3. |
R-DUP-002 |
Repeated dense-BLAS conversion/copy, ASCII/source resolution, and DOF invariant logic shall have one owner. |
R-MODEL-001 |
Material, element-property, and element-definition semantic objects shall have independent abstractions and Domain-owned stable lifetime. |
R-ELEMENT-001 |
Semantic ElementDefinition and runtime numerical Element shall remain separate and be connected by a fail-closed factory. |
R-PIPELINE-001 |
DofManager, SparseAssembler, and ResultRecovery shall consume runtime Element interfaces without scattered B33/MITC4 type branches. |
R-LOAD-001 |
A Load shall emit ordered contributions and only LoadAssembler shall accumulate the global vector. |
R-BC-001 |
A BoundaryCondition shall emit definitions and an essential-constraint policy shall enforce prescribed displacement. |
R-ANALYSIS-001 |
Analysis shall expose only Run() and LinearStaticAnalysis shall own its approved lifecycle. |
R-MODULE-001 |
Domain mapping, recovery, and HDF5 writing shall be split by their approved responsibilities. |
R-AGENT-001 |
Implementation Agent shall read /docs/CODINGSTYLE.md as a mandatory global input. |
R-SCOPE-001 |
No excluded future feature or runtime-performance change shall be introduced. |
5. Work Breakdown
| Task | Name | Depends on | Deliverable |
|---|---|---|---|
T00 |
coding-style-agent-contract | none | Agent profile and Python contract enforce CODINGSTYLE.md. |
T01 |
cpp-style-tooling | T00 |
clang-format/tidy configuration and deferred Doxygen configuration. |
T02 |
architecture-boundaries | T00 |
Architecture and ADR record the approved responsibility graph. |
T03 |
foundation-google-style | T01 |
Core/math/linear-solver APIs use the approved style. |
T04 |
model-element-google-style | T03 |
Model and current element APIs use the approved style. |
T05 |
solver-workflow-google-style | T04 |
FEM/assembly/constraint/analysis/result APIs use the approved style. |
T06 |
io-application-google-style | T05 |
I/O, application, and test helper APIs use the approved style. |
T07 |
vector3-value-type | T03 |
Tested fixed-size vector value type. |
T08 |
element-geometry-vector3 | T04, T07 |
Element/model geometry duplicate helpers removed. |
T09 |
result-io-vector3 | T06, T08 |
Result/I/O vector duplicate helpers removed. |
T10 |
dense-blas-adapter | T03 |
Matrix/Vector share private MKL conversion and copy helpers. |
T11 |
source-target-resolver | T06 |
Shared ASCII and source-target resolution module. |
T12 |
material-property-hierarchy | T04 |
Independent semantic material and property abstractions. |
T13 |
element-definition-domain | T11, T12 |
Domain-owned polymorphic semantic element definitions. |
T14 |
runtime-element-factory | T08, T13 |
Runtime element abstraction and fail-closed factory. |
T15 |
generic-dof-manager | T14 |
DofManager consumes element DOF layouts and owns invariant checks. |
T16 |
generic-sparse-assembler | T15 |
SparseAssembler consumes element stiffness contributions. |
T17 |
generic-result-recovery | T16 |
ResultRecovery consumes element result bundles. |
T18 |
load-hierarchy | T11, T15 |
Ordered load contribution hierarchy. |
T19 |
boundary-condition-policy | T15 |
Constraint definition hierarchy and essential policy. |
T20 |
analysis-hierarchy | T17, T18, T19 |
Minimal Analysis base and unchanged linear-static lifecycle. |
T21 |
domain-mapper-modules | T11, T13, T18, T19 |
Mapper split by semantic responsibility. |
T22 |
result-recovery-modules | T17 |
Recovery split into global, beam, shell, and commit responsibilities. |
T23 |
hdf5-writer-modules | T17, T22 |
HDF5 writer split without schema changes. |
T24 |
final-quality-reference-gate | all prior tasks | Full style, build/test, HDF5, determinism, and reference evidence. |
Each task maps one-to-one to /phases/cpp-object-oriented-modular-refactoring/stepN.md.
6. TDD Test Plan
| Test ID | First failing evidence | GREEN evidence |
|---|---|---|
P-AGENT-001 |
Python contract reports missing mandatory CODINGSTYLE.md input. |
Agent workflow contract passes. |
P-STYLE-001 |
Policy test reports missing or incorrect clang/Doxygen configuration. | Policy and full Harness Python tests pass. |
C-STYLE-001..004 |
Test includes/calls use .h and PascalCase before production conversion, causing a compile failure. |
Focused module suites and full CTest pass. |
C-VEC3-001 |
vector3_test.cpp cannot compile because Vector3 is absent. |
Arithmetic, finite, and normalization-boundary tests pass. |
C-DUP-001..004 |
Tests reference the new shared seam before it exists. | Shared seam passes and old duplicate helper definitions are absent by rg checks. |
C-MODEL-001..002 |
Polymorphic ownership and const stable-index tests fail before semantic bases exist. | Material/property/definition tests and Domain mapping tests pass. |
C-ELEMENT-001 |
Base-interface creation and incompatibility tests fail before ElementFactory. |
B33/MITC4 creation, rejection, stiffness, and recovery tests pass. |
C-DOF-001 |
Fake runtime element layout is not accepted by DofManager. | Stable scatter/pattern and invariant tests pass. |
C-ASSEMBLY-001 |
Fake runtime contribution is not assembled. | Serial/TBB/repeated CSR outputs remain byte-identical. |
C-RECOVERY-001 |
Fake result bundle cannot flow through recovery. | Beam/shell identities, signs, energy, and atomic rollback pass. |
C-LOAD-001 |
A fake Load cannot emit ordered full-DOF contributions. | Source-order accumulation and current load validation pass. |
C-BC-001 |
A fake BoundaryCondition cannot resolve constraint definitions. | Nonzero prescribed displacement and reconstruction pass. |
C-ANALYSIS-001 |
LinearStaticAnalysis cannot be invoked through Analysis. |
Approved factorization/load/solve/recovery lifecycle passes. |
C-MODULE-001..003 |
Tests reference extracted mapper/recovery/HDF5 responsibilities before their seams exist. | Existing public behavior and atomicity suites pass after extraction. |
C-REF-B33-001 |
No new intentional failure; final gate reuses the approved external comparison. | B33 comparison passes under its existing component-scale tolerance. |
C-REF-MITC4-001 |
No new intentional failure; final gate reuses the approved external comparison. | MITC4 translations pass at fixed 1.0e-5; rotations remain warning-only. |
RED and GREEN evidence, command, exit code, duration, output tail, and failed test names must be recorded during execution in the Implementation-owned reports. A final reference gate does not manufacture an artificial RED because it verifies an unchanged approved external contract after all refactoring tasks.
7. CMake/CTest Plan
- Keep the existing
fesa_solver,fesa_cli,fesa_unit_tests,fesa_integration_tests,fesa_reference_tests, andfesa_teststargets. - Register new production/test files in
/src/fesa/CMakeLists.txtand/tests/CMakeLists.txtin their owning task. - Do not create a new test executable or change existing test labels.
.harness/config.jsonis absent, so use.harness/build, MSVC x64, Debug, and the explicit local dependency paths recorded in each Step.- Every C++ task runs a focused CTest regular expression and the full CTest discovery and execution sequence.
- Step
T24performs a fresh configure and the final B33/MITC4 reference tests.
8. Candidate Files and Ownership
| Responsibility | Candidate files |
|---|---|
| Policy/tooling | .codex/agents/implementation-agent.toml, .clang-format, .clang-tidy, Doxyfile, tests/test_agent_skill_workflow_contract.py, tests/test_cpp_policy_contract.py |
| Fixed/dynamic math | include/fesa/math/vector3.h, include/fesa/math/vector.h, include/fesa/math/matrix.h, src/fesa/math/dense_blas_internal.h, matching .cpp and unit tests |
| Semantic material/property | include/fesa/materials/*.h, include/fesa/properties/*.h, src/fesa/materials/*.cpp, src/fesa/properties/*.cpp, matching unit tests |
| Semantic element definitions | include/fesa/elements/element_definition.h, concrete definition headers, include/fesa/model/domain.h, src/fesa/model/domain.cpp |
| Runtime elements | include/fesa/elements/element.h, element_factory.h, existing B33/MITC4 kernels and new factory implementation/tests |
| Source resolution | include/fesa/model/source_target_resolver.h, src/fesa/model/source_target_resolver.cpp, focused tests |
| Solver consumers | DofManager, SparseAssembler, ResultRecovery headers/sources/tests |
| Loads | include/fesa/loads/load.h, concentrated_nodal_load.h, sources, LoadAssembler and tests |
| Constraints | boundary_condition.h, prescribed_displacement.h, essential_constraint_policy.h, sources and tests |
| Analysis | analysis.h, linear_static_analysis.h, sources and integration tests |
| Mapper split | focused private mapper modules under src/fesa/io/abaqus/ with one public domain_mapper.h facade |
| Recovery split | focused modules under src/fesa/results/ with one public result_recovery.h facade |
| HDF5 split | private modules under src/fesa/io/hdf5/ with one public hdf5_results_writer.h facade |
These are implementation candidates, not permission to introduce extra public API. Each Step must choose the minimum files consistent with the approved boundaries.
9. Candidate Interface Contracts
The implementation may refine parameter carrier names while preserving these semantic contracts:
struct AnalysisRequest {
std::filesystem::path input_path;
std::filesystem::path output_path;
};
class Analysis {
public:
virtual ~Analysis() = default;
virtual Status Run(const AnalysisRequest& request) = 0;
};
class ElementDefinition {
public:
virtual ~ElementDefinition() = default;
virtual ElementDefinitionKind Kind() const noexcept = 0;
virtual const SourceEntityId& SourceId() const noexcept = 0;
virtual const std::vector<EntityIndex>& NodeIndices() const noexcept = 0;
virtual EntityIndex PropertyIndex() const noexcept = 0;
};
class Element {
public:
virtual ~Element() = default;
virtual const ElementDofLayout& DofLayout() const noexcept = 0;
virtual Result<ElementStiffnessContribution> ComputeStiffness() const = 0;
virtual Result<ElementResultBundle> Recover(
const Vector& full_displacement) const = 0;
};
class Load {
public:
virtual ~Load() = default;
virtual Result<std::vector<LoadContribution>> ComputeContributions(
const LoadContext& context) const = 0;
};
class BoundaryCondition {
public:
virtual ~BoundaryCondition() = default;
virtual Result<std::vector<ConstraintDefinition>> ResolveConstraints(
const BoundaryConditionContext& context) const = 0;
};
Do not add future-only methods to these bases. Factory compatibility may use a centralized,
explicit kind discriminator followed by a checked concrete access; consumers must not scatter
dynamic_cast or B33/MITC4 switches.
10. Data Flow Contract
existing Abaqus .inp
-> syntax reader
-> responsibility-split semantic mappers
-> immutable Domain-owned definitions
-> AnalysisModel non-owning active view
-> ElementFactory runtime elements
-> DofManager / deterministic assembly / constraints
-> LinearStaticAnalysis
-> result recovery candidate and validation
-> authoritative results.h5 atomic commit
-> test-only deterministic projection
-> existing Abaqus CSV comparison by source identity and component
- B33 input and CSVs remain under
/reference/cantilever beam/with their current names and component-scale tolerance. - Blocking MITC4 S4 input/displacement CSV remains under
/reference/shell/with fixed absolute tolerance1.0e-5for U1/U2/U3 and warning-only UR1/UR2/UR3. /reference/shellR/is not promoted into a blocking comparison.- No reference artifact is renamed, rewritten, regenerated, or normalized.
11. Acceptance Traceability Matrix
| Requirement | Tasks | Tests/evidence | Acceptance |
|---|---|---|---|
R-PRESERVE-001 |
T03..T24 |
all current suites, C-REF-B33-001, C-REF-MITC4-001 |
Full CTest and blocking references pass. |
R-STYLE-001 |
T01, T03..T06, T24 |
P-STYLE-001, clang-format, clang-tidy config, legacy-header scan |
Style commands and full build pass. |
R-DOC-001 |
T03..T24 |
policy scan and configured warning-strict Doxyfile | Production comments exist; tests are excluded. |
R-DUP-001 |
T07..T09 |
C-VEC3-001, element/result/I/O suites, duplicate scan |
One Vector3 implementation remains. |
R-DUP-002 |
T10, T11, T15 |
C-DUP-001..004 |
Shared owners pass focused tests. |
R-MODEL-001 |
T12, T13 |
C-MODEL-001..002 |
Polymorphic stable ownership passes. |
R-ELEMENT-001 |
T13, T14 |
C-ELEMENT-001 |
Factory creates current kinds and rejects incompatible combinations. |
R-PIPELINE-001 |
T15..T17 |
C-DOF-001, C-ASSEMBLY-001, C-RECOVERY-001 |
Generic consumer and deterministic tests pass. |
R-LOAD-001 |
T18 |
C-LOAD-001 |
Ordered accumulation and current validations pass. |
R-BC-001 |
T19 |
C-BC-001 |
Prescribed displacement partition/reconstruction passes. |
R-ANALYSIS-001 |
T20 |
C-ANALYSIS-001 |
Lifecycle and factorization count pass. |
R-MODULE-001 |
T21..T23 |
C-MODULE-001..003 |
Facade behavior and atomicity suites pass. |
R-AGENT-001 |
T00 |
P-AGENT-001 |
Python workflow contract passes. |
R-SCOPE-001 |
every task | diff review and final reference/artifact checks | No excluded behavior or artifact change appears. |
12. Validation Commands
Harness Python and policy validation:
uv run --with pytest python -m pytest -v -rs
& "C:/Program Files/LLVM/bin/clang-format.exe" --version
& "C:/Program Files/LLVM/bin/clang-tidy.exe" --version
& "C:/Program Files/LLVM/bin/clang-tidy.exe" --verify-config
MSVC clean configure and full verification:
$requiredBuildPaths = @(
"C:/git/googletest",
"C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl",
"C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb",
"C:/Program Files/HDF_Group/HDF5/2.1.1/cmake"
)
foreach ($requiredBuildPath in $requiredBuildPaths) {
if (-not (Test-Path -LiteralPath $requiredBuildPath)) {
throw "Missing $requiredBuildPath"
}
}
cmake --fresh -S . -B .harness/build -G "Visual Studio 18 2026" -A x64 `
"-DFESA_GTEST_SOURCE_DIR=C:/git/googletest" `
"-DMKL_DIR=C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl" `
"-DTBB_DIR=C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb" `
"-DHDF5_DIR=C:/Program Files/HDF_Group/HDF5/2.1.1/cmake"
cmake --build .harness/build --config Debug --target fesa_tests
ctest --test-dir .harness/build -C Debug --show-only=json-v1
ctest --test-dir .harness/build -C Debug --output-on-failure
ctest --test-dir .harness/build -C Debug `
-R "B33ReferenceComparison|Mitc4S4Reference" --output-on-failure
Repository style and artifact checks:
$cppFiles = @(rg --files include src tests -g "*.h" -g "*.cpp")
& "C:/Program Files/LLVM/bin/clang-format.exe" --dry-run --Werror $cppFiles
$publicHeaders = @(rg --files include/fesa -g "*.h")
foreach ($publicHeader in $publicHeaders) {
& "C:/Program Files/LLVM/bin/clang-tidy.exe" --config-file=.clang-tidy `
$publicHeader -- -x c++ -std=c++17 -Iinclude
if ($LASTEXITCODE -ne 0) {
throw "clang-tidy failed for $publicHeader"
}
}
$legacyHeaders = @(rg --files include tests -g "*.hpp")
if ($legacyHeaders.Count -ne 0) {
$legacyHeaders
throw "Legacy .hpp headers remain"
}
git diff --exit-code 1e5758f -- reference
Doxygen generation is deliberately absent from the blocking commands. When the user
requests documentation generation later, execute doxygen Doxyfile and treat warnings
as failures without committing generated HTML.
13. Risks and Downstream Handoff
- Global API/header renaming has a wide compile blast radius. Mechanical style Steps are isolated from semantic restructuring to keep failures attributable.
- Domain polymorphism can accidentally destabilize vector indices or lifetimes. Tests must prove insertion order, const access, and AnalysisModel non-owning lifetime.
- Virtual element recovery can tempt a giant result record. Preserve distinct beam and shell rows in a backend-neutral bundle rather than adding meaningless common fields.
- Moving vector helpers can change floating-point operation order. Preserve each formulation expression order and use exact regression where no approved tolerance applies.
- File splits can leak vendor dependencies through public headers. Keep all HDF5/MKL/TBB types in private implementation modules.
Downstream handoff is one bounded handoff to implementation-agent through the
Coordinator: execute only the Executor-selected stepN.md, read /docs/CODINGSTYLE.md
before C++ work, record RED/GREEN/VERIFY evidence, and do not advance another Step.
14. Harness Step Draft
- Task name:
cpp-object-oriented-modular-refactoring - Steps:
step0.mdthroughstep24.mdin dependency order shown in Work Breakdown. - Every Step contains its own prerequisite files, test-first failure, candidate interfaces, exact focused/full commands, and prohibitions.
- Stop conditions are an upstream contract conflict, a missing declared artifact at final comparison, an unresolved environment dependency, or repeated build/test failure. In each case only the current Step status payload is changed.
- Planning approval materializes these files but does not authorize
python scripts/execute.py cpp-object-oriented-modular-refactoring.
15. Open Issues
- No blocking architecture, formulation, I/O, reference, or tolerance issue remains.
- Doxygen executable use and generated documentation are deferred by explicit user
decision; this does not waive production Doxygen comments or
Doxyfileconfiguration.