Skip to content

release: drift probes, HPC container path, and README deduplication - #325

Merged
enriquea merged 4 commits into
mainfrom
dev
Sep 1, 2026
Merged

enriquea merged 4 commits into
mainfrom
dev

Conversation

@enriquea

@enriquea enriquea commented Sep 1, 2026

Copy link
Copy Markdown
Member

Promotes dev to main. Four commits, all green on dev:

PR Change
#319 Real drift probes for gevir and insider, with review fixes
#320 Real drift probes for the five remaining documentation-only plugins
#323 HPC container build path fix so it works on a cluster
#324 Fold the README's duplicated sections into the docs site

Bulk of the diff is the drift-probe work: insider/shared/http_probe.py, per-dataset probes and fingerprints, plus new guards (test_committed_drift_baselines.py, test_probe_normalize_etag.py, test_run_builder_probe_degradation.py).

main runs a wider matrix than dev — it adds Python application and Deploy docs on top of the 3.10/3.11/3.12 build, the two Hail jobs, build-linux and the smoke test. That wider set is the point of the gate, so nothing here is merged until it is green.

Note the docs change in #324 retargets two doc-guard tests from README.md to docs_site/, since the README copies they parsed are gone. Both were verified green locally and on the #324 PR run.

Replaces stub sentinels with real drift probes for gevir:metrics, insider:variants and insider:interfaces, and closes the defects an adversarial review found in them.

Issue #177 had recorded both sources as unprobeable. Re-checking showed GeVIR is served as the article's MOESM3 object on Springer's CDN (Content-Length + an MD5 ETag), and that INSIDER's two products are at stable direct paths despite a link-free download page.

Review fixes folded in:
- run_builder no longer aborts a build when a probe cannot reach its source; provenance records a self-describing PROBE_UNAVAILABLE_TOKEN so offline builds keep working on manual-acquisition plugins.
- normalize_etag added to core: str.strip('"') mangles weak and transform-suffixed validators.
- Signals moved under headers so drift is not auto-batched as routine; checksums left empty per _conventions §12.
- INSIDER split into two probes with two baselines: the products are independently versioned, and a shared baseline meant the bot could only ledger the anchor dataset while a fault on one file masked drift in the other.
- ETag compared rather than demoted for INSIDER, since it is hex(size)-hex(mtime) and catches equal-size edits Content-Length cannot.
- Docs corrected: the gevirank repo ships analysis code, not data.

Datasets with a live drift comparator: 18 -> 21 of 26.

Refs #177
…gins (#320)

Completes the sweep #319 began; together they close #177.

Replaces the last five stub sentinels (dbnsfp, gnomad_metrics, cosmic_cgc, pqtl, alphagenome) with real probes, and closes the defects an adversarial review found in them.

gnomad_metrics HEADs the public GCS constraint objects (MD5 ETag + Content-Length + x-goog-generation). The other four watch a release stream, because their data is gated or gone: dbNSFP's advertised S3 archives all 404 (NoSuchBucket, tracked as #321), COSMIC's census is login-gated, pqtl ships as preprint supplementary material, and alphagenome is a credentialed service. Each probe documents what it cannot see.

Review fixes folded in:
- dbNSFP's pattern missed every v-prefixed archive, so the entire 2.x/3.x generation was invisible (30 releases recorded, 59 actual) and a dbNSFPv5.0a.zip release would have reported clean.
- COSMIC matched prose and picked up Actionability-product versions; it now reads the page's id=v<N> release anchors.
- Signals moved under headers with checksums empty, per _conventions §12; the redundant sha256 dropped.
- gnomad_metrics: normalize_etag, both validators required, non-identity Content-Encoding refused, timeout sized against the runner's 60s SIGALRM, failures collected across objects rather than aborting before v4.0 is probed.
- pqtl selects by version rather than list position and fails closed on a missing version; alphagenome no longer hard-requires PyPI's deprecated releases key.
- All five use request_with_retry; both HTML scrapes decode explicitly; COSMIC rejects a redirected response.
- All five SKILL.md files updated - they still described the deleted stubs.
- New suite validates every committed baseline at rest (placeholder_baseline_reason, a real fetched_at, a non-empty compared surface).

Committed fingerprints 21 -> 26 of 26; live comparators 18 -> 26 of 26. No stub sentinels remain.

Refs #177, #321
…ster (#323)

* docs(hpc): fix the container build path so it actually works on a cluster

The Apptainer/Singularity section of the HPC migration guide documented a build
that cannot succeed. Four independent blockers, each verified on the cluster:

* Base image had no Java 11. The guide pinned `python:3.10-slim-bookworm`, but
  Debian 12 ships no `openjdk-11` package at all -- apt reports it is replaced by
  `openjdk-17-jre-headless`, and Hail 0.2.x / Spark 3.5 support Java 8 or 11 only.
  Repinned to `python:3.10-slim-bullseye` (openjdk 11.0.32.1).
* `--fakeroot` is not universally available. It needs an `/etc/subuid` entry; with
  none, the build fails with `no valid mapping entry found` and an unprivileged
  build is refused outright. Documented the check and the static `proot` fallback
  that SingularityCE accepts instead.
* Extras omitted `expression`, producing an image with no scanpy in which
  `hvantk expression ...` cannot run. Checked the full list against
  [project.optional-dependencies]; `ml` and `interactive` are genuinely redundant.
* The container cannot initialise Hail without `SPARK_LOCAL_DIRS` on writable
  node-local scratch, and the failure is misdiagnosed: the visible error is
  `[Errno 111] Connection refused` from py4j, which reads as a network fault. The
  real cause is one line above it, `DiskBlockManager: Failed to create any local dir`.

The definition file now lives at `containers/hvantk.def` rather than as a prose
snippet, so the base image and extras cannot drift from what was last built, and
`containers/hvantk_run.sh` sets up and binds Spark scratch so the container is
invoked correctly by default.

Verified end to end: image builds (2.2 GB) and
`hvantk utils check-install` passes on a compute node -- Hail 0.2.137 initialises
and the balding_nichols_model smoke test succeeds.

* docs(hpc): do not link to containers/hvantk.def from the guide

mkdocs --strict rejects a link whose target is not a documentation file:

  WARNING - Doc file 'guide/hpc-migration.md' contains a link
  '../../containers/hvantk.def', but the target '../containers/hvantk.def'
  is not found among documentation files.

Reference the path as a code span, matching how the rest of the guide names
repo paths. Verified with the same command CI runs:
mkdocs build --strict now exits 0.
* docs: fold the README's duplicated sections into the docs site

Project structure, Optional extras, and the plugin contract each existed twice:
once in README.md and once in docs_site/, where the copy was already a strict
superset. The README is 272 -> 174 lines, and each section keeps a short
orienting summary plus a link to the canonical page.

Nothing is lost. installation.md already carried all twelve extras plus the
scanpy/Intel-macOS caveat the README omitted, and architecture.md already
carried a richer tree, the build sequence diagram, an annotated plugin.yaml,
the two-pass loader and the streamer placement rule. The one thing only the
README had -- a real builder rather than a synthetic my_source one -- is added
to architecture.md, along with a note that build_clinvar is a sanctioned name:
_conventions/SKILL.md cites it explicitly, and the rule is "whatever
plugin.yaml's builder.function declares", so both the short and the
per-dataset form are correct.

Two guards asserted on the README copies and are retargeted:

- test_pyproject_extras.py parsed the README extras table; it now guards only
  installation.md. Its docstring complained the table was "duplicated in THREE
  places ... and only the first is executable" -- that is now two.
- test_docs_claims.py parsed the README tree in both the tree test and its
  "guard the guard" test; both now read architecture.md. Its docstring
  described architecture.md accumulating seven dead paths "while the parallel
  tree in README.md was corrected by hand" -- with one tree left, that
  divergence cannot recur.

Verified: mkdocs build --strict passes, and all six README -> docs_site anchors
resolve under GitHub's slug rules (each space becomes its own hyphen, so the
em-dash heading is #3-plugin-contract--adding-a-data-source).

The plugin-contract prose was checked against the code before being condensed:
build_clinvar, its schema_id, AnnotationTable.from_hail's keyword-only
provenance, run_builder_for_spec's artifact_type/schema_id validation, the
sidecar .provenance.json, and the count and names of the 21 plugins are all
accurate as written.

* docs: the manifest downloader is optional, not mandatory

The condensed plugin contract said a plugin.yaml names "its builder, drift
probe, and downloader", which overstates the contract. Verified against the
tree: builder and drift_probe appear in 21/21 manifests, but lifecycle.download
appears in only 12 -- alphagenome, cosmic-cgc, dbnsfp, gevir, gtex-eqtl,
gwas-catalog, insider, msigdb and pqtl ship none, and api.py documents
DownloadFn as an "Optional download stage".

That is by design, not an omission: CLAUDE.md's downloader strategy routes
sources behind a license gate or over ~1 GB to a documented acquisition
procedure instead. A contributor reading the old sentence would think a
downloader was required and write an unnecessary one.

No count is quoted in the prose -- nothing guards it, and the point holds
without one.

Caught by Qodo on #324.

* docs: split the garden-path sentence about optional downloaders

"the ones behind a license gate or too large to mirror ship a documented
acquisition procedure instead" reads as "mirror ship" before the subject
resolves. Two sentences, same meaning.

Caught by Copilot on #324.
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 73cb64cf-0f34-4fb6-8e9e-288fb04c5b1f


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 66 high · 34 minor

Alerts:
⚠ 100 issues (≤ 0 issues of at least minor severity)

Results:
100 new issues

Category Results
Documentation 34 minor
Security 66 high

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add live drift probes and a reproducible HPC container path

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Replaces drift stubs with live fingerprints and preserves offline builds during probe outages.
• Adds a reproducible Singularity container and node-local Spark scratch wrapper.
• Consolidates README guidance into maintained docs and strengthens regression coverage.
Diagram

graph TD
  S["Upstream sources"] --> P["Dataset probes"] --> N["ETag normalization"] --> F["Drift fingerprints"]
  P -->|unreachable| R["Builder fallback"] --> B["Artifact build"] --> V["Provenance sidecar"]
  F --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Declarative HTTP probe manifests
  • ➕ Could remove repeated HEAD validation and fingerprint-shaping code.
  • ➕ Would centralize timeout, encoding, and validator policies.
  • ➖ Cannot naturally model PyPI, medRxiv, or HTML release projections.
  • ➖ Source-specific failure rules would make the manifest language complex.
2. Download and hash complete artifacts
  • ➕ Provides the strongest byte-level drift signal.
  • ➕ Avoids relying on server validator semantics.
  • ➖ Would transfer very large files during routine checks.
  • ➖ Cannot access licensed, credentialed, or unavailable artifacts.
  • ➖ Conflicts with lightweight nightly drift checks.

Recommendation: Keep the PR’s hybrid strategy: source-specific projections for heterogeneous APIs and release pages, with shared helpers where transport semantics truly match. A reusable core HEAD helper could later consolidate GeVIR, gnomAD, and INSIDER validation, but full declarative probes or body downloads would either lose source-specific correctness or impose excessive network cost.

Files changed (47) +2593 / -367

Enhancement (10) +837 / -89
api.pyAdd unavailable-probe provenance and safe ETag normalization +41/-0

Add unavailable-probe provenance and safe ETag normalization

• Defines a self-describing token for source reachability failures. Adds normalization for strong, weak, empty, and transform-suffixed ETags.

hvantk/core/plugin/api.py

drift_probe.pyProbe AlphaGenome releases through PyPI +75/-12

Probe AlphaGenome releases through PyPI

• Replaces the stub with a PyPI JSON probe comparing the current SDK version. Release history remains informational, and malformed or incomplete responses fail closed.

hvantk/skills/alphagenome/drift_probe.py

drift_probe.pyProbe public COSMIC release anchors +80/-12

Probe public COSMIC release anchors

• Replaces the stub by extracting numbered release anchors from public release notes. Redirects and missing anchors fail closed to avoid fingerprinting login pages or prose.

hvantk/skills/cosmic_cgc/drift_probe.py

drift_probe.pyProbe advertised dbNSFP releases +113/-12

Probe advertised dbNSFP releases

• Replaces the stub with a stable projection of archive names from the landing page. It identifies the newest academic release componentwise and rejects empty or incompatible release sets.

hvantk/skills/dbnsfp/drift_probe.py

drift_probe.pyProbe the GeVIR supplementary workbook +102/-11

Probe the GeVIR supplementary workbook

• Replaces the stub with an identity-encoded HEAD probe comparing Content-Length and normalized ETag. Missing validators or compressed responses fail closed, while Last-Modified remains informational.

hvantk/skills/gevir/drift_probe.py

drift_probe.pyProbe all declared gnomAD constraint tables +148/-12

Probe all declared gnomAD constraint tables

• Replaces the stub with session-reused HEAD requests comparing ETag, Content-Length, and GCS generation. It evaluates every object, aggregates failures, and rejects degraded or compressed responses.

hvantk/skills/gnomad_metrics/drift_probe.py

drift_probe.pyProbe the INSIDER genomic BED directly +29/-18

Probe the INSIDER genomic BED directly

• Replaces the shared stub with a dataset-specific HEAD fingerprint for the genomic BED using common INSIDER transport mechanics.

hvantk/skills/insider/drift_probe.py

drift_probe.pyAdd an independent INSIDER interfaces probe +34/-0

Add an independent INSIDER interfaces probe

• Adds a dedicated HEAD probe for the protein-pair interfaces table so its drift and provenance are isolated from the genomic BED.

hvantk/skills/insider/interfaces/drift_probe.py

http_probe.pyShare robust INSIDER HEAD fingerprint mechanics +106/-0

Share robust INSIDER HEAD fingerprint mechanics

• Adds identity-encoded HEAD handling, ETag normalization, complete-validator checks, compression rejection, and standardized fingerprint shaping for both products.

hvantk/skills/insider/shared/http_probe.py

drift_probe.pyProbe pQTL preprint version metadata +109/-12

Probe pQTL preprint version metadata

• Replaces the stub with a medRxiv JSON probe comparing version, date, and publication status. It selects the latest numeric version independently of response ordering and fails closed on malformed data.

hvantk/skills/pqtl/drift_probe.py

Bug fix (1) +35 / -3
run_builder.pyAllow builds to continue when drift sources are unreachable +35/-3

Allow builds to continue when drift sources are unreachable

• Catches DriftProbeError during provenance collection, logs a warning, and stamps the unavailable-probe token. Probe contract violations and other errors remain fatal.

hvantk/core/plugin/run_builder.py

Tests (13) +1156 / -42
test_drift_probe.pyTest AlphaGenome release probing offline +76/-0

Test AlphaGenome release probing offline

• Covers fingerprint shape, release changes, missing versions, deprecated response fields, and malformed JSON using mocked requests.

hvantk/skills/alphagenome/tests/test_drift_probe.py

test_drift_probe.pyTest COSMIC release extraction and redirect safety +107/-0

Test COSMIC release extraction and redirect safety

• Verifies numeric ordering, new-release detection, exclusion of unrelated prose versions, and rejection of login redirects or missing anchors.

hvantk/skills/cosmic_cgc/tests/test_drift_probe.py

test_drift_probe.pyTest dbNSFP release projection stability +113/-0

Test dbNSFP release projection stability

• Covers legacy names, academic-version selection, numeric ordering, case folding, markup independence, release changes, and fail-closed behavior.

hvantk/skills/dbnsfp/tests/test_drift_probe.py

test_drift_probe.pyTest GeVIR validator fingerprinting offline +130/-0

Test GeVIR validator fingerprinting offline

• Covers signal placement, timestamp demotion, weak ETags, missing validators, identity encoding, and compressed-response rejection.

hvantk/skills/gevir/tests/test_drift_probe.py

test_drift_probe.pyTest multi-object gnomAD probing offline +137/-0

Test multi-object gnomAD probing offline

• Verifies per-object attribution, generation changes, complete validator requirements, identity encoding, and aggregated failure reporting.

hvantk/skills/gnomad_metrics/tests/test_drift_probe.py

test_drift_probe.pyTest independent INSIDER product probes +165/-13

Test independent INSIDER product probes

• Verifies dataset isolation, outage independence, equal-size change detection, signal classification, complete validators, and identity encoding.

hvantk/skills/insider/tests/test_drift_probe.py

test_drift_probe.pyTest pQTL publication probing offline +127/-0

Test pQTL publication probing offline

• Covers journal publication, editorial exclusions, response ordering, version normalization, missing records, and malformed version fields.

hvantk/skills/pqtl/tests/test_drift_probe.py

test_committed_drift_baselines.pyValidate every committed drift baseline +100/-0

Validate every committed drift baseline

• Discovers manifest-declared baselines and checks JSON shape, placeholder rejection, live timestamps, and non-empty comparable signals without network access.

hvantk/tests/test_committed_drift_baselines.py

test_docs_claims.pyRetarget project-tree guards to canonical architecture docs +5/-3

Retarget project-tree guards to canonical architecture docs

• Stops parsing the removed README tree and validates the sole project-structure copy in docs_site/architecture.md.

hvantk/tests/test_docs_claims.py

test_plugin_contract_artifacts.pyMark newly completed drift baselines +20/-13

Mark newly completed drift baselines

• Removes drift-fingerprint gaps for AlphaGenome, COSMIC, dbNSFP, gnomAD, and pQTL while retaining their genuine fixture or snapshot gaps.

hvantk/tests/test_plugin_contract_artifacts.py

test_probe_normalize_etag.pyGuard ETag normalization behavior +42/-0

Guard ETag normalization behavior

• Tests strong, weak, lowercase, suffixed, unquoted, whitespace, missing, and empty ETags. It explicitly captures the former strip-based corruption.

hvantk/tests/test_probe_normalize_etag.py

test_pyproject_extras.pyGuard only the canonical optional-extras table +17/-13

Guard only the canonical optional-extras table

• Removes README from duplicated dependency-table checks after its table was replaced by a documentation link.

hvantk/tests/test_pyproject_extras.py

test_run_builder_probe_degradation.pyTest graceful builder behavior during probe outages +117/-0

Test graceful builder behavior during probe outages

• Verifies DriftProbeError does not abort builds, provenance receives the unavailable token, healthy probes remain unchanged, and contract violations still raise.

hvantk/tests/test_run_builder_probe_degradation.py

Documentation (11) +264 / -222
README.mdReplace duplicated reference sections with canonical documentation links +25/-121

Replace duplicated reference sections with canonical documentation links

• Condenses optional-extras and plugin-architecture guidance in the README. Detailed tables, diagrams, and package structure now live only in the docs site to prevent divergence.

README.md

architecture.mdClarify builder naming and manifest binding +7/-0

Clarify builder naming and manifest binding

• Adds a concrete ClinVar example explaining how plugin manifests bind dataset builders and schema identifiers.

docs_site/architecture.md

data-sources.mdCorrect INSIDER and GeVIR acquisition guidance +32/-8

Correct INSIDER and GeVIR acquisition guidance

• Documents both INSIDER products and their stable direct URLs. Corrects GeVIR’s source to the Springer supplementary workbook and explains its required conversion.

docs_site/guide/data-sources.md

hpc-migration.mdDocument the validated cluster container workflow +80/-72

Document the validated cluster container workflow

• Replaces the copied definition snippet with the committed container path and explains Bullseye, Java 11, extras, proot builds, and node-local Spark scratch. Adds troubleshooting guidance for common cluster failures.

docs_site/guide/hpc-migration.md

SKILL.mdDocument AlphaGenome SDK release drift coverage +11/-5

Document AlphaGenome SDK release drift coverage

• Explains that the probe tracks public SDK releases and cannot detect unannounced server-side model updates. Records the newly populated live baseline.

hvantk/skills/alphagenome/SKILL.md

SKILL.mdDocument COSMIC release-note drift detection +17/-0

Document COSMIC release-note drift detection

• Explains release-anchor extraction, login redirect handling, and the limits imposed by licensed Census data.

hvantk/skills/cosmic_cgc/SKILL.md

SKILL.mdDocument dbNSFP release-list probing and broken downloads +15/-1

Document dbNSFP release-list probing and broken downloads

• Describes the landing-page release signal, its detection limits, and the currently broken upstream archive routes.

hvantk/skills/dbnsfp/SKILL.md

SKILL.mdDocument GeVIR’s real supplementary-data source +26/-9

Document GeVIR’s real supplementary-data source

• Corrects the upstream location and explains that drift watches the Springer workbook while builds consume a derived BGZF table. Documents HEAD-based validator coverage.

hvantk/skills/gevir/SKILL.md

SKILL.mdDocument complete gnomAD object probing +5/-2

Document complete gnomAD object probing

• Explains that every declared constraint table is checked using GCS content validators without transferring object bodies.

hvantk/skills/gnomad_metrics/SKILL.md

SKILL.mdDocument independent INSIDER product fingerprints +36/-1

Document independent INSIDER product fingerprints

• Describes direct product paths, separate per-dataset baselines, validator semantics, risk classification, compression handling, and cleartext transport limitations.

hvantk/skills/insider/SKILL.md

SKILL.mdDocument pQTL publication-version drift coverage +10/-3

Document pQTL publication-version drift coverage

• Explains medRxiv metadata probing, its publication transition signal, and the inability to detect unchanged-version supplement replacement.

hvantk/skills/pqtl/SKILL.md

Other (12) +301 / -11
hvantk.defAdd a locked Singularity container definition +58/-0

Add a locked Singularity container definition

• Introduces a Bullseye-based Python 3.10 image with Java 11, locked Poetry dependencies, toolkit extras, and build-time Hail validation. The image exposes hvantk as its runscript.

containers/hvantk.def

hvantk_run.shAdd an HPC-safe container execution wrapper +30/-0

Add an HPC-safe container execution wrapper

• Runs the Singularity image with writable node-local Spark scratch and optional data bindings. It exports Spark, Hail, and temporary-directory variables and cleans scratch on exit.

containers/hvantk_run.sh

drift_fingerprint.jsonCommit the AlphaGenome live drift baseline +28/-0

Commit the AlphaGenome live drift baseline

• Records the current AlphaGenome SDK version and observed release history from a live PyPI probe.

hvantk/skills/alphagenome/tests/drift_fingerprint.json

drift_fingerprint.jsonCommit the COSMIC release-index baseline +14/-0

Commit the COSMIC release-index baseline

• Records the currently published COSMIC release anchors and latest release version.

hvantk/skills/cosmic_cgc/tests/drift_fingerprint.json

drift_fingerprint.jsonCommit the dbNSFP release baseline +69/-0

Commit the dbNSFP release baseline

• Records the advertised dbNSFP release set and latest academic version from a live probe.

hvantk/skills/dbnsfp/tests/drift_fingerprint.json

drift_fingerprint.jsonReplace the GeVIR stub baseline +13/-3

Replace the GeVIR stub baseline

• Records live Content-Length, ETag, and informational modification time for the Springer workbook.

hvantk/skills/gevir/tests/drift_fingerprint.json

drift_fingerprint.jsonCommit gnomAD constraint-object baselines +28/-0

Commit gnomAD constraint-object baselines

• Records live validators for both v2.1.1 tables and the v4.0 constraint table.

hvantk/skills/gnomad_metrics/tests/drift_fingerprint.json

datasets.jsonCorrect INSIDER catalog files and direct URLs +10/-3

Correct INSIDER catalog files and direct URLs

• Updates the BED size and direct path, adds the interfaces table, and refreshes catalog metadata.

hvantk/skills/insider/catalog/datasets.json

drift_fingerprint.jsonCommit the INSIDER interfaces baseline +17/-0

Commit the INSIDER interfaces baseline

• Records live Content-Length, ETag, and informational modification time for the interfaces table.

hvantk/skills/insider/interfaces/tests/drift_fingerprint.json

plugin.yamlBind interfaces to its dedicated drift probe +2/-2

Bind interfaces to its dedicated drift probe

• Points insider:interfaces at its own probe module and dataset-specific committed baseline.

hvantk/skills/insider/plugin.yaml

drift_fingerprint.jsonReplace the INSIDER BED stub baseline +15/-3

Replace the INSIDER BED stub baseline

• Records live Content-Length, ETag, and informational modification time for the genomic BED.

hvantk/skills/insider/tests/drift_fingerprint.json

drift_fingerprint.jsonCommit the pQTL publication baseline +17/-0

Commit the pQTL publication baseline

• Records the current preprint version, posting date, publication status, and informational title.

hvantk/skills/pqtl/tests/drift_fingerprint.json

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Scheduler scratch can be deleted 🐞 Bug ☼ Reliability
Description
When SLURM_TMPDIR is set, the wrapper assigns the scheduler-owned directory itself to
SPARK_SCRATCH and recursively deletes it from the EXIT trap. Any failure after the trap is
installed, including a missing singularity executable, can erase unrelated files stored in the
job's shared scratch directory.
Code

containers/hvantk_run.sh[R17-20]

+SPARK_SCRATCH="${SLURM_TMPDIR:-/tmp/spark-$USER-${SLURM_JOB_ID:-$$}}"
+mkdir -p "$SPARK_SCRATCH"
+cleanup(){ rm -rf "$SPARK_SCRATCH"; }
+trap cleanup EXIT
Evidence
The wrapper selects SLURM_TMPDIR directly and installs an unconditional rm -rf trap for that
path. The same wrapper can subsequently fail at its hardcoded runtime invocation, causing the trap
to execute against the scheduler directory.

containers/hvantk_run.sh[16-26]
docs_site/guide/hpc-migration.md[107-108]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The wrapper may recursively delete the complete scheduler-provided `SLURM_TMPDIR`, including files it did not create.

## Issue Context
`SLURM_TMPDIR` should be treated as a parent directory. Create a uniquely named child owned by this invocation, bind that child, and remove only that child. Account for the fact that a successful `exec` replaces the shell and does not execute its EXIT trap.

## Fix Focus Areas
- containers/hvantk_run.sh[16-30]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Apptainer-only clusters cannot run 🐞 Bug ≡ Correctness
Description
The wrapper advertises Apptainer/Singularity support but unconditionally invokes singularity exec.
On clusters exposing only the documented apptainer executable, every wrapper command fails before
starting hvantk.
Code

containers/hvantk_run.sh[26]

+exec singularity exec "${BINDS[@]}" \
Evidence
The script describes itself as an Apptainer/Singularity wrapper but executes only singularity. The
migration guide explicitly checks for either executable with which apptainer || which singularity.

containers/hvantk_run.sh[1-2]
containers/hvantk_run.sh[26-30]
docs_site/guide/hpc-migration.md[97-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The wrapper hardcodes `singularity`, preventing execution on Apptainer-only clusters even though both runtimes are documented as supported.

## Issue Context
Resolve `apptainer` or `singularity` before creating scratch state, allow an explicit override if useful, and emit a clear error if neither exists.

## Fix Focus Areas
- containers/hvantk_run.sh[11-30]
- docs_site/guide/hpc-migration.md[93-104]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Deprecated field causes false drift 🐞 Bug ≡ Correctness
Description
The AlphaGenome probe places release_count from PyPI's deprecated releases field in the compared
headers surface, despite intentionally allowing that field to disappear. When PyPI removes it—or
when a yanked/prerelease entry changes—the probe reports drift even though info.version and the
installable SDK are unchanged.
Code

hvantk/skills/alphagenome/drift_probe.py[R68-70]

+    releases = sorted((payload.get("releases") or {}).keys())
+    if releases:
+        compared["release_count"] = len(releases)
Evidence
The implementation states that releases is deprecated and optional, but copies its count into
headers. Drift comparison ignores only top-level metadata keys, so a change inside headers is
reported as drift; the committed baseline currently contains release_count.

hvantk/skills/alphagenome/drift_probe.py[56-70]
hvantk/skills/alphagenome/drift_probe.py[72-81]
hvantk/skills/alphagenome/tests/drift_fingerprint.json[4-8]
hvantk/core/plugin/drift_runner.py[256-272]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A deprecated, non-authoritative release count is included in the compared fingerprint and creates false drift.

## Issue Context
The current SDK version is already the authoritative signal. Keep the release list/count under `informational`, and add a regression test proving that removal or alteration of `releases` does not change the compared fingerprint when `info.version` is unchanged.

## Fix Focus Areas
- hvantk/skills/alphagenome/drift_probe.py[56-81]
- hvantk/skills/alphagenome/tests/test_drift_probe.py[60-69]
- hvantk/skills/alphagenome/tests/drift_fingerprint.json[4-12]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Retries exceed probe timeout 🐞 Bug ☼ Reliability
Description
The gnomAD probe's per-request (5, 10) timeout does not keep its three-object loop within the
60-second probe budget because request_with_retry performs four attempts with backoff for each
object. One object can consume roughly 54 seconds on repeated read timeouts, so another slow object
causes the global alarm to abort an otherwise recoverable probe.
Code

hvantk/skills/gnomad_metrics/drift_probe.py[R58-64]

+# Sized against the runner's budget, not per request. drift_cli defaults
+# --timeout to 60s and enforces it with a single SIGALRM around the whole probe,
+# while requests applies its timeout separately to connect and read. At the
+# previous 30s this loop's worst case was 3 x 60 = 180s, so a merely slow bucket
+# reported probe_failed on a healthy source. A (connect, read) pair keeps the
+# whole loop inside the alarm.
+_TIMEOUT_S = (5.0, 10.0)
Evidence
The probe passes its timeout to request_with_retry without overriding retries. That helper
defaults to four attempts, retries timeouts and connection failures with exponential backoff, while
the drift runner places one 60-second SIGALRM around the entire multi-object probe.

hvantk/skills/gnomad_metrics/drift_probe.py[58-83]
hvantk/skills/gnomad_metrics/drift_probe.py[124-148]
hvantk/core/utils/http.py[30-36]
hvantk/core/utils/http.py[81-129]
hvantk/core/plugin/drift_runner.py[218-239]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Per-attempt request timeouts and default retries can exceed the drift runner's single whole-probe timeout.

## Issue Context
Set an explicit attempt count and smaller request/backoff limits based on the number of objects, or implement a shared deadline so all objects retain a chance to be probed before the 60-second alarm.

## Fix Focus Areas
- hvantk/skills/gnomad_metrics/drift_probe.py[58-83]
- hvantk/core/utils/http.py[30-36]
- hvantk/core/utils/http.py[81-145]
- hvantk/core/plugin/drift_runner.py[218-239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: ⚖️ Balanced

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread containers/hvantk_run.sh
Comment on lines +17 to +20
SPARK_SCRATCH="${SLURM_TMPDIR:-/tmp/spark-$USER-${SLURM_JOB_ID:-$$}}"
mkdir -p "$SPARK_SCRATCH"
cleanup(){ rm -rf "$SPARK_SCRATCH"; }
trap cleanup EXIT

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Scheduler scratch can be deleted 🐞 Bug ☼ Reliability

When SLURM_TMPDIR is set, the wrapper assigns the scheduler-owned directory itself to
SPARK_SCRATCH and recursively deletes it from the EXIT trap. Any failure after the trap is
installed, including a missing singularity executable, can erase unrelated files stored in the
job's shared scratch directory.
Agent Prompt
## Issue description
The wrapper may recursively delete the complete scheduler-provided `SLURM_TMPDIR`, including files it did not create.

## Issue Context
`SLURM_TMPDIR` should be treated as a parent directory. Create a uniquely named child owned by this invocation, bind that child, and remove only that child. Account for the fact that a successful `exec` replaces the shell and does not execute its EXIT trap.

## Fix Focus Areas
- containers/hvantk_run.sh[16-30]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread containers/hvantk_run.sh
BINDS=(-B "$SPARK_SCRATCH:$SPARK_SCRATCH")
[[ -n "${HVANTK_BIND:-}" ]] && BINDS+=(-B "$HVANTK_BIND")

exec singularity exec "${BINDS[@]}" \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Apptainer-only clusters cannot run 🐞 Bug ≡ Correctness

The wrapper advertises Apptainer/Singularity support but unconditionally invokes singularity exec.
On clusters exposing only the documented apptainer executable, every wrapper command fails before
starting hvantk.
Agent Prompt
## Issue description
The wrapper hardcodes `singularity`, preventing execution on Apptainer-only clusters even though both runtimes are documented as supported.

## Issue Context
Resolve `apptainer` or `singularity` before creating scratch state, allow an explicit override if useful, and emit a clear error if neither exists.

## Fix Focus Areas
- containers/hvantk_run.sh[11-30]
- docs_site/guide/hpc-migration.md[93-104]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +68 to +70
releases = sorted((payload.get("releases") or {}).keys())
if releases:
compared["release_count"] = len(releases)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Deprecated field causes false drift 🐞 Bug ≡ Correctness

The AlphaGenome probe places release_count from PyPI's deprecated releases field in the compared
headers surface, despite intentionally allowing that field to disappear. When PyPI removes it—or
when a yanked/prerelease entry changes—the probe reports drift even though info.version and the
installable SDK are unchanged.
Agent Prompt
## Issue description
A deprecated, non-authoritative release count is included in the compared fingerprint and creates false drift.

## Issue Context
The current SDK version is already the authoritative signal. Keep the release list/count under `informational`, and add a regression test proving that removal or alteration of `releases` does not change the compared fingerprint when `info.version` is unchanged.

## Fix Focus Areas
- hvantk/skills/alphagenome/drift_probe.py[56-81]
- hvantk/skills/alphagenome/tests/test_drift_probe.py[60-69]
- hvantk/skills/alphagenome/tests/drift_fingerprint.json[4-12]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +58 to +64
# Sized against the runner's budget, not per request. drift_cli defaults
# --timeout to 60s and enforces it with a single SIGALRM around the whole probe,
# while requests applies its timeout separately to connect and read. At the
# previous 30s this loop's worst case was 3 x 60 = 180s, so a merely slow bucket
# reported probe_failed on a healthy source. A (connect, read) pair keeps the
# whole loop inside the alarm.
_TIMEOUT_S = (5.0, 10.0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Retries exceed probe timeout 🐞 Bug ☼ Reliability

The gnomAD probe's per-request (5, 10) timeout does not keep its three-object loop within the
60-second probe budget because request_with_retry performs four attempts with backoff for each
object. One object can consume roughly 54 seconds on repeated read timeouts, so another slow object
causes the global alarm to abort an otherwise recoverable probe.
Agent Prompt
## Issue description
Per-attempt request timeouts and default retries can exceed the drift runner's single whole-probe timeout.

## Issue Context
Set an explicit attempt count and smaller request/backoff limits based on the number of objects, or implement a shared deadline so all objects retain a chance to be probed before the 60-second alarm.

## Fix Focus Areas
- hvantk/skills/gnomad_metrics/drift_probe.py[58-83]
- hvantk/core/utils/http.py[30-36]
- hvantk/core/utils/http.py[81-145]
- hvantk/core/plugin/drift_runner.py[218-239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@enriquea
enriquea merged commit 2e4ecbb into main Sep 1, 2026
14 of 15 checks passed
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.

2 participants