Conversation
…#73) - Attestation.yaml: rewrite the base Attestation as is_a Claim with hasTarget, reliesOn, requirement, appliesRuleSet, outcome, rationale, verificationMethod and an inlined Scope. Drop contentHash, graphIri and the PENDING verdict. - RegistryReviewAttestation.yaml: add the Regen Registry review vocabulary (findingLabel, findingType, issuerRole, conditions with milestones, outcome terms) as is_a Attestation. - Evidence.yaml: add the source content hash, resolver, DCMI type, format, locator, licence reference and issue date, and the integrity/access outcome terms. - ClaimVocabulary.yaml: add the shared reference terms and the verification-method enumeration (CS-4). - C06Claim.yaml: add the C06 subject classes (Project, Cohort, Site, Plot) and claim classes (C06ProjectClaim, C06CohortClaim, C06SiteClaim, C06PlotClaim, C06ProjectStatementClaim). - Claim.yaml: remove hasClaimType (#86); the kind of claim is its class. - claim-examples.py: check examples of several classes and modules, including slots a class narrows to an enum. - Add synthetic C06 site claim and registry confirmation fixtures, c06-mvp-claim.jsonld and registry-review-attestation.jsonld, and five invalid examples. Update the generic fixtures for the new Evidence fields. - docs: add attestation-and-evidence.md; update claim-base.md.
… rules (#73) - ClaimVocabulary.yaml: make verificationMethod single-valued (one method per record, with that record's party and date). - Attestation.yaml: require verificationMethodDescriptor when the method is OTHER (CS-4). RegistryReviewAttestation.yaml: require evidence on a finding (CS-3). Both are LinkML rules: the generated JSON Schema enforces them, the generated SHACL does not express them. - C06Claim.yaml: state areas as QUDT quantity values (area, with qudt:numericValue and qudt:unit unit:HA) instead of a bare number. - Add synthetic examples: c06-project-claim, c06-cohort-claim, c06-plot-claim, c06-project-statement-claim and generic-attestation, with versioned licence and rule-set references; and two invalid examples for the rules. - claim-examples.py: an invalid example marked "# shacl: not enforced" must be rejected by JSON Schema only. - docs: licence terms are referenced by IRI, and structured terms are left to story EX-2; no derivation reference is needed; claim-base.md records hasPrimaryImpact and hasCoBenefits as removed (project fields) and points the other moved fields to C06Claim.
- RegistryReviewAttestation.yaml: add RegistryFindingAttestation (is_a RegistryReviewAttestation), which requires findingType and at least one piece of evidence (CS-3), and drop the LinkML rule that the generated SHACL ignored. findingType moves to the new class. - Attestation.yaml: a Scope requires appliesTo, and unbounded moves from Scope to the Attestation (AD-1): a scope always names its subjects, no scope means the judgment applies only to its targets, and unbounded: true states explicitly that it has no limits. - Add a synthetic finding (registry-finding-attestation.jsonld) and invalid examples for a finding without evidence and a scope without subjects, both rejected by JSON Schema and SHACL. - docs: CS-4 (a descriptor with OTHER) remains the only rule enforced by JSON Schema only; LinkML's SHACL generator does not translate it (linkml/linkml#2464).
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
…edBy (#73) - Drop C06 fields that are rules, reviewers' conclusions, values computed from other claims, evidence or lifecycle state; the aggregation basis and enrolment cutoff become statement claims. - Add Activity.yaml (Activity, wasAssociatedWith, startDate, endDate) and Evidence.wasGeneratedBy, so evidence names the activity that produced it, its period and its operator.
…asUnit and qudt:value (#73) Move QuantityValue from ProjectInfo.yaml to core.yaml so C06Claim can use it without importing ProjectInfo, and drop AreaQuantity: both used class_uri qudt:QuantityValue, so the composed schema's SHACL applied both shapes to every quantity node. QuantityValue.unit is now a uriorcurie mapped to qudt:hasUnit, so unit:HA is the QUDT unit IRI rather than a string literal; qudt:unit is deprecated in QUDT 2.1 for qudt:hasUnit and removed in 3.0.0. numericValue maps to qudt:value, which current QUDT constrains on QuantityValue.
…ue (#73) Restore the constraints AreaQuantity had, now on the shared QuantityValue, and add an invalid example that both validators reject.
| The numeric value of the quantity. It cannot be negative: the | ||
| quantities stated so far are sizes and areas. | ||
| unit: | ||
| slot_uri: qudt:hasUnit |
There was a problem hiding this comment.
QUDT properties: qudt:hasUnit and qudt:value replace qudt:unit and qudt:numericValue
QuantityValue (moved here from ProjectInfo.yaml) previously mapped unit to qudt:unit with range: string, so a fixture's unit: unit:HA became the string literal "unit:HA", not the QUDT unit.
- The unit must be an IRI. In QUDT 2.1,
qudt:unitis anowl:ObjectPropertywithrdfs:range qudt:Unit(SCHEMA_QUDT-v2.1.ttl#L3041-L3050, release v2.1.30). In OWL, object properties connect individuals and only data properties take literals (OWL 2 Structural Specification §5.3–5.4).http://qudt.org/vocab/unit/HAdereferences tounit:HA a qudt:Unit. qudt:unitis deprecated, then removed. The same QUDT 2.1 definition hasdcterms:isReplacedBy qudt:hasUnit ; qudt:deprecated true. QUDT 3.0.0 "Removed all previously deprecated entities" (CHANGELOG.md#L838), soqudt:unitno longer exists in current QUDT.- Current QUDT constrains
qudt:hasUnitandqudt:value. Onmain,qudt:QuantityValueis a subclass ofqudt:Quantifiable(SCHEMA_QUDT_NoOWL.ttl#L672-L681), whose shape requiresqudt:hasUnitvalues to bequdt:Unitnodes (#L2506-L2511) and constrains the number onqudt:value(#L2534).qudt:numericValuewas never deprecated, but current QUDT puts no constraint on it. QUDT's own example usesqudt:hasUnit unit:KiloM-PER-HR ; qudt:value "90.0"^^xsd:DECIMAL(EXAMPLES_QUDT-DATATYPES.ttl#L146-L147).
So the unit slot is now hasUnit, a uriorcurie mapped to qudt:hasUnit (renamed from unit in 5eb8171), and numericValue maps to qudt:value. In the project YAML fixtures the key unit: becomes hasUnit:, and their RDF changes: the CreditProjectInfo-C06-019 fixture goes from qudt:numericValue "186.41"^^xsd:float ; qudt:unit "unit:HA" to qudt:hasUnit unit:HA ; qudt:value "186.41"^^xsd:float.
The rename also matters for JSON-LD: a term named unit shadowed the unit: prefix, so unit:HA did not expand there. With hasUnit, unit:HA expands to http://qudt.org/vocab/unit/HA in JSON-LD as in YAML and Turtle; c06-plot-claim.jsonld uses it, and its graph matches the fixture's Turtle.
The unit term shadowed the unit: prefix in JSON-LD, so unit:HA did not expand there. hasUnit matches the QUDT property it maps to and frees the prefix. Declare unit: in core.yaml and C06Claim.yaml, because a generated context only carries the root module's prefixes, and write unit:HA in the C06 plot fixture so the example check covers the expansion.
Closes #73 (WP1-06). Stacked on #87 (base
feat/84-linkml-1.11).It needs #85's base Claim and vocabulary, and #87's
uriorcuriereferences and LinkML 1.11 SHACL output.Implements ADR: ADR 0001 — D1 at
0cfe1c52(#56, Proposed), applied to the Attestation: no own hash or IRI, no mutable review or anchoring state in content.Differences from ADR (if any) and why: none.
The design is in
docs/attestation-and-evidence.md. It was derived from the review records of the WP8-01 workflow (regen-network/claims#49). Every example in this PR uses synthetic values.Please also review the internal evidence page: Claims Engine — CSSCP evidence for the WP1-06 schema design (Notion, internal). It holds what cannot be public: the source documents, which records map to which classes and fields, and the open questions specific to the workflow. Story IDs in this PR (CS-3, CS-4, AD-1, EX-2, PG-1) refer to the Claims Engine — Layered User Story Map (v2).
Changes
Attestation.yaml, rewritten.Attestation is_a Claim. The issuer ishasClaimantand the time isassertedAt; it is about a subject and cites evidence. It adds:hasTarget(exact versions of claims, attestations or a snapshot),reliesOn,requirement,appliesRuleSet,outcomeandrationale;verificationMethod, required, one per attestation, with a descriptor when it isOTHER;Scope(appliesTo, required, plusexclusionandlimitation), andunboundedfor a judgment with explicitly no limits.It holds nothing specific to one program.
RegistryReviewAttestation.yaml, new. The Regen Registry review vocabulary,is_a Attestation:findingLabel,issuerRole(required),conditionswith milestones, and theRegistryReviewOutcometerms. Findings are a subclass,RegistryFindingAttestation, which requires afindingType(CAR, CL, FAR, registry issue) and at least one piece of evidence. Another program would define its own subclasses. There is no attestation-type field.Evidence.yaml. AddssourceType(dcterms:type, DCMI Type Vocabulary),mediaType,contentHash(algorithm and hex digest of the cited version),resolver,locator,licence(dcterms:license, the IRI of the terms in effect),issued, andwasGeneratedBy(prov:wasGeneratedBy, the activity that produced the source). Also adds theEvidenceCheckOutcometerms (intact, altered, unreachable, access restricted), which the resolver reports and claims never store.Activity.yaml, new.Activity(ProvActivitymixin): an IRI,name,description, a period as dates (startDate,endDate) and who carried it out (wasAssociatedWith).wasAssociatedWithmoves here fromClaimVocabulary, which imports this module, andstartDate/endDatemove here fromC06Claim.yaml. It is a separate module becauseEvidenceneeds it andClaimVocabularyimportsEvidence. A claim reaches an activity through its evidence (claim →hasEvidence→wasGeneratedBy); the C06 claims need no domain activity of their own, because no C06 requirement checks who carried out a practice.ClaimVocabulary.yaml. AddshasTarget,reliesOn(⊑dcterms:references),requirement(named within a checklist version),appliesRuleSet(PG-1, distinct from schema-version declarations), andverificationMethodwithverificationMethodDescriptorand the CS-4 enumeration (OTHERwith a descriptor is the extension path).C06Claim.yaml, new (version 0.1.0). Named after its credit class, likeC01ProjectInfo.yaml.Project,Cohort,SiteandPlot,is_a ClaimSubject, holding only identifying fields.C06ProjectClaim,C06CohortClaim,C06SiteClaim,C06PlotClaimandC06ProjectStatementClaim,is_a Claim.C06ProjectStatementClaim. Rules (the project's mandatory and complementary practices), reviewers' conclusions (plot eligibility), values computed from other claims (project and cohort areas, project ecosystem types), evidence (land register records, land cover datasets, historic activity records) and lifecycle state (plot enrolment status) are not fields.area) use the sharedQuantityValue(below).QuantityValuemoves fromProjectInfo.yamltocore.yaml, soC06Claim.yamlreuses it without importingProjectInfo. A separate C06 area class would have shared the class IRIqudt:QuantityValue, so the composed schema's SHACL would have applied both shapes to every quantity node.numericValuemaps toqudt:value, and the unit slot is renamedunit→hasUnitand maps toqudt:hasUnit, now auriorcurie; both are required and the number cannot be negative. The rename frees theunit:prefix in JSON-LD, which theunitterm shadowed, sounit:HAexpands there as in YAML and Turtle;core.yamlandC06Claim.yamldeclare the prefix, because a generated context only carries the root module's prefixes.qudt:unitis deprecated in QUDT 2.1 forqudt:hasUnitand removed in 3.0.0 (sources in the inline comment oncore.yaml). In the project YAML fixtures the keyunit:becomeshasUnit:; their RDF changes:unit:HAbecomes the QUDT unit IRI instead of a string literal, and the number isqudt:value.Claim.yaml.hasClaimTypeis removed (Claim model gaps found when applied outside ecology (research-literature test) #86): a single required enum could not cover every kind of claim, and the specialized class says what kind of claim it is. TheClaimTypeenum stays in the taxonomy.ClaimSubject.yaml. Description updated: the module is no longer a skeleton.scripts/claim-examples.py. Checks examples of several classes, each against its own module's context and shapes. The class is taken from the fixture name, or from a# class:line in an invalid example. Slots a class narrows to an enum get the same context correction as other enum-valued slots. An invalid example marked# shacl: not enforcedbreaks a LinkML rule, so only JSON Schema must reject it.Examples (all synthetic).
c06-mvp-claim.jsonld(aC06SiteClaim, with field records and the activity that generated them),c06-project-claim.jsonld,c06-cohort-claim.jsonld,c06-plot-claim.jsonld,c06-project-statement-claim.jsonld,generic-attestation.jsonld(a baseAttestationwith anOTHERmethod and its descriptor),registry-review-attestation.jsonld(a scoped confirmation) andregistry-finding-attestation.jsonld(a clarification request). The evidence in them uses versioned licence and rule-set references.OTHERmethod without a descriptor, a scope without subjects, a finding without evidence, evidence without a hash, an evidence activity without an IRI, a site without its key, an undeclared field, and a negative area.Docs.
docs/attestation-and-evidence.md.docs/claim-base.mdupdated where WP1-06 — Define the MVP claim, attestation and evidence schema requirements #73 now answers it. Its field record now listshasPrimaryImpactandhasCoBenefitsas removed, because they are project and credit class fields, and pointsquantity,hasCreditClassandusesMethodologyto where they now live.#73 checklist
ClaimVocabulary; a descriptor is required withOTHERunspecified — all rights reservedunspecified — all rights reserved. Not done: licence terms as structured fields (permitted uses, prohibitions, attribution, fees). That is story EX-2, in the story map's Layer 3 (exchange and discovery: publishing data and its usage terms for others to reuse), which the Work Packages say to test with data owners before building. The MVP's source records state no licence terms to model.rfs:unless an existing term fits (dcterms:type,dcterms:format,dcterms:license,dcterms:issued,schema:startDate/endDate,schema:addressCountry,qudt:QuantityValue,qudt:value,qudt:hasUnit,prov:wasGeneratedBy)C06Claim.yamlc06-mvp-claim.jsonldwith synthetic valuesValidation
Run locally with the pinned toolchain (
requirements.txt: linkml 1.11.1, Python 3.10):make -C schema lintmake -C schema check-claim-examplesmake -C schema gen-rdfmake -C schema gen-docNot run:
update-graph(needs a graph store), the site build, and a graph comparison of the existing fixtures' RDF against the base branch. The project fixtures' quantity triples change by design (seeQuantityValueabove).Known limitations
uriorcurieslot to an enum in a subclass: the generated Python model of the base class rejects the value. SoRegistryReviewAttestation.outcomeaccepts any IRI, andRegistryReviewOutcomedocuments the vocabulary.OTHERmust describe it. This is a LinkML rule, which the generated JSON Schema enforces. LinkML's SHACL generator does not translate it (linkml/linkml#2464): 1.11.1 ignores rules, and the unreleased rule support (linkml/linkml#3451) covers other patterns. SHACL itself can express it withsh:or. The other two conditional rules, evidence on a finding (CS-3) and a scope that names its subjects (AD-1), are modelled as a subclass and a required slot, which both validators enforce.appliesTo,project,cohort,site). A typed node of aClaimSubjectsubclass fails the generatedsh:classcheck unless the validator is given the class hierarchy.gen-rdf's playground JSON-LD does not match its Turtle.gen-rdf's playground.jsonldoutput writes everyuriorcurievalue, units andwasRevisionOfincluded, as anxsd:anyURIliteral, while its.ttlhas IRIs, becauselinkml-convertbuilds its own context without--xsd-anyuri-as-iri. Those files are gitignored andupdate-graphpushes only.ttl; WP1-07 — Generate and version schema artifacts and validation examples #74 will build them with the published context and check them against the Turtle. A richer quantity structure (uncertainty, rate denominators) is open (Claim model gaps found when applied outside ecology (research-literature test) #86).wasAssociatedWithnames anEntity, which has no identifier until feat(Entity): add optional rid identifier slot #58, so an activity's operator is a node with a name and type and cannot be joined across activities.🤖 Generated with Claude Code