diff --git a/.gitignore b/.gitignore index e30e616..bb19a89 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ code/bin/ code/lib/ code/include */__pycache__ +/.idea/LNKD.tech Editor.xml diff --git a/dprod-contracts/README.md b/dprod-contracts/README.md new file mode 100644 index 0000000..ac74868 --- /dev/null +++ b/dprod-contracts/README.md @@ -0,0 +1,159 @@ +# DPROD Data Contracts: Deterministic Policy Language for Data Governance + +**An ODRL 2.2 profile with deterministic evaluation semantics for data governance.** + +--- + +## What This Is + +DPROD Contracts is an ODRL 2.2 profile. It uses ODRL terms for all standard constructs (Permission, Duty, Prohibition, Agreement, etc.) and only adds extensions where ODRL 2.2 leaves behavior undefined: + +1. **Explicit lifecycle**: Pending -> Active -> Fulfilled/Violated (unified for duties and contracts) +2. **Bilateral agreements**: Both assigner and assignee may have duties +3. **Deterministic evaluation**: Total functions, no undefined states +4. **Formal verification target**: Amenable to Dafny, Why3, Coq +5. **Structured operand resolution**: SHACL-style `dprod:path` property paths +6. **Recurring duties**: `recurrence` via RFC 5545 RRULE for scheduled obligations + +DPROD Contracts is **specification-first**. The semantics document defines what any conformant implementation must do. Every DPROD policy is a valid ODRL 2.2 policy. + +--- + +## Quick Start + +See [examples/](examples/) for complete working policies: + +- [data-contract.ttl](examples/data-contract.ttl) -- DataContract, Subscription, bilateral duties +- [data-use-policy.ttl](examples/data-use-policy.ttl) -- Role-based access, purpose constraints + +--- + +## What DPROD Contracts Adds to ODRL 2.2 + +| Extension | ODRL 2.2 | What DPROD Adds | +|-----------|----------|-----------------| +| Duty lifecycle | Undefined | Pending -> Active -> Fulfilled/Violated | +| Bilateral duties | Unilateral (assignee only) | Assigner duties + assignee duties | +| Conflict resolution | Configurable | Fixed: Prohibition > Permission | +| Evaluation order | Undefined | Deterministic left-to-right | +| Operand resolution | Implicit | Explicit `dprod:path` property paths (+ `dprod:select` for complex resolution) | +| Recurring duties | -- | `recurrence` via RFC 5545 RRULE with per-instance `deadline` | +| Contract types | -- | `DataContract` (subclass of Offer), `Subscription` (subclass of Agreement) | + +**Note**: DPROD Contracts is an ODRL profile, not a parallel vocabulary. Standard ODRL processors can parse DPROD policies; DPROD-aware processors additionally enforce lifecycle, bilateral duties, and deterministic evaluation. + +--- + +## Design Principles + +### 1. Specification Precedes Implementation + +The [formal semantics](docs/formal-semantics.md) is the normative reference. + +### 2. Total Functions + +Every evaluation terminates with a defined result: + +``` +Eval : Request x PolicySet x State -> Decision x DutySet +``` + +### 3. Bilateral Agreements + +Agreements return duties for **both** parties: + +``` +Result = { + decision: Permit | Deny | NotApplicable, + assignerDuties: Set, // Provider obligations (SLAs) + assigneeDuties: Set, // Consumer obligations + violations: Set +} +``` + +### 4. Unified Lifecycle State + +Duties and contracts share four states: + +``` + condition true +Pending ──────────────> Active + │ │ + action done │ │ deadline passed + ▼ ▼ + Fulfilled Violated +``` + +An `odrl:Duty` progresses through `dprod:State` values. A `dprod:DataContract` shares the same state machine. + +### 5. Structured Operand Resolution + +Operands resolve via `dprod:path` -- SHACL-style property paths from the evaluation context: + +```turtle +# Context-rooted (single-step): direct property on request +dprod:environment dprod:path dprod:environment . + +# Asset-rooted (two-step): via odrl:target +dprod:timeliness dprod:path (odrl:target dprod:timeliness) . + +# Agent-rooted (two-step): via odrl:assignee +dprod:recipientType dprod:select "SELECT ?v WHERE { $request odrl:assignee/dprod:recipientType ?v }" . +``` + +--- + +## Repository Structure + +``` +dprod-contracts/ +├── dprod-contracts.ttl # Core ontology (ODRL profile extension) +├── dprod-contracts-shapes.ttl # SHACL validation shapes +├── dprod-contracts-prof.ttl # DXPROF profile declaration +├── examples/ +│ ├── data-contract.ttl # Complete contract example (with recurrence) +│ ├── data-use-policy.ttl # Access control example +│ └── baseline.ttl # Comprehensive test data (8 contracts, 2 subscriptions) +└── docs/ + ├── overview.md # What is DPROD Contracts? (start here) + ├── specification.md # Technical vocabulary reference + ├── term-mapping.md # Business term -> property mapping + DCON migration + ├── formal-semantics.md # Formal semantics (normative) + ├── contracts-guide.md # Data contract authoring guide + └── policy-writers-guide.md # Data use policy authoring guide +``` + + +--- + +## Namespaces + +| Prefix | Namespace | Role | +|--------|-----------|------| +| `odrl:` | `http://www.w3.org/ns/odrl/2/` | Primary -- all standard constructs | +| `dprod:` | `https://ekgf.github.io/dprod/` | Extensions (State, deadline, recurrence, DataContract, Subscription, path, select, hierarchy) + domain-specific actions, operands, and concept values | + +--- + +## Conformance + +An implementation conforms to DPROD Contracts if: + +1. It accepts policies that validate against `dprod-contracts-shapes.ttl` +2. It uses `odrl:Permission`, `odrl:Duty`, `odrl:Prohibition`, `odrl:Agreement` for standard constructs +3. Its evaluation function produces identical results for identical inputs +4. All functions are total (no undefined behavior) +5. State transitions match the operational semantics +6. Agreement evaluation returns duties for both assigner and assignee + +--- + +## References + +- [ODRL 2.2 Information Model](https://www.w3.org/TR/odrl-model/) +- [W3C Market Data Profile](https://www.w3.org/2021/md-odrl-profile/v1/) +- [W3C ODRL Profile Best Practices](https://www.w3.org/community/reports/odrl/CG-FINAL-profile-bp-20240808.html) + +--- + +**Version**: 0.7 | **Date**: 2026-02-04 diff --git a/dprod-contracts/docs/contracts-guide.md b/dprod-contracts/docs/contracts-guide.md new file mode 100644 index 0000000..e4a8081 --- /dev/null +++ b/dprod-contracts/docs/contracts-guide.md @@ -0,0 +1,574 @@ +# DPROD Contracts Guide + +A guide for data platform teams using DPROD for data contracts and subscriptions. + +--- + +## Overview + +DPROD models internal data sharing agreements as ODRL 2.2 policies. A **DataContract** is an offer from a data provider. A **Subscription** is an activated contract binding provider and consumer. + +``` +DataContract (Offer) Subscription (Agreement) ++--------------------------+ +--------------------------+ +| Provider duties | | Provider duties | +| Consumer rights | | Consumer rights | +| Prohibitions | | Consumer duties | +| Recurrence rules | | Prohibitions | ++--------------------------+ | State tracking | + accept +--------------------------+ + --------> +``` + +--- + +## Key Concepts + +### DataContract (Offer) + +A `dprod:DataContract` is a subclass of `odrl:Offer`. It specifies: + +- **Provider** (`odrl:assigner`): the data team providing data +- **Target** (`odrl:target`): the data asset(s) covered -- inherited by rules unless overridden +- **Provider duties** (`odrl:obligation` with `dprod:subject` = provider): SLAs like delivery, notification, schema conformance +- **Consumer permissions** (`odrl:permission`): what consumers can do with the data +- **Consumer duties** (`odrl:obligation` without subject in Offer): obligations consumers accept upon subscribing +- **Prohibitions** (`odrl:prohibition`): what consumers cannot do + +### Subscription (Agreement) + +A `dprod:Subscription` is a subclass of `odrl:Agreement`. It adds: + +- **Consumer** (`odrl:assignee`): the subscribing team +- **Effective/expiration dates**: contract period +- **State tracking**: lifecycle state on duties and the subscription itself + +### Provider Duties + +Provider duties use DPROD actions: + +| Action | Description | Example | +|--------|-------------|---------| +| `dprod:deliver` | Deliver data to consumers | Daily market data delivery | +| `dprod:notify` | Send notifications | Schema change notification | +| `dprod:conformTo` | Maintain conformance to a standard | Schema/quality SLA | + +### Consumer Duties + +| Action | Description | Example | +|--------|-------------|---------| +| `dprod:report` | Submit usage reports | Monthly usage reporting | + +### Permissions + +Standard ODRL actions apply: + +| Action | Description | +|--------|-------------| +| `odrl:display` | Display data | +| `dprod:nonDisplay` | Non-display (algorithmic) use | +| `odrl:derive` | Create derived products | +| `odrl:read` | Read data | + +--- + +## Step-by-Step Cookbook + +Create your first DataContract in five steps. + +### Step 1: Declare the Contract + +Every contract starts with a type, profile declaration, and provider identity. + +```turtle +@prefix odrl: . +@prefix dprod: . +@prefix xsd: . + +ex:contract a dprod:DataContract ; + odrl:profile ; + odrl:assigner ex:dataTeam ; + odrl:target ex:marketPrices ; + dprod:state dprod:Active . +``` + +### Step 2: Add Provider Duties (SLAs) + +Provider duties declare what the data team commits to. The provider is identified by `dprod:subject` on each duty. Use `dprod:object` to identify who is affected (e.g., who receives notifications). + +Rules inherit `odrl:target` from the policy unless they target a different asset. + +```turtle + # Daily delivery by 06:30 (target inherited from policy) + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:deliver ; + dprod:recurrence "FREQ=DAILY;BYHOUR=6;BYMINUTE=0" ; + dprod:deadline "PT30M"^^xsd:duration + ] ; + + # Schema conformance (different target -- not inherited) + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:marketDataSchema + ] ; +``` + +### Step 3: Add Consumer Permissions + +Permissions define what subscribers can do. In an Offer, omit `odrl:assignee` -- it is filled when the subscription is created. Target is inherited from the policy. + +```turtle + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:display + ] ; + + odrl:permission [ + a odrl:Permission ; + odrl:action dprod:nonDisplay ; + odrl:constraint [ + a odrl:Constraint ; + odrl:leftOperand dprod:recipientType ; + odrl:operator odrl:eq ; + odrl:rightOperand dprod:internal + ] + ] ; +``` + +### Step 4: Add Consumer Duties and Prohibitions + +Consumer duties activate upon subscription. Prohibitions apply to all subscribers. + +```turtle + # Consumer must report usage monthly (different target -- not inherited) + odrl:obligation [ + a odrl:Duty ; + odrl:action dprod:report ; + odrl:target ex:usageStats ; + dprod:deadline "P30D"^^xsd:duration + ] ; + + # No external redistribution (target inherited from policy) + odrl:prohibition [ + a odrl:Prohibition ; + odrl:action odrl:distribute + ] . +``` + +### Step 5: Create a Subscription + +When a consumer accepts the contract, create a Subscription (Agreement) referencing the contract: + +```turtle +ex:subscription a dprod:Subscription ; + odrl:profile ; + dprod:subscribesTo ex:contract ; + odrl:assigner ex:dataTeam ; + odrl:assignee ex:analyticsTeam ; + dprod:effectiveDate "2026-02-01T00:00:00Z"^^xsd:dateTime ; + dprod:expirationDate "2026-12-31T23:59:59Z"^^xsd:dateTime . +``` + +The subscription materializes all duties from the contract with explicit `dprod:subject` on each. + +--- + +## Provider Duty Patterns + +### Timeliness Pattern (Delivery SLA) + +Scheduled data delivery with a fulfillment window. Target inherited from policy. + +```turtle +odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:deliver ; + dprod:recurrence "FREQ=DAILY;BYHOUR=6;BYMINUTE=0" ; + dprod:deadline "PT30M"^^xsd:duration +] . +``` + +**DCON equivalent**: `ProviderTimelinessPromise` + +### Schema Pattern (Schema Conformance) + +Provider guarantees data conforms to a published schema. Target differs from policy -- specify explicitly. + +```turtle +odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:marketDataSchema +] . +``` + +**DCON equivalent**: `ProviderSchemaPromise` + +### Notification Pattern (Change Notification) + +Provider must notify consumers before making changes, with a lead time expressed as a duration deadline. Use `dprod:object` to identify who is notified. + +```turtle +odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + dprod:object ex:consumer ; + odrl:action dprod:notify ; + odrl:target ex:schemaChanges ; + dprod:deadline "P14D"^^xsd:duration +] . +``` + +**DCON equivalent**: `ProviderChangeNotificationPromise` + +### Quality SLA Pattern + +Provider guarantees data quality via `conformTo` with a constraint. This replaces DCON's `ProviderQualityPromise`. + +```turtle +odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:riskMetricsSchema ; + odrl:constraint [ + a odrl:Constraint ; + odrl:leftOperand dprod:timeliness ; + odrl:operator odrl:eq ; + odrl:rightOperand dprod:realtime + ] +] . +``` + +The constraint can check any DPROD operand -- timeliness, classification, environment, etc. + +--- + +## Recurrence + +Recurring duties use `dprod:recurrence` -- an RFC 5545 RRULE string. Combined with `dprod:deadline`, this defines a schedule and fulfillment window. + +```turtle +odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:deliver ; + dprod:recurrence "FREQ=DAILY;BYHOUR=6;BYMINUTE=0" ; + dprod:deadline "PT30M"^^xsd:duration +] . +``` + +This means: deliver market prices daily at 06:00 (target inherited from policy), with a 30-minute window to fulfill. + +### Common RRULE Patterns + +| Pattern | RRULE | +|---------|-------| +| Daily at 06:00 | `FREQ=DAILY;BYHOUR=6;BYMINUTE=0` | +| Weekly on Monday | `FREQ=WEEKLY;BYDAY=MO` | +| Monthly on the 1st | `FREQ=MONTHLY;BYMONTHDAY=1` | +| Every 15 minutes | `FREQ=MINUTELY;INTERVAL=15` | +| Hourly | `FREQ=HOURLY` | + +Each generated instance follows the standard duty lifecycle independently (Pending -> Active -> Fulfilled/Violated). + +--- + +## Common Patterns Quick Reference + +### Simple File Drop + +Read-only access, no recurrence, no consumer duties. Target inherited from policy. + +```turtle +ex:contract a dprod:DataContract ; + odrl:profile ; + odrl:assigner ex:dataTeam ; + odrl:target ex:referenceData ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read + ] ; + odrl:prohibition [ + a odrl:Prohibition ; + odrl:action odrl:modify + ] . +``` + +### API with SLA + +Daily delivery, schema conformance, display + non-display, monthly reporting. Target inherited from policy unless overridden. + +```turtle +ex:contract a dprod:DataContract ; + odrl:profile ; + odrl:assigner ex:dataTeam ; + odrl:target ex:customerData ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:deliver ; + dprod:recurrence "FREQ=DAILY;BYHOUR=7;BYMINUTE=0" ; + dprod:deadline "PT30M"^^xsd:duration + ] ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:customerSchema + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:display + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action dprod:nonDisplay + ] ; + odrl:obligation [ + a odrl:Duty ; + odrl:action dprod:report ; + odrl:target ex:usageStats ; + dprod:deadline "P30D"^^xsd:duration + ] ; + odrl:prohibition [ + a odrl:Prohibition ; + odrl:action odrl:distribute + ] . +``` + +### Mission-Critical Service + +High-frequency delivery with quality SLA and change notification. Target inherited from policy unless overridden. + +```turtle +ex:contract a dprod:DataContract ; + odrl:profile ; + odrl:assigner ex:dataTeam ; + odrl:target ex:riskMetrics ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:deliver ; + dprod:recurrence "FREQ=MINUTELY;INTERVAL=1" ; + dprod:deadline "PT30S"^^xsd:duration + ] ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:riskSchema ; + odrl:constraint [ + a odrl:Constraint ; + odrl:leftOperand dprod:timeliness ; + odrl:operator odrl:eq ; + odrl:rightOperand dprod:realtime + ] + ] ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:notify ; + odrl:target ex:schemaChanges ; + dprod:deadline "P14D"^^xsd:duration + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:display + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action dprod:nonDisplay + ] . +``` + +### Multi-Dataset Contract + +A single contract covering multiple targets. When a policy has multiple targets, rules must specify their target explicitly -- inheritance is ambiguous. + +```turtle +ex:contract a dprod:DataContract ; + odrl:profile ; + odrl:assigner ex:dataTeam ; + odrl:target ex:marketPrices , ex:referenceData , ex:riskMetrics ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read ; + odrl:target ex:marketPrices + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read ; + odrl:target ex:referenceData + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read ; + odrl:target ex:riskMetrics + ] . +``` + +--- + +## Advanced Topics + +### Target Inheritance + +`odrl:target` at the policy level is inherited by rules that don't declare their own target. This reduces redundancy: + +```turtle +ex:contract a dprod:DataContract ; + odrl:target ex:marketPrices ; # policy-level target + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read # inherits ex:marketPrices + ] ; + odrl:obligation [ + a odrl:Duty ; + dprod:subject ex:dataTeam ; + odrl:action dprod:conformTo ; + odrl:target ex:marketDataSchema # different target -- explicit + ] . +``` + +**Rules**: +- Single-target policy: rules inherit the target unless they specify a different one +- Multi-target policy: rules must specify their target (inheritance is ambiguous) +- Named duty instances (standalone): always specify their target + +### Multi-Asset Contracts + +A contract can cover multiple targets. When multiple targets exist, each rule must specify its own target (inheritance is ambiguous): + +```turtle +ex:contract odrl:target ex:asset1 , ex:asset2 ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:read ; + odrl:target ex:asset1 + ] ; + odrl:permission [ + a odrl:Permission ; + odrl:action odrl:display ; + odrl:target ex:asset2 + ] . +``` + +### Team Delegation + +Use `dprod:memberOf` to model team hierarchies. A permission granted to a team applies to its members via hierarchy subsumption during evaluation: + +```turtle +ex:analyst a odrl:Party ; + dprod:memberOf ex:analyticsTeam . + +ex:analyticsTeam a odrl:Party ; + dprod:memberOf ex:tradingDivision . +``` + +### Version Chains + +Use `prov:wasRevisionOf` to link contract versions: + +```turtle +ex:contract-v2 a dprod:DataContract ; + prov:wasRevisionOf ex:contract-v1 . + +ex:contract-v3 a dprod:DataContract ; + prov:wasRevisionOf ex:contract-v2 . +``` + +Subscriptions reference the specific contract version they activate: + +```turtle +ex:subscription dprod:subscribesTo ex:contract-v2 . +``` + +### Expiration + +Contracts and subscriptions can have explicit expiration dates: + +```turtle +ex:subscription a dprod:Subscription ; + dprod:effectiveDate "2026-01-15T00:00:00Z"^^xsd:dateTime ; + dprod:expirationDate "2026-12-31T23:59:59Z"^^xsd:dateTime . +``` + +--- + +## Lifecycle + +Duties and contracts share four states: + +``` + condition true +Pending ──────────────> Active + | | + action done | | deadline passed + v v + Fulfilled Violated +``` + +- **Pending**: condition not yet met / not yet in force +- **Active**: condition met, action required / in force +- **Fulfilled**: action performed / obligations complete +- **Violated**: deadline passed / breached + +--- + +## Versioning + +Contracts can be versioned using `prov:wasRevisionOf`: + +```turtle +ex:contract-v2 a dprod:DataContract ; + prov:wasRevisionOf ex:contract-v1 . +``` + +Subscriptions reference the contract they activate via `dprod:subscribesTo`: + +```turtle +ex:subscription dprod:subscribesTo ex:contract-v2 . +``` + +--- + +## Complete Example + +See [examples/data-contract.ttl](../examples/data-contract.ttl) for a full working contract with bilateral duties, recurrence, schema conformance, and subscription. + +For comprehensive test data covering all patterns, see [examples/baseline.ttl](../examples/baseline.ttl). + +--- + +## DCON Migration + +If migrating from DCON, see [term-mapping.md](term-mapping.md) for complete property equivalents. + +--- + +## Validation Checklist + +1. Every policy declares `odrl:profile ` +2. Conflict strategy (`odrl:conflict odrl:prohibit`) is inherited from the profile -- do not repeat per-policy +3. DataContract has `odrl:assigner` (provider) +4. Subscription has both `odrl:assigner` and `odrl:assignee` +5. Subscription has `dprod:subscribesTo` referencing a DataContract +6. Each duty has exactly one `odrl:action` +7. Each permission and prohibition has exactly one `odrl:action` and one `odrl:target` +8. Provider duties have `dprod:subject` set to the provider +9. Deadlines use `xsd:dateTime` or `xsd:duration` +10. Recurrence uses a valid RFC 5545 RRULE starting with `FREQ=` +11. Constraints have `leftOperand`, `operator`, and `rightOperand` +12. LogicalConstraints use exactly one of `odrl:and`, `odrl:or`, or `dprod:not` +13. Validate against SHACL shapes: + +```bash +shacl validate --shapes dprod-contracts-shapes.ttl --data my-contract.ttl +``` diff --git a/dprod-contracts/docs/formal-semantics.md b/dprod-contracts/docs/formal-semantics.md new file mode 100644 index 0000000..c53b430 --- /dev/null +++ b/dprod-contracts/docs/formal-semantics.md @@ -0,0 +1,1106 @@ +--- +title: "DPROD Contracts Formal Semantics" +subtitle: "Deterministic Policy Evaluation for Data Governance" +version: "0.7" +status: "Draft" +date: 2026-02-03 +abstract: | + DPROD Contracts is a proper ODRL 2.2 profile with deterministic, total evaluation + semantics and bilateral agreement support. This document specifies the formal + semantics in a style amenable to mechanization in Dafny, Why3, or similar + verification frameworks. +--- + +## 1. Introduction + +DPROD Contracts addresses semantic gaps in ODRL 2.2: + +1. **Duty Ambiguity**: ODRL conflates pre-conditions with post-obligations +2. **Unilateral Agreements**: ODRL evaluates only from assignee perspective +3. **Undefined States**: ODRL permits evaluation to be "undefined" + +DPROD Contracts provides: + +- Explicit duty lifecycle with state machine semantics +- Bilateral agreement evaluation (grantor and grantee duties) +- Total evaluation functions (always terminate with defined result) +- Clear separation of Condition (pre-requisite) from Duty (obligation) +- Property-path-based operand resolution with SHACL-style traversal semantics + +### 1.1 Scope and Runtime Boundary + +This specification defines **evaluation semantics** — the contract a conformant engine +must satisfy. The `State` parameter in `Eval` is an opaque input provided by the +runtime environment. DPROD Contracts specifies what decision and state transitions *should* +result from evaluation, but does not define: + +- How `State` is persisted or managed between evaluations +- Event-driven triggers for duty activation or deadline enforcement +- Protocols for requirement fulfillment claims or re-evaluation + +These operational concerns are out of scope for a declarative policy profile. +Implementations requiring runtime state management, event processing, and enforcement +protocols should consult RL2, which extends DPROD Contracts's evaluation semantics with a +complete operational protocol layer. + +### 1.2 Notation + +- `×` for Cartesian product +- `→` for function types +- `∪` for union +- `∈` for set membership +- `⊥` for undefined/bottom value +- `⟦e⟧` for denotation of expression `e` +- `Γ ⊢ e : τ` for typing judgement ("in context Γ, expression e has type τ") + +### 1.2 Document Status + +This document is **normative** for DPROD Contracts implementations. + +--- + +## 2. Type System + +The type system ensures well-formed policies. + +### 2.1 Typing Judgements + +We use: + +``` +Γ ⊢ e : τ +``` + +Where Γ is a typing context mapping identifiers to types. + +### 2.2 Types + +``` +τ ::= Agent | Action | Asset | Condition | Time | Duration | Boolean | Value | Norm | State | Policy +``` + +### 2.3 Key Typing Rules + +Permission: + +``` +Γ ⊢ a : Agent Γ ⊢ x : Action Γ ⊢ s : Asset Γ ⊢ c : Condition +--------------------------------------------------------------------------- + Γ ⊢ Permission(a, x, s, c) : Norm +``` + +Duty: + +``` +Γ ⊢ a : Agent Γ ⊢ x : Action Γ ⊢ s : Asset +Γ ⊢ c : Condition Γ ⊢ dl : Deadline Γ ⊢ r : Recurrence +-------------------------------------------------------------------------- + Γ ⊢ Duty(a, x, s, c, dl, r) : Norm +``` + +Prohibition: + +``` +Γ ⊢ a : Agent Γ ⊢ x : Action Γ ⊢ s : Asset Γ ⊢ c : Condition +--------------------------------------------------------------------------- + Γ ⊢ Prohibition(a, x, s, c) : Norm +``` + +AtomicConstraint: + +``` +Γ ⊢ left : LeftOperand Γ ⊢ op : ComparisonOperator Γ ⊢ right : Value +------------------------------------------------------------------------------- + Γ ⊢ AtomicConstraint(left, op, right) : Condition +``` + +Logical connectives follow standard typing rules for Boolean-valued expressions. + +--- + +## 3. Abstract Syntax + +We define DPROD Contracts's abstract syntax using a typed algebraic grammar. + +### 3.1 Syntactic Domains + +| Domain | Symbol | Description | +|--------|--------|-------------| +| Agents | **A** | Set of agent identifiers | +| Actions | **X** | Set of action identifiers | +| Assets | **S** | Set of asset identifiers | +| Values | **V** | Set of atomic values (strings, numbers, URIs) | +| Time | **T** | Time domain (ISO 8601 instants) | +| Duration | **D** | Duration domain (ISO 8601 durations) | + +### 3.2 Norms + +``` +Norm ::= Permission(subject: Agent, action: Action, asset: Asset, condition: Condition?) + | Duty(subject: Agent, action: Action, asset: Asset, + object: Agent?, condition: Condition?, deadline: Deadline?, recurrence: Recurrence?) + | Prohibition(subject: Agent, action: Action, asset: Asset, condition: Condition?) + +Deadline ::= AbsoluteDeadline(time: Time) + | RelativeDeadline(duration: Duration) + +Recurrence ::= RRule(rule: String) +``` + +**Notes**: + +- `Permission` corresponds to `odrl:Permission`; `Prohibition` to `odrl:Prohibition`; `Duty` to `odrl:Duty`. +- The formal `subject` parameter maps to `dprod:subject` on duties (rdfs:subPropertyOf `odrl:assignee`) and to `odrl:assignee` on permissions/prohibitions. +- The formal `object` parameter (duties only) maps to `dprod:object` — the party affected by the duty action (e.g., who is notified). Not used in norm matching. +- `AbsoluteDeadline`: Fixed point in time (e.g., 2026-12-31T23:59:59Z) +- `RelativeDeadline`: Duration from activation (e.g., P30D, PT24H) + +**Abstract-to-RDF Name Mapping**: + +| Abstract Syntax | RDF Encoding | Notes | +|---|---|---| +| `Permission` | `odrl:Permission` | | +| `Duty` | `odrl:Duty` | | +| `Prohibition` | `odrl:Prohibition` | | +| `subject` (Permission/Prohibition) | `odrl:assignee` | Party to whom the norm applies | +| `subject` (Duty) | `dprod:subject` | Party bearing the duty (rdfs:subPropertyOf odrl:assignee) | +| `object` (Duty) | `dprod:object` | Party affected by the duty action (metadata, not used in matching) | +| `grantor` | `odrl:assigner` | Party granting rights | +| `grantee` | `odrl:assignee` | Party receiving rights (policy-level) | +| `condition` | `odrl:constraint` | | +| `Set` | `odrl:Set` | | +| `Offer` | `odrl:Offer` | `DataContract` is a subtype | +| `Agreement` | `odrl:Agreement` | `Subscription` is a subtype | +| `lte` | `odrl:lteq` | | +| `gte` | `odrl:gteq` | | +| `recurrence` | `dprod:recurrence` | RFC 5545 RRULE string | + +### 3.3 Conditions + +``` +Condition ::= AtomicConstraint(leftOperand: LeftOperand, + operator: ComparisonOperator, + rightOperand: Value) + | And(operands: Condition+) + | Or(operands: Condition+) + | Not(operand: Condition) + +ComparisonOperator ::= eq | neq | lt | lte | gt | gte | isAnyOf | isNoneOf + +RuntimeRef ::= currentAgent | currentDateTime +``` + +**Notes**: + +- `leftOperand` is drawn from profile-defined operands with `dprod:path`, or dual-typed `RuntimeReference` operands (e.g., `currentDateTime`) +- Dynamic value resolution on the left side uses `LeftOperand` with `dprod:path` (and optionally `dprod:select`) or dual-typed `RuntimeReference` operands resolved via `resolveRuntime` +- Right operands are literal values. Identity binding via runtime references in right-operand position is deferred to RL2 (`rl2:rightOperandRef`) + +### 3.4 Policies + +``` +Policy ::= Set(target: Asset?, clauses: Norm+, condition: Condition?) + | Offer(grantor: Agent, grantee: Agent?, target: Asset?, clauses: Norm+, condition: Condition?) + | Agreement(grantor: Agent, grantee: Agent, target: Asset?, clauses: Norm+, condition: Condition?) +``` + +**Notes**: + +- `Set`: Unilateral declaration, no parties. Maps to `odrl:Set` in the RDF encoding. +- `Offer`: Proposal from grantor, grantee optional (open offer). Maps to `odrl:Offer`. `DataContract` is a subtype of `Offer`. +- `Agreement`: Bilateral binding, both parties identified. Maps to `odrl:Agreement`. `Subscription` is a subtype of `Agreement`. +- The formal `grantor` parameter maps to `odrl:assigner` (the party granting rights) in the RDF encoding. +- The formal `grantee` parameter maps to `odrl:assignee` (the party receiving rights) in the RDF encoding. + +### 3.5 Requests + +``` +Request ::= Request(agent: Agent, action: Action, asset: Asset, context: Context) + +Context ::= Map +``` + +**Note**: Context properties correspond to the leaf of `dprod:path` declarations (e.g., `dprod:path odrl:purpose` resolves `?request odrl:purpose ?value`). + +--- + +## 4. Semantic Domains + +### 4.1 State + +``` +Σ = { + clock : Time, + state : Duty → State, + activatedAt : Duty → Time?, // When duty became Active + performed : Set<(Agent, Action, Asset, Time)> +} + +State ::= Pending | Active | Fulfilled | Violated +``` + +**Notes**: + +- `State` is a unified lifecycle enum shared by duties, contracts, and subscriptions. The formal semantics tracks duty state during evaluation; contract and subscription state is administrative (not evaluated at request time). +- Terminal states (`Fulfilled`, `Violated`) are permanent — see §9.4. + +**Initial state** Σ₀: + +``` +Σ₀ = { + clock = currentSystemTime, + state = λd. Pending, + activatedAt = λd. ⊥, + performed = ∅ +} +``` + +**State Update Notation**: We use `Σ[f ↦ v]` to denote state update: + +``` +Σ[state(d) ↦ Active] = + (Σ.clock, Σ.state[d ↦ Active], Σ.activatedAt, Σ.performed) + +Σ[state(d) ↦ Active, activatedAt(d) ↦ t] = + (Σ.clock, Σ.state[d ↦ Active], Σ.activatedAt[d ↦ t], Σ.performed) +``` + +### 4.2 Environment + +``` +Env = { + agent : Agent, // Canonical root: agent + action : Action, + asset : Asset, // Canonical root: asset + context : Context, // Canonical root: context + Σ : Σ +} +``` + +The evaluation context is the entry point for `dprod:path` property path traversal (see §6.3). + +**Environment Construction**: Given a Request `R = (a, x, s, ctx)` and state Σ: + +``` +buildEnv(R, Σ) = { + agent = R.agent, + action = R.action, + asset = R.asset, + context = R.context, + Σ = Σ +} +``` + +### 4.3 Decision + +``` +Decision ::= Permit | Deny | NotApplicable +``` + +### 4.4 Evaluation Result + +``` +Result = { + decision : Decision, + grantorDuties : Set, // Duties on the grantor (data provider) + granteeDuties : Set, // Duties on the grantee (data consumer) + violations : Set, + explanation : Explanation +} +``` + +--- + +## 5. Duty Lifecycle + +### 5.1 State Diagram + +``` + condition becomes true + ┌─────────────────────────────────────┐ + │ ▼ + ┌───────┐ ┌────────┐ + │Pending│ │ Active │ + └───────┘ └────────┘ + │ │ + action performed │ │ deadline exceeded + ▼ ▼ + ┌──────────┐ ┌─────────┐ + │Fulfilled │ │Violated │ + └──────────┘ └─────────┘ +``` + +### 5.2 Transition Rules + +**Rule D-ACTIVATE** (Pending → Active): + +``` +Σ.state(duty) = Pending +duty.condition = ⊥ ∨ ⟦duty.condition⟧(Env) = true +───────────────────────────────────────────────── +Σ' = Σ[state(duty) ↦ Active, activatedAt(duty) ↦ Σ.clock] +``` + +Activation is **condition-driven**: when the duty's condition first evaluates to true (or the duty has no condition), the duty becomes active. + +**Rule D-FULFILL** (Active → Fulfilled): + +``` +Σ.state(duty) = Active +performed(duty.subject, duty.action, duty.asset, Σ) = true +effectiveDeadline(duty, Σ) ≥ Σ.clock ∨ effectiveDeadline(duty, Σ) = ∞ +──────────────────────────────────────────────────────────────────────── +Σ' = Σ[state(duty) ↦ Fulfilled] +``` + +Fulfillment is **event-driven**: when a performed action matches the duty's required action (including narrower actions via `includedIn` subsumption), the duty is fulfilled. + +**Rule D-VIOLATE** (Active → Violated): + +``` +Σ.state(duty) = Active +Σ.clock > effectiveDeadline(duty, Σ) +performed(duty.subject, duty.action, duty.asset, Σ) = false +──────────────────────────────────────────────────────────── +Σ' = Σ[state(duty) ↦ Violated] +``` + +Violation is **time-driven**: when the deadline passes without fulfillment, the duty is violated. + +**Algorithmic form** (for implementation): + +``` +updateDutyStates(duties, Env, Σ) = + foldl(updateOneDuty(Env), Σ, duties) + +updateOneDuty(Env)(Σ, d) = + case Σ.state(d) of + Pending → if d.condition = ⊥ ∨ ⟦d.condition⟧(Env) + then Σ[state(d) ↦ Active, activatedAt(d) ↦ Σ.clock] + else Σ + Active → if performed(d.subject, d.action, d.asset, Σ) + then Σ[state(d) ↦ Fulfilled] + else if Σ.clock > effectiveDeadline(d, Σ) + then Σ[state(d) ↦ Violated] + else Σ + _ → Σ -- Fulfilled/Violated are terminal +``` + +### 5.3 Effective Deadline + +``` +effectiveDeadline(duty, Σ) = + case duty.deadline of + ⊥ → ∞ + AbsoluteDeadline(t) → t + RelativeDeadline(d) → Σ.activatedAt(duty) + d +``` + +### 5.4 Match Semantics + +Action and asset matching support hierarchy subsumption: + +``` +x₁ matches x₂ ⟺ x₁ = x₂ ∨ x₁ includedIn⁺ x₂ +s₁ matches s₂ ⟺ s₁ = s₂ ∨ s₁ partOf⁺ s₂ +``` + +Where `includedIn⁺` and `partOf⁺` are the transitive closures of `odrl:includedIn` and `dprod:partOf` respectively. + +Agent matching supports hierarchy subsumption: + +``` +a₁ matches a₂ ⟺ a₁ = a₂ ∨ a₁ memberOf⁺ a₂ +``` + +Where `memberOf⁺` is the transitive closure of `dprod:memberOf`. + +The subsumption-aware performed check is: + +``` +performed(a, x, s, Σ) := + ∃(a', x', s', t) ∈ Σ.performed : + a' = a ∧ (x' = x ∨ x' includedIn⁺ x) ∧ s' matches s +``` + +`Σ.performed` records exact actions as they occur. `performed()` is the query-time subsumption check used in all fulfillment and violation rules. This is a bounded graph traversal over the `odrl:includedIn` hierarchy. + +### 5.5 Recurrence Semantics + +A duty with a `recurrence` field defines a recurring obligation. The recurrence value is an RFC 5545 RRULE string (e.g., `FREQ=DAILY;BYHOUR=6;BYMINUTE=0`). + +**Instance Generation**: + +``` +expand : Recurrence × Time → Set