Skip to content

pv-contract extractor: no per-entity-type class, so a SHACL shape cannot target one entity type — targetClass ont:Contract selects every contract (apex EV-19b) #4160

Closed

Description

@noahgift

Consumer: apex, APEX-001 row EV-19b (paiml/apex#143, #144). This is the §7.12 deletion of apex's local closed-world checker apex-ont, which the operator scheduled on 2026-09-24. Filed under apex's directive G: apex pulls and upstream owns, so apex may not route around this locally.

The gap, measured on the published aprender-contracts 0.69.1 and unchanged on origin/main

A SHACL shape cannot be scoped to one entity type. The pv-contract extractor types every contract node the same way, and records the entity type only as a literal:

  • crates/aprender-contracts/src/ontology/extract/pv_contract.rs:65-66: rdf:type ont:Contract and rdf:type prov:Entity, for every contract.
  • :87: ont:entityType "<type>" is a string literal, not a class.
  • shapes.rs: targetClass is the only target form; targetNode, targetSubjectsOf and targetObjectsOf are refused.

So the only target that reaches an apex contract is targetClass: ont:Contract, which selects every contract. apex has two closed shapes over two entity types: study-shape-v1 (entity type study, 9 degree-of-freedom predicates) and the per-row claim shape (the 18 contracts/work/PMAT-*.yaml). Measured with every apex contract converted to targetClass: ont:Contract and study:/claim: paths:

  • pv lint contracts --gate shapes gives focus_nodes_n: 19.
  • The study shape fails every claim contract, for example ont:contract/PMAT-001 violates shape study-shape-v1 (closed): carries ont:claim/row … and (minCount): has 0 value(s) of ont:study/scale.
  • The claim shape fails the study in the same way.

With a single contract in the directory, the same study shape gives Pass. A planted scale: quadratic gives Fail (in), and a planted tenth key gives Fail (closed). So the closed-world validator itself does what apex needs; only the scoping is missing.

What is asked

A way for a shape to select only the contracts whose entity.type is T. The smallest option is probably for the pv-contract extractor to also emit a class per entity type, for example rdf:type ont:entity/<type> (the spelling is upstream's choice), so that targetClass: ont:entity/study selects exactly the study contracts. Then:

  1. A shape with that targetClass has focus nodes = the contracts of that type, and nothing else.
  2. There is an accept-level test upstream with two entity types, two closed shapes, and no cross-firing.

Related: #3567 (the fleet pv pin), and #3530 (the entity.properties → <entityType>:<key> predicates apex relies on).

Activity

  1. added this to the 0.70.0 milestone on Sep 24, 2026
  2. noahgift commented on Sep 24, 2026

    @noahgift
    MemberAuthor

    Cop ruling (aprender-cf): milestone 0.70.0 (ONT-001 must finish in .70; this blocks apex EV-19b / apex-ont deletion). Owner: aprender-75 (ONT stack). Scope: extractor emits a per-entity-type class alongside ont:Contract so targetClass: ont:entity/<type> selects one type; acceptance = apex's study shape over ALL apex contracts passes the study contract and does not fire on the 18 claim contracts, plus a planted wrong-type contract that must Fail.

  3. added
    kind:codeWork is a code change (derived rule, #4159)
    on Sep 24, 2026
  4. added a commit that references this issue on Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    apex-upstreamUpstream change an apex milestone waits onkind:codeWork is a code change (derived rule, #4159)

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions