Skip to content

feat: score the vPlan from test results as well as coverage - #243

Open
martin-velay wants to merge 5 commits into
lowRISC:masterfrom
martin-velay:testcase_dvplan
Open

feat: score the vPlan from test results as well as coverage#243
martin-velay wants to merge 5 commits into
lowRISC:masterfrom
martin-velay:testcase_dvplan

Conversation

@martin-velay

@martin-velay martin-velay commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Linked to https://github.com/lowRISC/dvplan/pull/117

What this does

The cov_vplan job already annotated a vPlan from the coverage database. It now also
annotates from the regression's test results, so a nightly says how much of the
verification plan is met and not only how much of the design was covered. A test the
plan asked for and the regression never ran shows as a hole rather than going missing.

dvsim writes those results to dv_evidence.json and passes it to dvplan alongside the
coverage report. It also passes through a path to hand-written inspection records if the
cfg names one.

Nothing runs unless the sim cfg sets vplan.

Three decisions worth reviewing

The evidence comes from a new scheduler callback, not from the end-of-run results.
Everything it records is already in run_results, but that only exists once the scheduler
has finished, and cov_vplan is a scheduled job that needs the file before then. The
alternative is to stop scheduling it and run it at gen_results time, which would drop
the callback, the collector and the FlowCfg hook. I kept it scheduled so the step keeps
its row in the status table and can fail like any other job.

needs_all_dependencies_passing became DependencyPolicy. The bool had two states
and this job needs a third. ALL_PASSING is the default and ANY_PASSING is what
CovMerge always did, so neither changes. CovVPlan takes ALWAYS, because a regression
where nothing passed is exactly the case the plan has to describe, and under either
existing policy it was killed instead of scored: with --cov it has one dependency, so
anything that stopped the coverage report also stopped the plan.

dvsim defines the evidence format, not dvplan. doc/dv_evidence.md specifies it and
the pydantic models are normative. dvsim is what produces the file and is the public repo,
so a consumer can be written against a spec rather than against whichever tool was built
first. dvplan is one consumer.

Dependencies and degradation

Needs the linked dvplan PR first: it defines the dv_evidence source name and the
multi-source behaviour. Whether dvplan is installed is decided by the job's own script on
the machine it runs on, so a checkout without it warns and passes.

The credential fix rides along

git_https_url_with_commit returns the origin remote verbatim today, so a CI checkout
with https://oauth2:<token>@host/org/repo already publishes the token in the JSON and
HTML reports. This PR adds another archived artefact carrying the same URL, so the fix is
first in the series. It reverts cleanly on its own.

Behaviour change

A cfg that sets vplan and runs without --cov previously got no vPlan job. It now gets
one, scored from test results alone.

Verified

ruff format --check and ruff check --config=ruff-ci.toml clean, pytest --strict 396
passed, license_check.py clean, pyright 182 errors unchanged, every commit tested
standalone. Run end to end against a real hmac regression in an OpenTitan tree.

CI checkouts leave the access token in the remote url, like
https://oauth2:<token>@host/org/repo. We record that url in the run metadata and print
it in the JSON and HTML reports, and those get archived, so the token leaks with them.

ssh urls keep their user. git@ is part of the address, so dropping it would give a url
that no longer reaches the remote. Passwords are stripped whatever the scheme.

AI-assisted (Claude Code) - reviewed and approved by author

Signed-off-by: martin-velay <mvelay@lowrisc.org>
The status-change callback carries no reason, so an observer cannot tell a failed job
from one the scheduler cancelled before dispatching it. The new callback gets the
reason and fires once the status is settled.

The existing callback is untouched, since its only consumer is the status printer and
that has no use for the reason. Flows opt in by overriding FlowCfg.on_job_completed,
which does nothing by default.

AI-assisted (Claude Code) - reviewed and approved by author

Signed-off-by: martin-velay <mvelay@lowrisc.org>
A cov_vplan job runs dvplan over the coverage report and a dv_evidence.json this flow
writes, so a nightly says how much of the verification plan is met and not just how
much of the design was covered. Nothing runs unless the sim cfg names a vplan.

The evidence comes from the scheduler's completion hook as each run finishes, so it
covers jobs cancelled before dispatch too. A test the plan asked for and the regression
never ran then shows up as a hole instead of going missing.

Both sources go to one dvplan invocation, because dvplan writes an item off as
unmeasurable when nothing it was given can measure it, and that sticks in the annotated
file. Runs without --cov score from the evidence alone.

Deploy gains a log_path property for the path it already built inline, which is what
the LSF launcher reaches for.

AI-assisted (Claude Code) - reviewed and approved by author

Signed-off-by: martin-velay <mvelay@lowrisc.org>
@martin-velay martin-velay changed the title feat: back-annotate a DVPlan vPlan from the regression's own results feat: score the vPlan from test results as well as coverage Aug 18, 2026
Review fixes for the vPlan back-annotation series.

The plan could not be scored in the regression it most needs to describe.
`needs_all_dependencies_passing` had two states and this job needs a third,
so it becomes `DependencyPolicy`. `ALL_PASSING` is the default and
`ANY_PASSING` is what CovMerge always did, so neither changes behaviour.
CovVPlan takes `ALWAYS` and runs once its dependencies are terminal,
whatever they concluded. Under either existing policy a regression where
nothing passed was killed rather than scored, and with --cov the job has a
single dependency, so anything that stopped the coverage report also
stopped the plan.

dvsim now defines the evidence format rather than deferring to dvplan.
doc/dv_evidence.md specifies it and the pydantic models are normative.
dvsim produces the file and is the public repo, so a consumer can be
written against a spec rather than against whichever tool was built first.

Whether dvplan is installed is decided by the job's own script, so it reads
the PATH of the machine the job lands on rather than that of the host dvsim
was launched from, which on a compute farm need not be the same.

A `dvplan_inspect` pattern matching nothing is now a config error. The
command is built while the jobs are, so it stops the run in seconds rather
than failing inside dvplan once the regression has already gone.

The vPlan report page is linked only once it exists, since a killed job or
a machine without dvplan otherwise left a dead link in the HTML report.

AI-assisted (Claude Code) — reviewed and approved by author

Signed-off-by: martin-velay <mvelay@lowrisc.org>
The page claimed the pydantic models were the normative definition of the
whole format. They are not: they forbid the inspection key, so they reject
a file DVPlan accepts. That is correct for a writer, but it makes the
claim wrong.

AI-assisted (Claude Code) — reviewed and approved by author

Signed-off-by: martin-velay <mvelay@lowrisc.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant