Skip to content

Latest commit

 

History

History
58 lines (47 loc) · 5 KB

File metadata and controls

58 lines (47 loc) · 5 KB

Architecture

owl-sop-enforcement-gate is a small, single-chokepoint gate over an ontology/config edit. The novel part is the ordering of four governance checks behind one mode switch, with the two heavy checks pulled out as injectable, degrade-open seams — not any single check.

Module map

Module Responsibility
owl_sop_enforcement_gate/gate.py OntologyEditGate (the chokepoint): evaluate() (pure verdict) + enforce() (mode-aware action) + GateMode + GateBlocked + detect_mutation_type / is_ontology_path + the main() hook entry point.
owl_sop_enforcement_gate/decision.py GateDecision — the frozen verdict value returned by evaluate().
owl_sop_enforcement_gate/seams.py The injectable seams + reference impls: ShaclCheck / reference_shacl_check, PhaseCheck / reference_phase_check, ShaclResult, and the inline is_substantive_verbatim.
owl_sop_enforcement_gate/couplings.py Best-effort, never-hard-import couplings: try_emit_event (advisor event), try_substance_check (external linter).
owl_sop_enforcement_gate/__init__.py Public API surface.
examples/ontology/ A tiny generic ontology (core.ttl), one SHACL shape (core.shacl.ttl), one SPARQL competency question (competency_question.rq).

The evaluation flow (the hot path)

evaluate(file_path, verbatim_response?, responsible_owner?, change_set_id, mutation_type?)
   │
   ├─ mutation_type = explicit OR detect_mutation_type(file_path)
   │        └─ None (not a gated surface) ⇒ GateDecision(allowed=True)  ── no-op edit
   │
   ├─ Finding 1: ontology edit? ─ shacl_check(data, shapes) ─┐
   │        "violations" ⇒ BLOCK reason (+count)             │  "skipped"/"error" ⇒ degrade open
   │
   ├─ Finding 2: verbatim present? ── no ⇒ BLOCK reason ─────┤
   ├─ Finding 3: verbatim substantive? ── no ⇒ BLOCK reason ─┤   (≥50 non-ws chars; inline floor)
   ├─ Finding 2b: owner-gated mutation w/o owner ⇒ BLOCK ────┤
   ├─ Finding 4: phase_check(cs, mut) ⇒ (ok, missing) ───────┤   broken seam ⇒ degrade open
   │        not ok ⇒ BLOCK reason (+missing phases)          │
   │                                                         │
   └────────────────────────────► GateDecision(allowed = no reasons, ...) ◄┘

enforce(...) = evaluate(...) then, by mode:
   advisory ⇒ warn(stderr) + ALLOW   |   enforce ⇒ raise GateBlocked   |   override ⇒ log(stderr) + ALLOW

Two invariants make this a gate rather than a linter: the verdict is a pure value (evaluate never raises or exits — only enforce acts, and only it knows the mode), and BLOCK is reserved for a real finding (a degraded SHACL/phase seam allows, it never blocks on its own absence).

Seams (injection points)

Seam How to use it
shacl_check(data_path, shapes_path) -> ShaclResult Plug in a SHACL toolkit / pyshacl. Return an object with .status ("ok"/"violations"/"skipped"/"error") and, on violations, .violation_count / .detail. Defaults to the lazy, degrade-open reference_shacl_check.
phase_check(change_set_id, mutation_type) -> (ok, missing) Plug in a governance phase tracker that maps a mutation to its prerequisite steps and checks each for completion. Defaults to the degrade-open reference_phase_check (all complete).
mutation_detector(file_path) -> mutation_type | None Override the path→mutation mapping when your surfaces are richer than .ttl/.json.
substance_check(text) -> bool Override the inline verbatim-substance floor.
owner_required_mutations The mutation types that additionally require a responsible_owner.
event_sink(kind, detail) -> None An advisor/notification sink for edit_allowed / edit_blocked / edit_overridden events. Best-effort; missing is a no-op.

Design invariants

  • The verdict is separate from the action. evaluate() is a pure, side-effect-free function of its inputs; enforce() is the only thing that warns, raises, or overrides — so the gate is unit-testable in-process without sys.exit.
  • BLOCK requires a real finding. A SHACL seam with no validator returns "skipped"; a broken phase seam is caught and treated as complete. The gate never blocks merely because a heavy dependency is absent.
  • Structural validity precedes metadata. SHACL non-conformance on an ontology edit is checked first — a structurally-invalid graph is rejected regardless of how complete the sign-off metadata is.
  • Override is documented and loud. A bypass (env OSEG_OVERRIDE=1 or override=True) always prints its reason to stderr and emits an edit_overridden event; it is never silent.
  • Offline-exercisable. Zero third-party deps for the gate; the full flow (including the bundled reference SHACL seam's "skipped" path) runs on a bare Python 3.9 — see the tests.