Skip to content

Verification Gate scope is stale: 20 of 161 feature artifacts checked, per-PR override never used #358

Description

@avrabe

Summary

The Verification Gate's scope has been stale since ~v0.11.0. It re-runs the same
20 v0.9.3/v0.10.0-era artifacts on every PR and never executes the artifacts the
PR under review actually adds or changes. The per-PR escape hatch designed to fix
this has never once been used.

Consequence: for 141 of 161 type: feature artifacts, the V-model's right
side is not mechanically closed. An artifact can be committed as
status: passing / a requirement as status: verified without its declared
fields.steps[].run ever having been executed by CI.

Evidence

.github/workflows/verification-gate.yml:66 — the default filter:

DEFAULT='(and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))'

Measured against artifacts/*.yaml at c065e3d:

count
type: feature artifacts 161
matched by the default filter 20
never executed by the gate 141

The workflow intends each PR to narrow the scope to its own artifacts with a
Verify-Filter: body line (verification-gate.yml:52-72). Checking the last ten
merged PRs — #354, #353, #352, #351, #349, #348, #346, #344, #342, #340none
set it.
Every one ran against the stale 20.

The clearest illustration is #356, which removed TEST-LAYOUT-CERT and rewrote
three requirements. Its gate comment:

20/20 passed
Filter: (and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))

A green check that verified twenty unrelated artifacts and none of the PR's own.

Why the existing escape hatch cannot work

Verify-Filter: is read from github.event.pull_request.body, which is captured
in the event payload at trigger time. So:

  • adding the line after opening the PR has no effect on the run already fired;
  • re-running the workflow replays the original payload, so it does not pick up an
    edited body either;
  • it only takes effect on the next synchronize.

A gate scope that depends on prose typed into a description before opening the
PR, and that silently no-ops if forgotten, is not a gate. This is the same shape
as the required-check hole fixed in #353: the failure mode is silence that looks
like success
.

Proposed fix

Make the scope a function of the commit instead of the description.

  1. Add tools/changed_verification_artifacts.py: parse
    git show <merge-base>:artifacts/verification.yaml and the working copy, diff
    by artifact id (not by diff hunk, so a body-only edit is caught too), and
    print the ids of added-or-modified type: feature artifacts.
  2. Give tools/run_verification.py an --also-ids option and union it with the
    filter results. Deliberately not expressed as a rivet filter s-expression:
    CI pins rivet to v0.7.0 (b7a17bef) while local rivet is 0.28.0, so filter
    syntax cannot be validated locally against the version that will run it. An
    explicit id list is version-independent.
  3. Keep the current 20 as a floor rather than replacing them — strict improvement,
    no regression risk.
  4. Retain Verify-Filter: as a manual widener for cases where a code change
    should re-verify artifacts it does not textually touch.

Cost scales with the PR, not the repo, so the 60-minute budget is unaffected in
the common case.

Deliberately not proposed

Making Verification Gate (rivet-driven) a required context. It currently is
not one of the 16. Requiring it before the scope is correct would only enforce a
gate that checks the wrong 12%, and CI already runs 2h20m–2h33m end-to-end.
Worth revisiting once the scope is diff-derived and its real cost is observed.

Adjacent, smaller

  • verification-gate.yml:20 justifies the 60-minute timeout with "TEST-PROOF-
    steps run cd proofs && lake build … 25–35 min"*. d902bf2 (fix(verify-gate): keep TEST-PROOF-* on sorry-grep — lake build exceeds gate budget #230) replaced
    those steps with a file-exists + no-sorry smoke check precisely because
    lake build exceeded the budget. The comment is stale; the budget now rests on
    an obsolete rationale.
  • 19 of the 161 type: feature artifacts have no runnable steps and are reported
    [SKIP], which is not counted as failed. These are descriptive FEAT-* /
    ARCH-SYS records, so skipping is correct — noting it only because
    "skipped satisfies the check" is the exact pattern ci: skip heavy jobs on artifacts/docs-only diffs #353 had to close at the
    workflow level, and it is worth being deliberate that this instance is benign.

Not a defect (checked, and I was wrong first)

I initially read TEST-PROOF-LATENCY / TEST-PROOF-ARINC653 as verifying Lean
proofs by mere file existence. They have two steps; the second is a real
no-sorry grep, and lake build is delegated to the dedicated required
"Lean proof typecheck" workflow by the documented decision in #230. No action.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions