Validation (Yew)

A policy can be checked against ODRL profiles. The result is a Report with a verdict and findings. OdrlProse can show it under the sentences, OdrlProseView can mark it at the slots it concerns, and ProseProblems lists it with a way to jump to each finding and apply each fix.

A verdict of Incomplete is never a pass. It means no error was found but something could not be checked, such as a declared profile that is not loaded.

Profiles, options and the validator #

A Wording holds the loaded profiles. A Validator pairs a wording with Options.

Report has mode, verdict, findings and gaps, and is #[non_exhaustive]. Verdict is Conforms, Violations or Incomplete, also #[non_exhaustive]. Always match with a wildcard arm.

Findings under the sentences #

OdrlProse writes a section.prose-violations after the policies when it has a validator and violations is true. With a validator and violations left false, nothing changes in the output, and with violations and no validator, there is nothing to show.

#[function_component(ReaderWithViolations)]
fn reader_with_violations() -> Html {
    let wording = Rc::new(Wording::new());
    let validator = Validator::new(Arc::new((*wording).clone()), Options::strict());
    html! {
        <OdrlProse json={POLICY} wording={Some(SharedWording(wording))}
                   validator={Some(validator)} violations={true} />
    }
}

From prose-yew/tests/site_examples.rs, region reader_violations.

The panel below is the output the repository pins for a policy that breaks a closed research profile: prose-yew/tests/snapshots/strict_read_violations.html, produced by ssr_strict.rs. It is styled by the example stylesheet.

Agreement urn:policy:violating

An agreement between hospital (assigner) and university (assignee).

  • Written to the profile Research Data Profile (https://example.org/odrl/profile/research, version 0.1.0).
  1. university may fine-tune cohort-2026, as permitted by the assigner hospital.

    Limits on the action:

    • The action "fine-tune" is limited to cases where:
      • the number of data subjects is at least "ten"

    Applies only if:

    • the research purpose is at most academic research
  2. university may distil cohort-2026, as permitted by the assigner hospital.

  3. university may bar cohort-2026, as permitted by the assigner hospital.

Terms from the profile
Fine-tune ex:fineTune
To adapt an already trained model using the Asset.
Usage: Fine-tuning implies that the Asset may be read.
A kind of: Train
Implies: read
From Research Data Profile
Number of data subjects ex:dataSubjectCount
The number of distinct data subjects represented in a result derived from the Asset. Right operand value MUST be an xsd:integer.
Usage: Only the gteq and gt operators SHOULD be used. Small counts risk re-identification.
From Research Data Profile
Research purpose ex:researchPurpose
The research purpose the action of the Rule is exercised for.
A kind of: purpose
From Research Data Profile
Academic research ex:academic
Research carried out by an accredited academic institution with no commercial sponsor.
From Research Data Profile

Does not conform

  • prose.datatype-lexical "ten" is not an integer, which the profile expects for "ex:dataSubjectCount"
  • prose.operator-not-allowed the profile allows only the operators eq, isAnyOf or isNoneOf for "ex:researchPurpose"
  • profile.undeclared-in-namespace the action "ex:distil" is not declared by the loaded profile <https://example.org/odrl/profile/research>
  • profile.unknown-term the action "foo:bar" is not defined by ODRL or by a loaded profile

The status line exists only for a strict report. Its class and words come from the verdict:

VerdictClassWords (Labels field)
Verdict::Conformsprose-conformsstatus_conforms
Verdict::Incompleteprose-incompletestatus_incomplete
any other verdictprose-violations-foundstatus_violations

A verdict this version does not know is shown as a failure, not as a pass.

The strict editor #

EditConfig::with_wording loads the profiles into the editor, and with_strict(Options::strict()) validates against them and makes the add buttons create admissible values. use_prose_editor_with takes the validator and a StrictEdit policy, and use_validation gives the report.

#[function_component(Strict)]
fn strict() -> Html {
    let cfg = Rc::new(
        EditConfig::default()
            .with_wording(Rc::new(Wording::new()))
            .with_strict(Options::strict()),
    );
    let with = use_prose_editor_with(
        || read_model(POLICY).unwrap_or_default(),
        Rc::new(cfg.rules.clone()),
        cfg.validator.clone(),
        StrictEdit::Flag,
    );
    let report = use_validation(&with.editor.doc, cfg.validator.as_ref());
    html! {
        <>
            <OdrlProseView doc={with.editor.doc.clone()} mode={EditMode::Edit} config={cfg}
                           onedit={with.editor.onedit.clone()}
                           refusal={with.refused.as_ref().and_then(|(ev, err)| err.issue(ev))} />
            <ProseProblems report={report} onfix={with.apply_all.clone()} />
        </>
    }
}

From prose-yew/tests/site_examples.rs, region strict.

Pass the hook Rc::new(cfg.rules.clone()) and cfg.validator.clone() as the example does. The reducer applies the rules it is handed, not the config's.

StrictEdit::Flag, the default, commits every edit the rules allow and lets the validator mark a violation. StrictEdit::RefuseTerms makes the reducer refuse a term outside the profile written into a vocabulary slot, as EditError::OutsideProfile. Show the refusal with refusal={with.refused.as_ref().and_then(|(ev, err)| err.issue(ev))}.

Under a closed profile, a vocabulary slot is a closed combobox and takes only what the validator admits. Enter on text that names nothing admissible keeps the draft in the slot, with the reason and the nearest term. Escape reverts it. When focus leaves the slot, the draft is given up: the slot goes back to its value and a polite live region says so. So text typed into a closed combobox can be lost, with StrictEdit::Flag too. A closed slot has data-closed="true". The operator select groups its options into those the profile allows and those it does not.

The problems panel #

ProseProblems groups the findings by rule, in document order. Each finding has a "Go to" button and one button for each fix. A fix is a list of events: give onfix the apply_all of the hook, which applies them as one step with one undo entry. The events carry expect ids, so a fix from a report the document has moved on from is refused as stale.

onjump receives the IssueTarget of the finding. The host moves focus to the [data-slot] or [data-node] element of the view that holds that path. After a fix removes the focused button, focus moves to the panel heading if it fell to the page body.

The classes of the panel are on the CSS hooks page. The demo, demo/src/edit.rs, shows a complete host with issues, onjump and an undo button.