Contributing guide
Op3 is developed as a research-grade framework that has to survive a PhD defense, a journal review, and an industry qualification. That imposes stricter contribution rules than a typical open-source project. This guide is the complete contract for anyone adding code, tests, documentation, or data.
The V&V-or-it-didn’t-happen rule
Every code change must ship with a test that would have failed before the change. This is the single most important rule in the project. No exceptions.
Fixing a bug? Write the test that exhibits the bug, confirm it fails, then write the fix, confirm it passes.
Adding a feature? Write a test that asserts the feature behaves as designed, confirm it fails in a minimal-implementation build, then implement until the test passes.
Refactoring? Run the full V&V suite before and after. The test deltas (pass counts, timings, reproducibility hash) must match except where an intentional numerical change is documented.
The PR template (.github/PULL_REQUEST_TEMPLATE.md) requires
pasting the V&V output of the full test run as evidence.
Never fabricate measured data
This is rule #2, documented in the project memory at
feedback_session_2026_04_01_final.md. If a reference number is
not in the cited paper or the cited dataset, mark it AWAITING_VERIFY
and let the V&V harness flip status automatically when someone fills
it in. Never guess, never “interpolate from memory”, never use a
placeholder that looks like a real number.
The PISA cross-validation harness
(scripts/pisa_cross_validation.py) is the reference
implementation of this pattern: each case has a citation, a status
flag, and a real paper-extracted reference that was only filled in
after the paper was actually opened.
Commit discipline
Never use
git add -Aorgit add .. Always stage specific files. The project has hundreds of gitignored artifacts (binaries, logs, large data) and one accidental bulk-add can balloon the repo history.Never bypass hooks with
--no-verifyunless a maintainer has explicitly approved.Never amend published commits. If a hook failure kills a commit, fix the issue and make a NEW commit. The previous commit is untouched.
Never force-push to
main. Feature branches can be force- pushed by the branch author before review;mainis strictly append-only.
Commit message format
<type>(<scope>): <short description>
<body explaining the WHY, not the WHAT>
Co-Authored-By: <co-author>
Types (conventional commits):
feat– new user-visible featurefix– bug fixdocs– documentation onlytest– adding or fixing testsrefactor– internal change with no behaviour differenceperf– performance improvementci– CI / release engineeringchore– dependency bumps, tooling updates
Scopes (project-specific):
pisa,cyclic,hssmall,mode-d– soil modulesuq,openfast,builder– specific subsystemsci,release,deps– infrastructurev0.4.1,v1.0.0-rc1, … – release tags
Example:
fix(pisa): depth functions + eccentric-load compliance
Closes the v0.4.1 PISA finding by implementing the three physics
corrections documented in DEVELOPER_NOTES section 13.2: ...
Branching model
main– always green, always releasable, all tags come from herefeature/<name>– feature branches off mainfix/<issue-id>– bug fix branches off maindocs/<topic>– documentation-only branches
Pull requests must target main and must pass the full CI workflow
before merge.
Adding a new turbine to the calibration regression
Opening an issue is the recommended first step (use the
calibration_request issue template). The workflow is:
Add a new entry to
op3/opensees_foundations/builder.py::TOWER_TEMPLATESwith the turbine geometry.Add a new
examples/<NN>_<turbine_name>/build.pycomposing theTowerModel.Add a new entry to
scripts/calibration_regression.py::REFERENCESwith the published reference frequency, tolerance, and citation.Add the rotor 1P frequency to
ROTOR_1P_HZinscripts/dnv_st_0126_conformance.py.Update the example count in
scripts/test_three_analyses.pyif needed (the script auto-discovers examples).Run the full V&V sweep and confirm the new example passes calibration and both conformance audits.
Update
docs/DEVELOPER_NOTES.mdsection 2 with the new entry.Commit with message
feat(calibration): add <turbine> to regression catalog.
Adding a new foundation standard
Create
op3/standards/<standard_name>.pyimplementing the stiffness function(s) with full NumPy docstrings, citing the source in the module docstring.Add unit tests in
tests/test_standards_<name>.pywith at least:Linearity in G (doubling G doubles K)
Symmetry and positive-definiteness of the output matrix
Agreement with a hand-computed reference at one point
Add an entry to the standards table in
docs/sphinx/standards.rst.Add the standard name to the accepted-source list in
scripts/iec_61400_3_conformance.py::check_I10_3_1_foundation_source.Commit with
feat(standards): add <standard_name> module.
Adding a new V&V test
Create the test in
tests/test_<topic>.pyusing the standalone runner pattern (def main() -> int) or pytest function pattern (def test_xxx()). Both work.Add the test module to the stage list in
scripts/release_validation_report.py::STAGES.Add the test to the CI workflow in
.github/workflows/ci.yml(undervv-suite).Add a row to the test summary table in
docs/sphinx/verification.rst.Run the full sweep and confirm the new test passes.
Code style
PEP 8 with line length up to 100 characters (
ruffconfig inpyproject.toml).Type hints on all public function signatures (
mypyconfig inpyproject.toml).Google or NumPy docstrings with at least one
ParametersandReturnssection.CommonMark Markdown for documentation. No HTML tags, no framework-specific extensions.
SI units throughout public APIs (see Technical reference section 1).
f-strings for string formatting, never
%or.format().Absolute imports within the
op3package (from op3.foundations import ...), not relative (from .foundations import ...).Dataclasses for structured data, not plain dicts.
Running the tools locally
# Formatting + lint
ruff check op3 scripts tests
ruff format op3 scripts tests
# Type check
mypy op3
# Full test suite
PYTHONUTF8=1 python scripts/release_validation_report.py
# Sphinx build
sphinx-build -b html docs/sphinx docs/sphinx/_build/html -W --keep-going
# Coverage
pytest --cov=op3 --cov-report=term-missing
Documentation contributions
All public API additions must come with a matching docstring. The Sphinx documentation picks docstrings up automatically via autodoc, so you do not usually need to write separate RST. Exceptions:
New foundation mode – add a section to
docs/sphinx/foundation_modes.rstNew standard – add a row to
docs/sphinx/standards.rstNew UQ tool – add a section to
docs/sphinx/uq.rstNew OpenFAST coupling surface – add to
docs/sphinx/openfast_coupling.rstMathematical derivation – add to
docs/sphinx/technical_reference.rstEnd-to-end worked example – add to
docs/sphinx/user_manual.rst
Review process
All PRs are reviewed by the project maintainer (Kim Kyeong Sun). Review criteria:
V&V evidence attached to the PR description.
Commit history follows the discipline rules above.
Code style checks pass (
ruff,mypy).No fabricated data – every reference number has a citation.
Documentation updated where required.
Reproducibility snapshot intentionally updated (or unchanged).
Security
Never commit secrets, credentials, or API keys. Use environment variables or external secret managers.
Never commit the OpenFAST binary (it is 44 MB and lives in
.gitignore).Never commit the r-test clone (it is 1.6 GB).
Never commit copyrighted paper PDFs (
tools/papers/is gitignored).Never commit patient / personal data – this is a wind turbine framework but the same discipline applies to the dissertation’s SiteA field data.
Release process
Only the project maintainer tags releases. The release procedure is:
Run the full V&V sweep on a clean checkout:
python scripts/release_validation_report.pyConfirm 18/19 PASS with 0 mandatory FAIL (the DNV SiteA flag is expected optional).
Update
CHANGELOG.mdwith the release entry.Bump
CITATION.cffversion and date.Bump
pyproject.tomlversion.Commit the release changes with message
release: v<version> -- <summary>.Tag the commit with an annotated tag:
git tag -a v0.X.Y -m "Op^3 v0.X.Y -- <summary>"
Push
mainand the tag to origin.Attach the release validation report Markdown to the GitHub release page.
If a DOI is desired, ensure Zenodo is linked to the repo and the release will auto-create a DOI.
Contact
Email: ksk5429@snu.ac.kr
Dissertation project: https://github.com/ksk5429 (top pinned)