Skip to content

Lint rules for empirically-confirmed invariants: GPU declare scoping, fypp determinism, allocate pairing #1576

@sbryngelson

Description

@sbryngelson

Motivation

Three invariants were each violated on master and found the hard way during the 2026-06 series; all three are statically checkable in toolchain/mfc/lint_source.py (already CI-gated via precheck):

  1. GPU_DECLARE must live in the module that declares its variables. Violations compile fine on NVHPC and fail only on Cray ftn (ftn-1448) — i.e. the feedback loop runs through Frontier CI, weeks after the commit. This bit the executable-dedup work (fixed in Share the global-parameters core across executables; generate MPI broadcasts; build hygiene #1552) and the rule currently exists only as documentation.
  2. No fypp set-literal loops (#:for x in {...}). Python set iteration order is hash-randomized per process, so emitted code differs between builds — harmless for the constant-assignment sites converted in Phase-2 completion: post-process context types, m_riemann_solvers split, cleanup #1556, but it silently defeats build reproducibility and makes emitted-code diffing (a verification technique the series relied on heavily) noisy. The existing sites are fixed; nothing stops new ones.
  3. @:ALLOCATE / @:DEALLOCATE pairing per module. The project rule exists in CLAUDE.md/contributing; Gs_rs and Res_gs are @:ALLOCATE'd but never deallocated in the Riemann finalizer #1568 (Gs_rs/Res_gs, leaked since 2022) and Single-precision output arrays (q_sf_s family) are never deallocated in post_process #1569 (the single-precision q_sf_s triple, since 2023) show it is not enforced. A per-module name-set comparison (allocated minus deallocated, with an allowlist for intentional cases) would have flagged both years ago.

Proposal & execution sketch

Three independent rules in lint_source.py, each with the same shape: parse, check, report file:line with a named rule.

Effort: small (an afternoon each). Risk: minimal — lint-only. Impact: four recurring bug classes become unrecurrable at commit time instead of at Frontier-CI time or never.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions