Coverage ratchet: changed code may not reduce tested coverage (closes #149) #210

Merged
conductor merged 30 commits from coverage-ratchet into master 2026-09-08 04:24:54 +01:00
30 Commits
Author SHA1 Message Date
Nick 99bf42293d merge master (resolve: master moved henxels to its own step — inline duplicate removed; coverage feature intact)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / lint (push) Successful in 33s
CI Pipeline / type-check (push) Successful in 26s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 46s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Successful in 29s
CI Pipeline / canary (pull_request) Successful in 26s
Spec gate (headless) / spec-gate (pull_request) Successful in 4s
CI Pipeline / type-check (pull_request) Successful in 24s
CI Pipeline / unit-tests (pull_request) Successful in 44s
CI Pipeline / gitea-offline (pull_request) Successful in 22s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / required-checks (pull_request) Successful in 2s
Auto-version and Release / release (pull_request) Failing after 15s
2026-09-08 04:23:12 +01:00
Nick 4fb9496afd fix: take master's tui_validator (declarative classification, #139) — branch carried a stale-era revert; superseded per regression doctrine (no backward reversion)
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / canary (push) Successful in 27s
CI Pipeline / lint (push) Successful in 31s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 45s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 30s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / canary (pull_request) Successful in 32s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / unit-tests (pull_request) Successful in 44s
CI Pipeline / required-checks (pull_request) Successful in 0s
Spec gate (headless) / spec-gate (pull_request) Successful in 9s
2026-09-08 04:13:10 +01:00
Nick 5abbf4d9b8 fix(ci): diff-cover flag order satisfies both #149 contracts; lint_ratchet.py + baseline travel from master (the missing bridge — master contracts meet branch feature)
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / lint (push) Successful in 33s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Failing after 46s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / canary (pull_request) Successful in 27s
CI Pipeline / type-check (pull_request) Successful in 26s
CI Pipeline / lint (pull_request) Successful in 29s
CI Pipeline / unit-tests (pull_request) Failing after 44s
Spec gate (headless) / spec-gate (pull_request) Successful in 8s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 04:06:57 +01:00
Nick 1783130421 fix(ci): diff-range-notation before compare-branch — both #149 contract assertions satisfied on one line
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 23s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Failing after 41s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / canary (pull_request) Successful in 28s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / unit-tests (pull_request) Failing after 39s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 03:58:50 +01:00
Nick 29c3e9ec4b fix(ci): unquote diff-range-notation — contract regex expects bare dots, not quoted string
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 23s
CI Pipeline / canary (push) Successful in 28s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Failing after 42s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / canary (pull_request) Successful in 28s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / unit-tests (pull_request) Failing after 39s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 03:53:05 +01:00
Nick 15666a081e ci: refresh head — statuses on the prior sha are stale (pre-restoration code); fresh sha triggers a clean CI verdict
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 25s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Failing after 43s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / canary (pull_request) Successful in 27s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / unit-tests (pull_request) Failing after 39s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 03:47:19 +01:00
Nick 47a26226f4 fix(ci): pin diff-cover --diff-range-notation '..' (#149 contract test demand)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 24s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Failing after 42s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / canary (pull_request) Successful in 26s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / unit-tests (pull_request) Failing after 40s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 01:45:57 +01:00
Nick 6c3d0b0edd resolve: feature content wins (this branch IS the coverage feature)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 22s
CI Pipeline / canary (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / type-check (push) Successful in 24s
CI Pipeline / unit-tests (push) Failing after 41s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / unit-tests (pull_request) Failing after 39s
CI Pipeline / canary (pull_request) Successful in 30s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / required-checks (pull_request) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
2026-09-08 01:42:18 +01:00
Nick 98a64a52b8 ci: graft master's dispatch condition + silent-handler ratchet onto coverage feature 2026-09-08 01:41:47 +01:00
Nick 0aee9dd386 merge master (coverage feature intact; master additions in other files) 2026-09-08 01:41:47 +01:00
Nick c4d2636a3c merge master (registry fix + robot self-heal travel)
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 21s
CI Pipeline / canary (pull_request) Successful in 24s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / unit-tests (pull_request) Failing after 34s
CI Pipeline / type-check (pull_request) Successful in 22s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / required-checks (pull_request) Skipped
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Failing after 21s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Failing after 35s
CI Pipeline / type-check (push) Successful in 22s
Spec gate (headless) / spec-gate (pull_request) Successful in 8s
CI Pipeline / required-checks (push) Skipped
2026-09-08 01:19:50 +01:00
Nick 75bf6c24b4 merge master (resolve: master's lock + ci evolution wins; branch content re-reviewed in PR)
CI Pipeline / best-practices (pull_request) Successful in 6s
CI Pipeline / lint (pull_request) Failing after 20s
CI Pipeline / canary (pull_request) Successful in 29s
CI Pipeline / unit-tests (pull_request) Failing after 34s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
CI Pipeline / lint (push) Failing after 22s
CI Pipeline / best-practices (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / unit-tests (push) Failing after 36s
CI Pipeline / canary (push) Successful in 24s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / type-check (push) Successful in 23s
Spec gate (headless) / spec-gate (pull_request) Successful in 9s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-08 00:58:21 +01:00
Nick 18d7f937a7 merge master (behind-base update, round 2)
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Successful in 28s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 43s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 28s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / unit-tests (pull_request) Successful in 42s
CI Pipeline / type-check (pull_request) Successful in 25s
CI Pipeline / required-checks (pull_request) Successful in 1s
2026-09-07 22:46:04 +01:00
Nick ebf9746225 merge master (behind-base update for robot drain)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Successful in 28s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / unit-tests (push) Successful in 44s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Successful in 28s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / unit-tests (pull_request) Successful in 41s
CI Pipeline / type-check (pull_request) Successful in 24s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 1s
2026-09-07 22:34:29 +01:00
Nick dc0c510736 Merge remote-tracking branch 'gitea/master' into coverage-ratchet
CI Pipeline / lint (pull_request) Successful in 27s
CI Pipeline / unit-tests (pull_request) Successful in 41s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 24s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 0s
auto-version.yml (push) Invalid workflow file
CI Pipeline / lint (push) Failing after 41s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Failing after 35s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Failing after 56s
CI Pipeline / type-check (push) Successful in 38s
CI Pipeline / required-checks (push) Skipped
2026-09-07 21:01:22 +01:00
Nick aef8f551a8 docs(ci): #149 plan tail — deviations, kill-test evidence, completion record
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (push) Successful in 28s
CI Pipeline / unit-tests (push) Successful in 38s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / type-check (push) Successful in 25s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Successful in 27s
CI Pipeline / unit-tests (pull_request) Successful in 39s
CI Pipeline / canary (pull_request) Successful in 24s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 24s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / required-checks (pull_request) Successful in 0s
2026-09-07 17:41:02 +01:00
Nick 3f358a3b46 docs(ci): coverage ratchet workflow (#149)
README gains a 'Coverage ratchet' section next to the #150 lock docs:
both floors (global 29, changed-lines 70), the raise-never-lower
doctrine, why the omitted canary files don't count, the merge-base
diff-range-notation choice, and the local reproduction commands.
2026-09-07 17:39:48 +01:00
Nick 61142944c1 style(ci): ruff format test_ci_lock_contract.py (#149) 2026-09-07 17:37:35 +01:00
Nick abc4a1c13e feat(ci): coverage ratchet in CI test job (#149)
RED-first (test_pr_context_diff_is_against_merge_base): the diff-cover
invocation now pins --diff-range-notation .. so the changed-lines diff
is against the merge base rather than the PR merge-ref tip — Gitea
Actions checks out the merge ref, and the default three-dot notation
would measure unrelated merge-commit lines. --compare-branch
origin/master is retained (fetch-depth: 0 guarantees the ref exists in
both push and PR contexts); the explicit range notation is the
supported mechanism diff-cover's CLI offers for pinning the range.
2026-09-07 16:53:39 +01:00
Nick 111b2bf2b5 feat(ci): coverage floors + diff-cover ratchet (#149)
Both floors measured and committed: global 29% (.coveragerc [report]
fail_under, canary_* scripts omitted — they are CI-run scripts, not
imported code) and changed-lines 70% (diff-cover --fail-under in the CI
test job). doctrine: raise, never lower.

coverage + diff-cover join [project.optional-dependencies] dev and the
pinned CI lock is regenerated (uv pip compile ... --extra dev --extra
memory --python-version 3.11): coverage==7.16.0, diff-cover==10.5.1 plus
transitives. scripts/check_dep_lock.py passes (drift ratchet green).

tests/test_ci_lock_contract.py (RED-first): asserts the committed floors,
lock pins, lock-only install, fetch-depth: 0 on the test checkout, and
the coverage run / report --fail-under / xml / diff-cover step chain.
2026-09-07 16:47:30 +01:00
Nick e9ebdb4b01 docs(ci): gate-review discharge record in plan completion record (#150)
Per-finding map: finding -> commit -> red evidence for all six gate
findings (F1-F6), final battery numbers, and the F3+F5 shared-commit
deviation note.
2026-09-07 16:07:45 +01:00
Nick 30a8ff8ee0 style(ci): ruff format check_dep_lock.py (#150)
Quote-style only (double -> single for the line containing \$PWD);
battery re-verified after format (15 checker tests pass).
2026-09-07 16:07:45 +01:00
Nick b58fc27780 fix(ci): type-check installs from the pinned lock, not floating extras (#150)
Gate-review F6 (pre-existing): the type-check job still installed
".[dev,memory]" — the one remaining floating install, leaving the
PROTECTED type-check toolchain unreproducible. Switched to the same
lock-only pattern as lint/unit-tests/canary: pip install -r
requirements-ci.txt + pip install -e . --no-deps. The lock pins
pyright==1.1.411, so the ratchet now runs against a pinned pyright.

RED->GREEN: config-only finding; red evidence was ci.yml:196 installing
floating extras (gate finding). yaml.safe_load parses after the edit;
no floating 'pip install .[...] ' remains in any workflow.
2026-09-07 16:07:45 +01:00
Nick 433c4247b9 docs(ci): disclose drift-checker limitations in module docstring (#150)
Gate-review F4: two known blind spots were undocumented — (1) marker-only
drift (env-marker changes with identical pins) is invisible to the pin
diff, (2) direct-URL requirement lines are skipped by the old parser /
now fail loudly instead of being compared. Both disclosed in the module
docstring with guidance; no behavior change.

RED->GREEN: docs-only finding; red evidence is the pre-existing docstring
lacking the disclosure (gate finding itself). Checker behavior and tests
unchanged (15 pass).
2026-09-07 16:07:45 +01:00
Nick 05d46dede4 fix(ci): actionable message when uv is missing; suppress compile stdout (#150)
Gate-review F3: with uv absent, run_uv_compile() let subprocess raise a
raw FileNotFoundError traceback. Now caught (sentinel -1) and main()
prints the house actionable pattern: what to install (pinned uv into
.ci-venv), what command (pip install + PATH export), local install doc.

Gate-review F5: uv's full resolution listing went to stdout even on
success, polluting CI logs. stdout/stderr are now captured and printed
only on compile failure.

RED->GREEN: new test (uv_binary stubbed to a missing binary, PATH
stripped) failed with FileNotFoundError, passes with exit 1 + actionable
stderr. Real smoke: successful run no longer prints uv's 'Resolved 37
packages' listing.
2026-09-07 16:07:45 +01:00
Nick 21d36c4550 fix(ci): lock checker fails loudly on non-pinned requirement lines (#150)
Gate-review F2: lock_requirements() silently skipped any requirement
line lacking '==', so a degraded floor-style lock (e.g. 'rune>=0.49.0')
would pass the drift diff with its floor pins intact. Options
(-r/--index-url/...) remain the only tolerated non-pin lines; any other
non-pinned form (floor, range, wildcard, bare name) now exits 1 with an
actionable message naming the offending line and the regen command.

RED->GREEN: two new tests (floor fixture + unpinned/wildcard variants)
failed against the skip behavior, pass after the loud-failure fix. The
pre-existing skip-options test was updated to match the tightened
contract; the committed lock (37 pins) still parses clean.
2026-09-07 16:07:45 +01:00
Nick e3cee0eee2 fix(ci): drift checker resolves the pinned uv, not a stray PATH uv (#150)
Gate-review F1: the drift-ratchet step installed uv==0.10.11 into
.ci-venv but never exported PATH, so check_dep_lock.py resolved
/usr/bin/uv (0.12.10) and re-compiled the lock with a different
resolver than generated it. Both ends fixed:

- ci.yml drift step: export PATH="$PWD/.ci-venv/bin:$PATH" before
  invoking the checker.
- check_dep_lock.uv_binary(): prefer the interpreter-adjacent uv
  (sys.executable's dir — where CI pins it) over shutil.which.

RED->GREEN: two new tests (PATH-stripped + decoy-uv-on-PATH) failed
against the old resolver order, pass after the fix.
2026-09-07 16:07:45 +01:00
Nick 4cf73f5dc4 docs(ci): dependency lock workflow (#150)
README Development section: how to regenerate requirements-ci.txt after
dependency edits (exact uv pip compile command), why --python-version 3.11
(runner-interpreter markers), and why CI installs the project with
--no-deps (deps only from the pinned lock). Regeneration command and
rationale also documented in the scripts/check_dep_lock.py header.
2026-09-07 16:07:45 +01:00
Nick 01085b1dff feat(ci): install from pinned lock + drift ratchet (#150)
All three CI venvs (.ci-venv, .test-venv, .canary-venv) now install deps
exclusively from the pinned requirements-ci.txt, then the project itself
with --no-deps — no floating escape hatch remains. The canary job's ad-hoc
'textual==8.2.8 textual-autocomplete==4.0.6 sqlite-vec || true' pre-install
is deleted: the lock pins exactly those versions. Lint job gains a
dependency-lock drift ratchet step (scripts/check_dep_lock.py) that fails
the job when the lock no longer matches pyproject.toml.
2026-09-07 16:07:45 +01:00
Nick b7269f878d feat(ci): pinned CI dependency lock (#150)
requirements-ci.txt: fully-pinned output of
'uv pip compile pyproject.toml -o requirements-ci.txt --extra dev --extra
memory --python-version 3.11' (plain pip format; runners need no uv).
scripts/check_dep_lock.py: drift ratchet — regenerates the compile into a
temp file, diffs requirement pins against the committed lock, exits 1 with
the regeneration command on drift. Unit-tested against fixture files.
2026-09-07 16:07:45 +01:00