Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ build:
- vcf-rdfizer=vcf_rdfizer:main
- vcf-rdfizer-rules=vcf_rdfizer_rules:main
- vcf-rdfizer-link=vcf_rdfizer_link:main
- vcf-rdfizer-policy=vcf_rdfizer_policy:main

requirements:
host:
Expand All @@ -36,16 +37,20 @@ test:
- vcf-rdfizer --help
- vcf-rdfizer-rules --help
- vcf-rdfizer-link list
- vcf-rdfizer-policy --version
# The vendored vocabulary is package data, not code, so no import touches
# it: a dropped package-data glob would pass every check above and only
# surface when SHACL validation runs. One file per glob in pyproject.toml.
- python -c "import importlib.resources as r; d = r.files('vcf_rdfizer_data'); assert d.joinpath('VOCABULARY_PROVENANCE.json').is_file() and d.joinpath('shacl').joinpath('vcf-4.5.shacl.ttl').is_file() and d.joinpath('ontology').joinpath('vcf-core-vocabulary.bundle.ttl').is_file()"
# The policy plug-in's profile and default purpose vocabulary are package data too.
- python -c "import importlib.resources as r; d = r.files('vcf_rdfizer_data.policy'); assert d.joinpath('vcf-core-profile.ttl').is_file() and d.joinpath('duo-subset.ttl').is_file()"
imports:
- vcf_rdfizer
# The vocabulary terms, VCF-version model and lexical parsers. Importing it
# here catches a packaging miss that would otherwise only surface at
# conversion time, since vcf_rdfizer imports it at module load.
- vcf_rdfizer_vocab
- vcf_rdfizer_policies

about:
home: https://github.com/ecrum19/VCF-RDFizer
Expand Down
6 changes: 6 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ deciding whether the tool fits your problem, read
graph: an ODRL profile with graph selectors, three enforcement tiers, and
verification — plus a candid account of why access control is not
anonymization when the genotypes are themselves identifiers.
- **[Policy attachment v0.1.0](policy-demonstrator.md)** — *implemented;
walkthrough in `examples/policy/`.* The first slice of the privacy design:
ODRL policies attached to any resource or declared graph selection, a
partition rule that says what a withheld resource takes with it, per-request
release views, and checks — including a VCF-text oracle — that each view
withholds exactly what it should. Selectors and partitions are Turtle, not code.

### What the graph looks like

Expand Down
7 changes: 6 additions & 1 deletion docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,12 @@ record what an artifact was permitted to contain. Three consequences today:
amount of label removal makes a released genotype graph non-identifying.

The plan is [`privacy-policy-design.md`](privacy-policy-design.md), which is
explicit that what it offers is *governed release*, not anonymization.
explicit that what it offers is *governed release*, not anonymization. Its first
slice exists as a demonstrator, [`vcf-rdfizer-policy`](policy-demonstrator.md)
v0.1.0: ODRL policies on files and on declared graph selections (region and
variant ship; others are Turtle declarations), verified release views, in
memory and after conversion. It changes none of the points above for a
graph produced by a normal conversion.

**No clinical claims.** The tool transcribes a VCF. It does not interpret,
annotate, prioritize, or assess pathogenicity, and its output should not be
Expand Down
446 changes: 446 additions & 0 deletions docs/policy-demonstrator.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions docs/privacy-policy-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ contract before code depends on it — and, in this case, to be explicit about
what a policy layer can and cannot achieve, because the failure mode of a
privacy feature is a false sense of safety.*

*The first slice is implemented and specified separately:
[`policy-demonstrator.md`](policy-demonstrator.md), v0.1.0 — ODRL attached to
files, regions and variants over single-sample fixtures, with per-request views
verified against an oracle. It implements a subset of this document and cites
the sections it defers.*

VCF-RDFizer currently makes one decision about disclosure: it converts
everything. Every sample, every genotype, every header line, every free-text
`Description` goes into the graph, and every artifact is all-or-nothing. The
Expand Down
5 changes: 4 additions & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ The proposal is an ODRL profile whose assets are **graph selectors** (by class,
predicate, sample, genomic region, declared field or pattern), compiled to a
release plan and enforced at the cheapest available point in the existing
pipeline — TSV pre-filtering, emitter-time filtering, or a post-hoc pass.
Full design in [`privacy-policy-design.md`](privacy-policy-design.md).
Full design in [`privacy-policy-design.md`](privacy-policy-design.md). The first
slice, a v0.1.0 demonstrator over single-sample fixtures, is specified in
[`policy-demonstrator.md`](policy-demonstrator.md); its §10 maps later versions
onto the full design's build order.

Two findings from that design are worth surfacing here because they affect work
outside it:
Expand Down
46 changes: 46 additions & 0 deletions examples/policy/P001.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
##fileformat=VCFv4.3
##fileDate=20260925
##source=vcf-rdfizer-policy-demonstrator-fixture
##reference=GRCh38
##contig=<ID=chr1,length=248956422,assembly=GRCh38>
##contig=<ID=chr17,length=83257441,assembly=GRCh38>
##contig=<ID=chr19,length=58617616,assembly=GRCh38>
##contig=<ID=chr20,length=64444167,assembly=GRCh38>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total read depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT P001
chr1 11913838 . A T 87 PASS DP=38 GT:DP 1/1:38
chr1 33711661 . G C 61 PASS DP=37 GT:DP 1/1:37
chr1 45899293 . C T 74 PASS DP=52 GT:DP 0/1:52
chr1 138834739 . T G 70 PASS DP=46 GT:DP 0/1:46
chr1 139602254 . G T 84 PASS DP=49 GT:DP 1/1:49
chr1 162068500 . A G 57 PASS DP=33 GT:DP 1/1:33
chr1 227621759 . C G 88 PASS DP=51 GT:DP 0/1:51
chr17 43044294 . A C 62 PASS DP=45 GT:DP 0/1:45
chr17 43044295 . C G 91 PASS DP=46 GT:DP 0/1:46
chr17 43055276 . G A 86 PASS DP=51 GT:DP 0/1:51
chr17 43059666 . G A 55 PASS DP=24 GT:DP 0/1:24
chr17 43061329 . G A 75 PASS DP=40 GT:DP 1/1:40
chr17 43075071 . C G 70 PASS DP=50 GT:DP 1/1:50
chr17 43087473 . A C 52 PASS DP=45 GT:DP 0/1:45
chr17 43095759 . C T 52 PASS DP=51 GT:DP 1/1:51
chr17 43100876 . G T 93 PASS DP=36 GT:DP 0/1:36
chr17 43108081 . T C 60 PASS DP=22 GT:DP 0/1:22
chr17 43111166 . C A 71 PASS DP=29 GT:DP 0/1:29
chr17 43118559 . T C 56 PASS DP=50 GT:DP 0/1:50
chr17 43125483 . C T 76 PASS DP=40 GT:DP 1/1:40
chr17 43125484 . G C 89 PASS DP=59 GT:DP 0/1:59
chr19 44906345 . T G 62 PASS DP=52 GT:DP 0/1:52
chr19 44907272 . T G 85 PASS DP=29 GT:DP 0/1:29
chr19 44907527 . G C 78 PASS DP=23 GT:DP 1/1:23
chr19 44908684 rs429358 T C 56 PASS DP=58 GT:DP 0/1:58
chr20 12657015 . G A 94 PASS DP=39 GT:DP 0/1:39
chr20 13974064 . C G 73 PASS DP=22 GT:DP 0/1:22
chr20 22188117 . A C 99 PASS DP=47 GT:DP 0/1:47
chr20 30588233 . T G 55 PASS DP=22 GT:DP 0/1:22
chr20 36112198 . C A 50 PASS DP=38 GT:DP 1/1:38
chr20 38576612 . C G 94 PASS DP=26 GT:DP 0/1:26
chr20 46050645 . A G 71 PASS DP=36 GT:DP 0/1:36
chr20 47351745 . C A 81 PASS DP=24 GT:DP 1/1:24
chr20 50908083 . G C 89 PASS DP=49 GT:DP 0/1:49
35 changes: 35 additions & 0 deletions examples/policy/P002.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
##fileformat=VCFv4.3
##fileDate=20260925
##source=vcf-rdfizer-policy-demonstrator-fixture
##reference=GRCh38
##contig=<ID=chr1,length=248956422,assembly=GRCh38>
##contig=<ID=chr17,length=83257441,assembly=GRCh38>
##contig=<ID=chr19,length=58617616,assembly=GRCh38>
##contig=<ID=chr20,length=64444167,assembly=GRCh38>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total read depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT P002
chr1 11913838 . A T 90 PASS DP=47 GT:DP 0/1:47
chr1 45899293 . C T 68 PASS DP=54 GT:DP 0/1:54
chr1 139602254 . G T 56 PASS DP=34 GT:DP 1/1:34
chr1 162068500 . A G 61 PASS DP=35 GT:DP 1/1:35
chr1 231965065 . C T 94 PASS DP=57 GT:DP 0/1:57
chr1 232595915 . T C 57 PASS DP=27 GT:DP 0/1:27
chr17 43061329 . G A 98 PASS DP=32 GT:DP 0/1:32
chr17 43075071 . C G 80 PASS DP=52 GT:DP 0/1:52
chr17 43087473 . A C 53 PASS DP=58 GT:DP 1/1:58
chr17 43095759 . C T 96 PASS DP=37 GT:DP 1/1:37
chr17 43111166 . C A 92 PASS DP=32 GT:DP 0/1:32
chr17 43118500 . C T 67 PASS DP=29 GT:DP 0/1:29
chr17 43124696 . T A 52 PASS DP=56 GT:DP 1/1:56
chr19 44907675 . A C 77 PASS DP=22 GT:DP 0/1:22
chr19 44908684 . T G 50 PASS DP=28 GT:DP 1/1:28
chr19 44908822 rs7412 C T 55 PASS DP=38 GT:DP 0/1:38
chr20 12657015 . G A 82 PASS DP=31 GT:DP 0/1:31
chr20 13974064 . C G 65 PASS DP=56 GT:DP 0/1:56
chr20 36112198 . C A 55 PASS DP=20 GT:DP 0/1:20
chr20 38576612 . C G 63 PASS DP=39 GT:DP 0/1:39
chr20 46050645 . A G 86 PASS DP=34 GT:DP 1/1:34
chr20 47351745 . C A 51 PASS DP=20 GT:DP 0/1:20
chr20 50908083 . G C 72 PASS DP=60 GT:DP 0/1:60
39 changes: 39 additions & 0 deletions examples/policy/P003.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
##fileformat=VCFv4.3
##fileDate=20260925
##source=vcf-rdfizer-policy-demonstrator-fixture
##reference=GRCh38
##contig=<ID=chr1,length=248956422,assembly=GRCh38>
##contig=<ID=chr17,length=83257441,assembly=GRCh38>
##contig=<ID=chr19,length=58617616,assembly=GRCh38>
##contig=<ID=chr20,length=64444167,assembly=GRCh38>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total read depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT P003
chr1 33711661 . G C 53 PASS DP=20 GT:DP 0/1:20
chr1 45899293 . C T 70 PASS DP=20 GT:DP 0/1:20
chr1 138834739 . T G 92 PASS DP=35 GT:DP 1/1:35
chr1 152491455 . A G 56 PASS DP=42 GT:DP 0/1:42
chr1 231965065 . C T 69 PASS DP=22 GT:DP 0/1:22
chr1 232595915 . T C 62 PASS DP=47 GT:DP 0/1:47
chr17 43055276 . G A 59 PASS DP=50 GT:DP 1/1:50
chr17 43059666 . G A 91 PASS DP=43 GT:DP 1/1:43
chr17 43061329 . G A 85 PASS DP=35 GT:DP 1/1:35
chr17 43075071 . C G 52 PASS DP=50 GT:DP 0/1:50
chr17 43087473 . A C 65 PASS DP=38 GT:DP 1/1:38
chr17 43095759 . C T 69 PASS DP=24 GT:DP 0/1:24
chr17 43100876 . G T 69 PASS DP=33 GT:DP 0/1:33
chr17 43108081 . T C 79 PASS DP=46 GT:DP 0/1:46
chr17 43124696 . T A 54 PASS DP=22 GT:DP 1/1:22
chr19 44906345 . T G 75 PASS DP=57 GT:DP 0/1:57
chr19 44907272 . T G 95 PASS DP=35 GT:DP 0/1:35
chr19 44907527 . G C 51 PASS DP=33 GT:DP 1/1:33
chr19 44907675 . A C 52 PASS DP=27 GT:DP 0/1:27
chr19 44908684 rs429358 T C 60 PASS DP=33 GT:DP 0/1:33
chr19 44908822 rs7412 C T 58 PASS DP=39 GT:DP 0/1:39
chr20 13974064 . C G 68 PASS DP=27 GT:DP 0/1:27
chr20 20513631 . T A 51 PASS DP=44 GT:DP 0/1:44
chr20 22188117 . A C 68 PASS DP=44 GT:DP 0/1:44
chr20 30588233 . T G 58 PASS DP=47 GT:DP 0/1:47
chr20 36112198 . C A 60 PASS DP=40 GT:DP 1/1:40
chr20 38576612 . C G 85 PASS DP=23 GT:DP 1/1:23
38 changes: 38 additions & 0 deletions examples/policy/P004.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
##fileformat=VCFv4.3
##fileDate=20260925
##source=vcf-rdfizer-policy-demonstrator-fixture
##reference=GRCh38
##contig=<ID=chr1,length=248956422,assembly=GRCh38>
##contig=<ID=chr17,length=83257441,assembly=GRCh38>
##contig=<ID=chr19,length=58617616,assembly=GRCh38>
##contig=<ID=chr20,length=64444167,assembly=GRCh38>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total read depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT P004
chr1 11913838 . A T 76 PASS DP=43 GT:DP 0/1:43
chr1 33711661 . G C 64 PASS DP=29 GT:DP 0/1:29
chr1 45899293 . C T 74 PASS DP=48 GT:DP 0/1:48
chr1 138834739 . T G 61 PASS DP=45 GT:DP 0/1:45
chr1 139602254 . G T 89 PASS DP=31 GT:DP 1/1:31
chr1 231965065 . C T 98 PASS DP=25 GT:DP 0/1:25
chr1 232595915 . T C 76 PASS DP=28 GT:DP 1/1:28
chr17 43055276 . G A 81 PASS DP=31 GT:DP 0/1:31
chr17 43059666 . G A 82 PASS DP=49 GT:DP 0/1:49
chr17 43075071 . C G 52 PASS DP=50 GT:DP 0/1:50
chr17 43087473 . A C 65 PASS DP=37 GT:DP 0/1:37
chr17 43095759 . C T 65 PASS DP=24 GT:DP 0/1:24
chr17 43108081 . T C 99 PASS DP=31 GT:DP 0/1:31
chr17 43118500 . C T 83 PASS DP=27 GT:DP 0/1:27
chr17 43118559 . T C 73 PASS DP=23 GT:DP 1/1:23
chr17 43124696 . T A 51 PASS DP=52 GT:DP 0/1:52
chr19 44907272 . T G 96 PASS DP=50 GT:DP 0/1:50
chr19 44907675 . A C 68 PASS DP=30 GT:DP 1/1:30
chr19 44908684 rs429358 T C 80 PASS DP=58 GT:DP 0/1:58
chr20 12657015 . G A 79 PASS DP=28 GT:DP 1/1:28
chr20 13974064 . C G 98 PASS DP=27 GT:DP 0/1:27
chr20 20513631 . T A 85 PASS DP=27 GT:DP 0/1:27
chr20 30588233 . T G 85 PASS DP=26 GT:DP 0/1:26
chr20 36112198 . C A 54 PASS DP=35 GT:DP 0/1:35
chr20 47351745 . C A 55 PASS DP=31 GT:DP 0/1:31
chr20 50908083 . G C 95 PASS DP=58 GT:DP 0/1:58
41 changes: 41 additions & 0 deletions examples/policy/P005.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
##fileformat=VCFv4.3
##fileDate=20260925
##source=vcf-rdfizer-policy-demonstrator-fixture
##reference=GRCh38
##contig=<ID=chr1,length=248956422,assembly=GRCh38>
##contig=<ID=chr17,length=83257441,assembly=GRCh38>
##contig=<ID=chr19,length=58617616,assembly=GRCh38>
##contig=<ID=chr20,length=64444167,assembly=GRCh38>
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total read depth">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read depth">
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT P005
chr1 11913838 . A T 71 PASS DP=25 GT:DP 0/1:25
chr1 33711661 . G C 72 PASS DP=56 GT:DP 0/1:56
chr1 45899293 . C T 87 PASS DP=47 GT:DP 0/1:47
chr1 138834739 . T G 51 PASS DP=47 GT:DP 1/1:47
chr1 139602254 . G T 87 PASS DP=26 GT:DP 1/1:26
chr1 152491455 . A G 66 PASS DP=40 GT:DP 0/1:40
chr1 231965065 . C T 50 PASS DP=25 GT:DP 0/1:25
chr1 232595915 . T C 58 PASS DP=50 GT:DP 1/1:50
chr17 43055276 . G A 75 PASS DP=54 GT:DP 0/1:54
chr17 43059666 . G A 98 PASS DP=55 GT:DP 0/1:55
chr17 43087473 . A C 94 PASS DP=23 GT:DP 1/1:23
chr17 43095759 . C T 91 PASS DP=27 GT:DP 1/1:27
chr17 43100876 . G T 51 PASS DP=35 GT:DP 0/1:35
chr17 43111166 . C A 68 PASS DP=31 GT:DP 0/1:31
chr17 43118500 . C T 56 PASS DP=47 GT:DP 0/1:47
chr17 43118559 . T C 68 PASS DP=22 GT:DP 0/1:22
chr17 43124696 . T A 54 PASS DP=58 GT:DP 1/1:58
chr19 44907675 . A C 82 PASS DP=57 GT:DP 0/1:57
chr19 44908684 rs429358 T C 67 PASS DP=43 GT:DP 0/1:43
chr19 44908822 rs7412 C T 84 PASS DP=34 GT:DP 1/1:34
chr20 12657015 . G A 95 PASS DP=60 GT:DP 0/1:60
chr20 13974064 . C G 56 PASS DP=43 GT:DP 0/1:43
chr20 20513631 . T A 81 PASS DP=21 GT:DP 0/1:21
chr20 22188117 . A C 80 PASS DP=44 GT:DP 0/1:44
chr20 36112198 . C A 74 PASS DP=28 GT:DP 0/1:28
chr20 38576612 . C G 92 PASS DP=55 GT:DP 0/1:55
chr20 46050645 . A G 59 PASS DP=53 GT:DP 1/1:53
chr20 47351745 . C A 82 PASS DP=28 GT:DP 0/1:28
chr20 50908083 . G C 99 PASS DP=20 GT:DP 1/1:20
106 changes: 106 additions & 0 deletions examples/policy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Policy attachment example (v0.1.0)

One synthetic cohort, one set of ODRL policies, three requesters, and three
different release views, each checked against the source VCFs. How the engine
works (select → partition → decide, each configured in Turtle) is in
[`docs/policy-demonstrator.md`](../../docs/policy-demonstrator.md).

This is **governed release, not anonymization.** Views keep the original IRIs,
and a released genotype still identifies the person it came from.

## Run it

```bash
examples/policy/run_demo.sh /tmp/policy-demo # needs rdflib; no Docker
PROFILE=condensed examples/policy/run_demo.sh /tmp/policy-demo-condensed
```

It explains the policy, attaches it to the graph, and then for each requester
evaluates a view and checks it. Finally it prints the decision grid:

```text
requester P001.vcf P002.vcf P003.vcf P004.vcf P005.vcf triples withheld
alz 22 16 18 withheld 20 4649
clinical 33 23 withheld withheld withheld 6539
gru 21 16 withheld withheld withheld 7869
```

Each number is the records released from that file. Where P001 and P002 differ
between requesters, that's the cohort rules at work. *BRCA1* records are
released only for clinical care, and the APOE ε4 variant (rs429358) only for
disease-specific research. P004 withdrew.

## What is here

| File | What it is |
| --- | --- |
| `make_fixture.py` | Deterministic generator for the five VCFs and `fixture.json` |
| `P001.vcf` … `P005.vcf` | One synthetic participant each, GRCh38, 23–34 records |
| `fixture.json` | Seed, loci, each participant's consent, and the three requesters |
| `policy.ttl` | Five consents (one per file) and the cohort policy (*BRCA1*, ε4) |
| `custom-selector.ttl` | A selector type declared in the policy itself (below) |
| `converted/` | The VCFs converted once per sample profile, so nothing needs Docker; see `PROVENANCE.json` |
| `run_demo.sh` | The walkthrough above |

The positions are real GRCh38 coordinates in real loci, and rs429358 and
rs7412 are the real variants. Every other allele, and every genotype, is
synthetic. To regenerate the fixture, run
`python3 examples/policy/make_fixture.py`.

## The pieces, one at a time

```bash
vcf-rdfizer-policy explain --policy policy.ttl
vcf-rdfizer-policy attach --rdf converted/expanded/P00*.nt.gz --policy policy.ttl -o annotated.nt
vcf-rdfizer-policy evaluate --rdf converted/expanded/P00*.nt.gz --policy policy.ttl \
--assignee https://example.org/party/alz-consortium --purpose DUO:0000007 -o views/alz
vcf-rdfizer-policy check --view views/alz --rdf converted/expanded/P00*.nt.gz \
--policy policy.ttl --vcf P00*.vcf
```

`evaluate` writes the following into its output directory:
- `view.nt`, the released triples;
- `decisions.csv`, one row per record with the rule that decided it;
- `summary.json`, the counts;
- `manifest.ttl`, the policy's digest, the request, what was withheld and the
obligations accepted.

`check` runs the structural checks against the source graph. With `--vcf`, it
also re-derives the expected records straight from the VCF text and fails on
any difference.

## Write your own selector

Selector types are SPARQL, declared in Turtle, and there is nothing to code.
`custom-selector.ttl` declares one inside the policy that uses it:

```turtle
ex:QualityBelow a vcfp:SelectorType ;
vcfp:parameter ex:threshold ; # bound to ?threshold
vcfp:query """
PREFIX vcfc: <https://w3id.org/vcf-core/vocab#>
SELECT ?resource WHERE {
?resource a vcfc:VCFRecord ; vcfc:hasCall ?call .
?call vcfc:qual ?qual .
FILTER(?qual < ?threshold) }""" .

ex:low-quality a odrl:Asset , vcfp:GraphSelection ;
vcfp:selector [ a ex:QualityBelow ; ex:threshold 60 ] .
```

With every file released for general research except that selection, 38 of
the 139 records are withheld:

```bash
vcf-rdfizer-policy evaluate --rdf converted/expanded/P00*.nt.gz --policy custom-selector.ttl \
--assignee https://example.org/party/anyone --purpose DUO:0000042 -o views/quality
```

The query must project `?resource`. Each `vcfp:parameter` names a property of
the selector node, bound to the variable of the same local name. A selector
type can also carry a `vcfp:violations` query, and any row it returns stops
evaluation; the shipped region and variant selectors use one to check the
assembly.

To share a selector across policies, put it in a file and pass
`--profile vcf-core --profile my-selectors.ttl`.
Loading
Loading