Skip to content

feat: explicit retrieval-sources override with {edge_id} record-URL templating - #116

Merged
SkyeAv merged 2 commits into
mainfrom
feat/explicit-sources-override
Aug 24, 2026
Merged

feat: explicit retrieval-sources override with {edge_id} record-URL templating#116
SkyeAv merged 2 commits into
mainfrom
feat/explicit-sources-override

Conversation

@SkyeAv

@SkyeAv SkyeAv commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

ManualProvenance gains an optional explicit sources template that replaces the derived primary/upstream sources[] emission entirely, plus an {edge_id} placeholder for per-edge record URLs.

provenance:
  override:
    sources:
      - resource_id: infores:multiomics-drugapprovals
        resource_role: aggregator_knowledge_source
        upstream_resource_ids: [infores:dailymed, infores:faers]
        source_record_urls:
          - "https://db.systemsbiology.net/gestalt/cgi-pub/KGinfo.pl?id={edge_id}"
      - resource_id: infores:faers
        resource_role: primary_knowledge_source
      - resource_id: infores:dailymed
        resource_role: supporting_data_source

Motivation

DAKP needs to reproduce its legacy KG retrieval provenance — the transforming resource as aggregator_knowledge_source carrying a per-edge gestalt viewer URL (KGinfo.pl?id=<edge id>), an upstream as the primary_knowledge_source — declaratively from the table config, instead of post-processing the built edges file.

Design

  • SourceOverride model (models.py): resource_id / resource_role / optional upstream_resource_ids / optional source_record_urls. Roles validate against the three Biolink ResourceRoleEnum members (literals, no heavy biolink import); all CURIEs must be infores:-prefixed; URLs must be http(s) after stripping {edge_id} occurrences.
  • Coherence validation (override-bad-sources): sources is mutually exclusive with upstream_resource_ids / upstream_source_record_urls (it subsumes both), must be non-empty, resource_ids unique, and at least one entry must be a primary or aggregator knowledge source (keeps the RIG audit's non-empty-primary check satisfiable).
  • retrieval_sources(explicit=...) (lib.py): emits exactly the templated entries, in order; id still mirrors resource_id and absent list fields stay typed nulls for the Rust null-stripper, so output formatting is unchanged.
  • {edge_id} resolution: the edge id is a deterministic content hash assigned by the Rust deduper after subgraphs are written, so the literal placeholder is what gets hashed and a post-dedup streaming sweep (_resolve_edge_id_placeholders) substitutes each record's own id into sources[].source_record_urls in the final edges NDJSON only. Files without the marker are left byte-identical (per-line substring precheck, no full parse).

Tests

  • tests/test_models.py: 6 new validation tests (valid template, bad role, non-infores ids, non-URL, both mutual-exclusion combos, empty/duplicate/all-supporting).
  • tests/test_lib.py: op-arg + executed-op test for the explicit template (exact order/roles/upstreams, literal placeholder unresolved at build stage, typed nulls on bare entries) and a direct test of the placeholder sweep.
  • Full suite: 1005 passed, 39 skipped; ruff check/format clean; pyright 0 errors.

Docs: new "Explicit sources template" subsection in docs/configuration/table.md.

…emplating

ManualProvenance gains an optional sources template that replaces the
derived primary/upstream sources emission entirely: each entry declares
its resource_id, resource_role (validated against the three Biolink
ResourceRoleEnum members), optional upstream_resource_ids, and optional
source_record_urls. source_record_urls may embed the {edge_id}
placeholder, resolved against each record's own id in a post-dedup sweep
of the final edges NDJSON (the literal placeholder is what the Rust
deduper hashes, so edge ids stay deterministic).

The template is mutually exclusive with upstream_resource_ids and
upstream_source_record_urls, must be non-empty with unique resource_ids,
and must include at least one primary or aggregator entry.

This lets ingests like DAKP reproduce legacy KG retrieval provenance
(aggregator primary entry with a per-edge viewer URL, an upstream as the
primary knowledge source) declaratively from the table config instead of
post-processing the built edges.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

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: Pro Plus

Run ID: 89ced56d-c60c-4035-9331-4dcf55a459bc


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.

@SkyeAv
SkyeAv merged commit eaab0d3 into main Aug 24, 2026
5 checks passed
SkyeAv added a commit that referenced this pull request Aug 24, 2026
Cut 14.0.0 and bump the package version in pyproject.toml, uv.lock, and
CITATION.cff.

Major: one breaking change since 13.0.0. Generated edges no longer duplicate each
nested `sources` entry's provenance identifier into `sources[].id`; `resource_id`
is now the sole identifier on a retrieval-source entry (#115). The pinned Biolink
model still requires the inherited `Entity.id` on `RetrievalSource`, so the
validator supplies it to an in-memory compatibility copy only, and neither the
decoded record nor the written NDJSON carries it.

Also ships the explicit retrieval-`sources` template with `{edge_id}` record-URL
interpolation (#116) and the negative-log p-value un-logging fix (#114).

Changelog:
- The Unreleased section was missing #116 entirely; added it under `Added`, and
  gave the two existing entries their PR links plus a reader migration note for
  the `sources[].id` removal.

Docs:
- `docs/configuration/table.md`'s automatic-coercion section documented neither
  half of #114: added a `Negative-log P value` row to the recognition table and a
  bullet covering the un-logging (`p = 10 ** -x` on rename and on banding), the
  complete-token requirement, the deliberate pass on unmarked `log10` spellings,
  raw-beats-alias selection, and the Float64 underflow floor. Every documented
  spelling was checked against `is_neglog10_column` and `pvalue_target`.
- `docs/cli.md`'s validate-kgx section explained the pending-field count but not
  the mirror case #115 introduced; added the `RetrievalSource` compatibility
  alias, including that it stops being applied once a model release drops the
  requirement.
- Removed the five em-dashes #115 and #116 reintroduced into the two doc pages,
  restoring the docs-wide convention set in abb042a.

Known gap, deliberately not fixed here: `PVALUE_TOKEN_PATTERN` anchors on `\b`,
which does not fire after an underscore, so `raw_pvalue` / `adj_pvalue` /
`fdr_pvalue` / `negative_log10_pvalue` are not recognized as p-value columns at
all, even though the same names with a separated token (`gene_p_value`) and the
bare-P forms (`raw_p`) are. It predates this window and changing recognition
would shift behavior for existing configs, so it wants its own PR.

Testing:
- uv run pytest -q -> 1078 passed, 15 skipped (94% coverage)
- uv run ruff check . && uv run ruff format --check . && uv run pyright -> clean / 0 errors
- uv lock --check -> up to date
- uv run mkdocs build --strict -> clean

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRefj7KvacA9PGQYMCt6wy
SkyeAv added a commit to glusman-team/dakp that referenced this pull request Aug 24, 2026
…g v3

- bump to 1.2.0; require tablassert[qc]>=14.0.0 (explicit override.sources,
  SkyeAv/Tablassert#116) and regenerate tables/*.yaml
- edge provenance replicates the shipped legacy DAKP shape: gestalt
  {edge_id} record URL on the DAKP entry, FAERS/MEDI primaries, no
  dataset-level URLs, no empty lists; manual_validation_of_automated_agent
  on all three families
- FAERS reindex denylist drops GENERIC DRUG / GENERIC DRUGS subjects
- contraindication evidence prose no longer folds into supporting_text
- new publish_release_artifacts task (release.py): drug_approvals_kg
  {nodes,edges}_v<version>.{ndjson,tsv} + drug_approvals_kg_v<version>.yaml
- DAG id dakp_build -> dakp_build_v3 (Python DAG + Go bundle)
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