You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
A scheduled CI workflow now checks the limitation tables against live issue states (#852). check_limitations_sync.py --check-states runs Mondays 07:00 UTC and on demand: every issue a KNOWN_ISSUES.md, vera/README.md, spec, SKILL.md, or LSP_SERVER.md limitation row cites is queried against the tracker, and a closed issue still listed as a limitation fails the run — the drift class the v0.1.1 sweep caught by hand is now caught on a schedule. Deliberately a visibility signal on the Actions tab rather than a required merge check, since issue state drifts independently of any particular PR. External contribution by @chethanuk.
Linux aarch64 gains an advisory CI lane (#702). The test matrix gains an ubuntu-24.04-arm cell (Python 3.12 — platform coverage, not version coverage), and the wheel-availability gate now checks manylinux_2_38_aarch64 wheels for all three Python versions; README §Supported platforms lists the tested cell, with Python 3.11/3.13 on aarch64 remaining wheel-checked only. The new cell is advisory for now — it runs on every commit but is deliberately not in the required merge checks until the arm runners prove reliable. External contribution by @chethanuk.
Changed
Two CI workarounds are retired — their removal triggers fired (#537). Pygments 2.20.0 (March 2026) shipped the CVE-2026-4539 fix, so the --ignore-vuln flag is gone from the dependency audit (left in place it would have masked a real regression); and the actions/setup-python toolcache now carries pip 26.1.2 natively, so the pre-audit pip install --upgrade pip (CVE-2026-3219) is gone too. Both KNOWN_ISSUES CI-workarounds rows retire with them, per the table's bridges-not-permanent-exceptions contract.
Fixed
An invalid string escape no longer crashes vera check with a raw Python traceback (#966). The E009 TransformError is raised inside a Lark token callback, which lark wraps in VisitError — so the CLI's except VeraError never fired and a user typo like "bad \q escape" produced exit 1 with zero bytes of JSON and a traceback on stderr, contradicting spec §0.5 and §0.5.8. transform() now unwraps a VisitError carrying a VeraError and re-raises the original, so both text and --json modes emit the proper diagnostic envelope. The E009 diagnostics themselves are upgraded from description-only to the full instruction format — rationale, fix, and spec_ref for both the invalid-escape and malformed-interpolation classes — retiring a # diag-fields-exempt waiver whose "the grammar prevents this" premise was false (spec §1.6 defines invalid escapes as a user-facing error). Found by the v0.1.2 pre-release sweep.
The pre-release sweep corrected the drift the gates don't reach. TESTING.md's contract-verification block was three campaigns stale (claimed 256 of 280 obligations, 91.4% static; live is 283 of 378, 74.9% — the denominator grew with the soundness campaign's auto-synthesised primitive-op obligations, and the per-example Tier-3 table is regenerated from live vera verify --json, which also surfaced the #967 summary off-by-one, now a tracked Stage 19 limitation); the README/FAQ test counts catch up to 6,846; HISTORY's v0.1.0 by-the-numbers column is restored to its true snapshot (6,779 — a v0.1.1-cycle edit had bumped it to the then-current count) with the growth-chart figure regenerated in lockstep; the spec-block counts correct to 189; §0.5.1 acknowledges the W001/W002 warning codes; TESTING.md documents the scheduled limitations-sync workflow and scopes the # diag-fields-exempt gate rows to the #955 semantics; and three test-code comments citing since-fixed issues (#918, #706, #635) are retired.
check_diagnostic_fields.py's # diag-fields-exempt opt-out is now honoured wherever an unresolvable field can arise (#955). The field-presence pass (check_source) appended its non-literal-severity violation and continued before its own opt-out lookup ran, so a marker on that exact call was never consulted even in the one pass that otherwise honours it; the spec_ref-validity pass never consulted the opt-out at all. Fixed for the unresolvable (non-literal) sub-case only: a non-literal severity or spec_ref can't be checked statically and so is opt-out-able, same as a missing field — with the marker found anywhere across a multi-line call's span, not just the argument's own line. A spec_ref that resolves but cites the wrong/nonexistent section, or an error_code not in ERROR_CODES, is a content error, not a tagging gap — the opt-out never suppresses either, marker or not; and the error_code pass skips non-literal codes entirely, so it has nothing to waive. On vera/ the exempt set is unaffected (the three existing real markers are all missing-field cases). main()'s remedy text now states this precisely instead of implying the opt-out waives everything it lists. External contribution by @chethanuk.
The diagnostic-fields gate's plumbing-skip now also confirms the sole own-scope Diagnostic is reachable as the helper's result (#956). The #827 narrowing (v0.1.1) requires a genuine helper method whose sole own-scope construction is ambiguity-free, but never checked that the construction was actually used as the helper's output — a helper that builds its one Diagnostic and hands it to something other than a return / .append(...) (e.g. self.dispatch(d)) still had that ctor elected as plumbing and skipped by all three passes, so a bogus spec_ref or unregistered error_code on it would ship silently. A new _ctor_is_reachable_as_result predicate now requires the ctor be return-ed, appended, or bound to a local later return-ed/appended, gated after the existing len(ctors) == 1 check so the #827 ambiguity handling is untouched. The name-based return/append match has no real data-flow, so a local rebound after the ctor-binding assign — plain reassignment (d = Diagnostic(...); d = something_else; return d), a for/with loop target, a walrus, an augmented assignment, or an except ... as name — would otherwise still match on the name and be wrongly treated as reachable — fixed by counting binding sites generically rather than by enumerating statement forms (every Store-context name — assignment or unpack of any shape, for/with targets, walrus — plus import ... as, except ... as, match captures, the helper's own parameters, and nonlocal declarations in nested functions; a bare annotation carries no assignment and is not counted): a name bound more than once anywhere in own scope is treated as unreliable rather than reachable, and the return/append name-match only counts at-or-after the binding line. Separately, _is_append_call treated ANY .append(...) call as evidence of reachability, including an append to an unrelated throwaway local (tmp = []; tmp.append(d)) that the helper never reads again — every real diagnostic-list sink in vera/ has the self.<attr>.append(...) shape, so the check is now scoped to that. On vera/ the exempt set is unchanged (all five real helpers return or append their sole ctor directly), so nothing new is flagged in the live tree — the gap was latent, closed defensively. External contribution by @chethanuk.