Skip to content

v0.1.2

Choose a tag to compare

@aallan aallan released this 09 Jul 21:15
3177cbd

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.