otko/CONTRIBUTING.md

97 lines
3.6 KiB
Markdown
Raw Normal View History

2026-09-08 02:12:15 -04:00
# Contributing
Thanks for helping with OTKO — a SAP2000-style desktop GUI for
OpenSeesPy. Early-stage project: the bar is architecture cleanliness, not
feature count. If your change breaks a layering rule below, it won't
merge — no matter how useful the feature.
2026-09-08 02:12:15 -04:00
## Dev setup
```bash
python -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windows
pip install -e ".[gui,dev]"
2026-09-08 02:12:15 -04:00
pre-commit install
```
`pip install -e ".[gui,dev]"` pulls the Qt/PyVista desktop stack plus the
dev tools. For a headless checkout (core + services only, no Qt) use
`pip install -e .` instead. Python 3.10+; on Windows use 3.12+.
Launch the GUI with:
```bash
python -m otko
```
`pre-commit install` wires ruff + mypy into your local git hooks so
obvious issues are caught before a commit. Run it once per clone.
2026-09-08 02:12:15 -04:00
## Before opening a PR
Run the verify commands in this order and make sure they are all clean:
2026-09-08 02:12:15 -04:00
```bash
ruff check src tests
ruff format src tests # line-length 100, E501 ignored
2026-09-08 02:12:15 -04:00
mypy src/otko/core src/otko/services
pytest -m "not slow" # CI gate: lint → this, on 3.10/3.11/3.12 × ubuntu/windows/macos
2026-09-08 02:12:15 -04:00
```
Focused runs are faster while iterating: `pytest tests/unit` (pure logic,
milliseconds), `pytest tests/gui -k <name>` (pytest-qt, needs a display;
Linux GUI tests want `xvfb-run -a pytest ...`), and
`pytest tests/integration -k <name>` (real OpenSeesPy runs). Single test:
`pytest tests/unit/test_project.py::test_name -q`. Markers: `gui`, `slow`.
2026-09-08 02:12:15 -04:00
## Architectural rules (enforced in review)
OTKO uses a strict one-way **MVVM + service** architecture. Dependencies
flow outward-in only:
```
views → viewmodels → services → core
```
`commands` sits alongside the bridge and owns every model mutation.
1. `core/` is pure Python — stdlib + numpy + pydantic. It may **not**
import Qt or `openseespy`. Period.
2. `services/` may use `core` + `h5py` + `openseespy`, but may **not**
import Qt.
3. `views/` (PySide6/pyvistaqt) may **not** import `openseespy` directly —
go through a service. No business logic in `views`.
4. `viewmodels/` bridges `core` ↔ Qt (signals, `QUndoStack`).
5. `commands/` holds the `QUndoCommand` subclasses; all model mutations
go through `commands`, not ad-hoc edits in `views`.
6. Public functions and methods need type hints and a docstring.
7. New domain entities go through Pydantic validation.
8. Long-running operations (>50 ms) run off the GUI thread (`AnalysisWorker`
in a `QThread`, cancelled via `isInterruptionRequested()`; results cross
threads as a lightweight `ResultsHandle` written to HDF5).
The full package map and the fixed OpenSeesPy command order the runner
emits live in [`docs/architecture.md`](docs/architecture.md). Never
reorder the runner's commands.
## Branch model
`main` is the default and integration branch. Work on short-lived topic
branches cut from `main` — `feat/<topic>`, `fix/<topic>`, or
`docs/<topic>` — and open a pull request against `main`. Do not commit
directly to `main` from an agent session. There is no `develop` branch.
2026-09-08 02:12:15 -04:00
## Commit style
Conventional Commits — `feat:`, `fix:`, `refactor:`, `docs:`, `test:`,
`chore:`, `ci:`. Keep each commit focused; a `feat:` commit should add a
feature, not mix one in with unrelated refactors.
## Documentation
If your change is user-visible, update
[`docs/QUICK_GUIDE.md`](docs/QUICK_GUIDE.md) and the relevant roadmap or
ADR entry. Project model files are `.osmodel` (Pydantic-validated JSON);
regenerate the checked-in `examples/*.osmodel` from their scripts with
`python examples/<name>.py` rather than hand-editing them.