Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2a019ba
Docs: internal design note for moisture-aware LAI phenology (GH-1292)
sunt05 Apr 17, 2026
02b90f9
PR1: moisture-aware LAI phenology scaffolding (GH-1292)
sunt05 Apr 17, 2026
1e1d4fc
Merge remote-tracking branch 'origin/master' into sunt05/gh1292-lai-m…
sunt05 Apr 17, 2026
01b0b4c
Merge remote-tracking branch 'origin/master' into sunt05/gh1292-lai-m…
sunt05 Apr 17, 2026
ff80f87
PR2: activate Design C numerics for moisture-aware LAI (GH-1292)
sunt05 Apr 17, 2026
6368af5
PR3: calibration scaffolding for moisture-aware LAI (GH-1292)
sunt05 Apr 18, 2026
3a272c8
docs: add dev-notes archival infrastructure
sunt05 Apr 18, 2026
9583f47
chore: scientific-PR review workflow — template + audit-pr checklist
sunt05 Apr 18, 2026
5991fb4
docs: archive GH-1292 moisture-aware LAI dev-note (#1292)
sunt05 Apr 18, 2026
014e507
Revert "docs: add dev-notes archival infrastructure"
sunt05 Apr 19, 2026
bedac74
Revert "chore: scientific-PR review workflow — template + audit-pr ch…
sunt05 Apr 19, 2026
aa41255
fix(phys): use -1.0 sentinel for unset moisture-history state (GH-1292)
sunt05 Apr 19, 2026
22484fa
test: harden FLUXNET moisture-phenology diagnostic harness (GH-1292)
sunt05 Apr 19, 2026
fd02aa6
chore(audit-pr): add scientific PR description rigour check
sunt05 Apr 19, 2026
4970c53
Merge remote-tracking branch 'origin/master' into sunt05/gh1292-lai-m…
sunt05 Apr 19, 2026
8f79a3d
fix: harden moisture phenology diagnostics and compatibility
sunt05 Apr 19, 2026
7fc3c87
test: add required pytest nature markers to moisture phenology tests
sunt05 Apr 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .claude/skills/audit-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ gh pr diff {pr} --name-only

- **Step 1 - Context**: Gather files, classify changes
- **Step 2 - Code Style**: lint-code
- **Step 3 - Scientific**: Physics validation (if applicable)
- **Step 3 - Scientific**: Physics validation + description rigour (if applicable)
- **Step 4 - Testing**: Coverage, FIRST principles
- **Step 5 - Docs**: CHANGELOG, PR description
- **Step 6 - Governance**: Check feature status tags (see below)
Expand All @@ -27,6 +27,41 @@ gh pr diff {pr} --name-only
- **Step 9 - Approval**: Wait for human confirmation
- **Step 10 - Post**: Only after approval

## Scientific PR Description Rigour (Step 3)

For PRs that introduce or materially change a scientific component
(physics, numerics, calibration, benchmark), the PR description + thread
must expose the science clearly so reviewers can judge it in-place. This
is a description-quality check, not a separate artefact requirement —
evidence lives in the PR, not in a sidecar dashboard.

**A PR is "scientific" if it touches any of**:

- `src/suews/src/suews_phys_*.f95`
- `src/suews/src/suews_ctrl_daily_state.f95`
- `src/supy/data_model/` (new physics-facing fields or enums)
- New YAML parameters that affect model output
- A CHANGELOG entry tagged `[feature]` or `[change]` that is not pure
tooling / build / docs

**Required in the PR description (or posted as comments in the thread)**:

- [ ] **Methodology** — what was changed and how it was developed/validated
(governing equation, numerical approach, calibration procedure)
- [ ] **Scientific decisions** — key choices made and rationale
(why this parameterisation, why this threshold, what alternatives
were considered)
- [ ] **Results** — quantitative evidence that the change works, posted
in the PR (numbers, plots, before/after comparisons, test outputs).
A bare "tests pass" is not sufficient for scientific changes.

**If missing or thin**: flag as a blocking review comment and ask the
author to expand the PR body or post a follow-up comment with the
missing pieces. Do not approve a scientific PR whose description reads
as purely mechanical ("refactored X", "added Y") without scientific
narrative. If scope is ambiguous, ask the author to classify rather
than guess.

## Governance Check (Step 6)

For PRs that add new features or breaking changes:
Expand Down Expand Up @@ -73,6 +108,7 @@ Details: `references/style-checks.md`
|----------|--------|
| Code Style | PASS/FAIL |
| Scientific | PASS/FAIL/N/A |
| Description rigour | PASS/FAIL/N/A |
| Testing | PASS/FAIL |
| Docs | PASS/FAIL |

Expand Down
51 changes: 51 additions & 0 deletions .claude/skills/audit-pr/references/review-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,56 @@ Detailed checklist for comprehensive PR review.

---

## Scientific PR Description Rigour Checklist

Applies to any PR that introduces or materially changes a scientific
component. The evidence lives in the PR itself — description and
thread comments — not in a sidecar artefact. Missing pieces are a
**blocking** finding: ask the author to expand the body or post
follow-up comments before approving.

### Triggers — a PR is "scientific" if it touches

- [ ] Any file matching `src/suews/src/suews_phys_*.f95`
- [ ] `src/suews/src/suews_ctrl_daily_state.f95`
- [ ] `src/supy/data_model/` (new physics-facing fields, enums, validators)
- [ ] New YAML parameters that alter model output
- [ ] A CHANGELOG entry tagged `[feature]` or `[change]` that is not pure
tooling / build / docs
- [ ] Benchmark additions or regressions against published reference runs

### Required in the PR description / thread

- [ ] **Methodology** — what was changed and how it was developed or
validated (governing equation, numerical approach, calibration
procedure, data source)
- [ ] **Scientific decisions** — the key choices made and why: which
parameterisation, which threshold, which alternatives were
considered and rejected
- [ ] **Results** — quantitative evidence that the change works, posted
in the PR as numbers, figures, or comparison tables. Plots can be
embedded via `draft-post`'s figure upload or linked from a
comment. A bare "tests pass" is not sufficient for a scientific
change
- [ ] **Scope** — which issue this resolves, which follow-ups remain

### How to handle a thin or mechanical PR description

When a scientific PR arrives with a description that only names files
changed, or says "refactored X / added Y" without scientific narrative:

1. Flag it as "Description rigour: FAIL" in the review summary
2. Post a blocking review comment listing which of the four items above
are missing, and invite the author to either edit the PR body or
post the missing content as a follow-up comment in the thread
3. Do not approve the PR for merge until the description covers
methodology, decisions, and quantitative results
4. If scope is ambiguous (is this really scientific, or is it tooling?),
ask the author to classify in the PR description and defer to a
maintainer rather than guess

---

## Testing Checklist

### Coverage Requirements
Expand Down Expand Up @@ -176,6 +226,7 @@ PR can be merged when ALL of:
- [ ] CI tests pass
- [ ] Code review approved
- [ ] Scientific review approved (if physics changes)
- [ ] PR description covers methodology, scientific decisions, and results (if scientific change)
- [ ] Documentation updated
- [ ] CHANGELOG entry present
- [ ] No blocking issues
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ EXAMPLES:

### 18 Apr 2026

- [feature][experimental] Added parameter-sweep calibration tool for moisture-aware LAI (#1292). `scripts/verify/moisture_phenology_sweep.py` scans any of the six moisture parameters (`w_wilt`, `w_opt`, `f_shape`, `w_on`, `w_off`, `tau_w`) over a user-supplied or default value list, reruns SUEWS per value, and writes a dose-response summary (mean LAI, RMSE vs `LAIType = 0` baseline, seasonal amplitude, green-up DOY) plus a dual-axis sensitivity plot to `.context/gh1292/<site>/sweep_<param>.{json,png}`. The `--dry-start` flag depletes vegetation `soilstore_surf` so the moisture gate engages at otherwise well-watered samples. Includes a pairwise-validator co-adjustment that keeps `w_opt > w_wilt` and `w_on > w_off` satisfied during extreme sweep values. Design note extended with a new calibration-methodology appendix (London sensitivity results, FLUXNET calibration roadmap, status of the optional SDD term).
- [maintenance] Register `physics` / `api` pytest markers as an orthogonal axis to the existing tier markers (#1300)
- `physics` covers numerical / binary correctness (one canonical Python per `(OS, arch)` suffices post-abi3); `api` covers Python wrapper surface (pandas / numpy / pydantic, CLI, `SUEWSSimulation`) and needs full `(platform x Python)` coverage
- Applied module-level `pytestmark` to all 43 non-UMEP test files; the 5 UMEP test files pick up `api` via the existing `pytest_collection_modifyitems` hook
Expand All @@ -79,6 +80,8 @@ EXAMPLES:

### 17 Apr 2026

- [feature][experimental] Activated moisture-aware LAI phenology numerics (`LAIType = 2`) with the Design C formulation (#1292). Replaces the PR1 no-op branch with (a) a Jarvis-style water-stress factor on `delta_GDD` parametrised by `w_wilt`, `w_opt`, and `f_shape` on dimensionless relative soil water `w = 1 - smd/smdcap`, and (b) a CLM5-style persistence latch (Lawrence et al. 2019) that freezes thermal accumulation when the `tau_w`-day running mean of `w` drops below `w_off` and reopens when it rises above `w_on` while a thermal companion (Tbar >= BaseT_GDD) is met. `PHENOLOGY_STATE.leaf_on_permitted` now defaults to true so well-watered sites do not spend `tau_w` days ramping up, and `wbar_id` is seeded from the first measured `w` on the first call. Default moisture thresholds (`w_wilt = 0.15`, `w_opt = 0.40`, `w_on = 0.35`, `w_off = 0.20`) degrade gracefully to thermal-only behaviour at well-watered sites -- the bundled London sample is bit-identical to `LAIType = 0`. Aggressive thresholds or depleted soil-store initial conditions produce the expected strictly lower LAI; a dry-start regression test locks in the spring green-up delay. Calibration against FLUXNET2015 dryland / monsoon sites is deferred to a follow-up. Internal design note: `dev-ref/design-notes/gh1292-moisture-phenology.md`.
- [feature][experimental] Added scaffolding for moisture-aware LAI phenology (`LAIType = 2`) behind a new per-vegetation-surface switch (#1292). Extends `LAI_PRM` with six parameter slots (`w_wilt`, `w_opt`, `f_shape`, `w_on`, `w_off`, `tau_w`) and `PHENOLOGY_STATE` with three per-veg-surface state slots (`wbar_id`, `w_id_prev`, `leaf_on_permitted`); bumps the Rust/C bridge schema for `LAI_PRM`, `PHENOLOGY_STATE`, `LC_DECTR_PRM`, `LC_EVETR_PRM`, `LC_GRASS_PRM` to version 2. The `LAIType = 2` branch is a no-op that reproduces `LAIType = 0` bit-identically in this release -- Design C numerics (Jarvis water-stress factor plus CLM5-style persistence trigger) land in a later PR. Internal design note: `dev-ref/design-notes/gh1292-moisture-phenology.md`.
- [maintenance] Remove NumPy build-time dependency (post-f2py cleanup) (#1298)
- [maintenance] Enforce numpy-style docstrings via ruff `D` rules (#1294)
- Removed D100-D105/D107 from the global gradual-adoption ignore list in `.ruff.toml`
Expand Down
13 changes: 13 additions & 0 deletions dev-ref/design-notes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Design Notes

Internal design notes for substantive SUEWS design decisions that need a durable record before implementation.

## Convention

- One markdown file per issue-scoped design decision.
- Filename: `gh<issue-number>-<short-slug>.md` (e.g. `gh1292-moisture-phenology.md`).
- Audience: SUEWS core developers. These are internal working documents, not user-facing docs.
- Link upstream issues, papers, and community threads; do not paraphrase public threads verbatim.
- British English, plain ASCII where practical, consistent with `.claude/rules/00-project-essentials.md`.

Design notes that turn into shipped features should be referenced from the PR body and may later be retired or moved under `docs/` if they become user-relevant.
Loading
Loading