Skip to content
Merged

dev #167

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
23a3f4d
improve verify_characterisic, fix shelf bug
matt-beanland May 17, 2026
957595c
Merge pull request #138 from diffo-dev/137-ensure-verifier-checks-cha…
matt-beanland May 17, 2026
fc216e2
defined_simple_relationship
matt-beanland May 17, 2026
651a14b
Merge pull request #142 from diffo-dev/140-definedrelationship-basere…
matt-beanland May 17, 2026
4592844
refactored assigner using defined_simple_relationship
matt-beanland May 17, 2026
bcd4431
Merge pull request #143 from diffo-dev/141-refactor-assigner-using-de…
matt-beanland May 17, 2026
4fa185d
source side validation
matt-beanland May 18, 2026
e96b022
Merge pull request #146 from diffo-dev/134-relationships-dsl
matt-beanland May 18, 2026
b80ebad
target side working using cypher
matt-beanland May 18, 2026
dab6c0f
agents insight
matt-beanland May 18, 2026
b57e0b6
agents and deps with failing tests
matt-beanland May 19, 2026
70de718
ash_neo4j 0.6.0 upgrade + domain extension pattern
matt-beanland May 19, 2026
fa3d802
refactor as Validator
matt-beanland May 19, 2026
f50913f
Merge pull request #148 from diffo-dev/145-relationships---target-sid…
matt-beanland May 19, 2026
aa5b400
minor refactorings
matt-beanland May 19, 2026
7a4d917
Merge pull request #150 from diffo-dev/149-clean-code
matt-beanland May 19, 2026
c3fb128
improved via assignment_relationship, added identity
matt-beanland May 19, 2026
858342d
Merge pull request #151 from diffo-dev/147-improve-assigner-to-use-ag…
matt-beanland May 19, 2026
841a42d
transform_behaviour is a transformer
matt-beanland May 19, 2026
75d9c0b
Merge pull request #152 from diffo-dev/144-refactor_transformers_and_…
matt-beanland May 19, 2026
1d72630
resource lifecycle_status
matt-beanland May 19, 2026
e3ea3c4
Merge pull request #154 from diffo-dev/153-resource-lifecycle-state
matt-beanland May 19, 2026
c5dd990
inheritied party and place via instance dsl
matt-beanland May 20, 2026
03413cf
Merge pull request #155 from diffo-dev/122-party-inheritance-via-inst…
matt-beanland May 20, 2026
ab207fc
spark cheatsheets
matt-beanland May 20, 2026
b4f99bb
formating
matt-beanland May 20, 2026
acaac31
agent guidance
matt-beanland May 20, 2026
0d7880b
Merge pull request #161 from diffo-dev/122-party-inheritance-via-inst…
matt-beanland May 20, 2026
063bb11
field via assigned relationship calculation
matt-beanland May 20, 2026
6f766f6
Merge pull request #162 from diffo-dev/156-fieldviaassignedrelationsh…
matt-beanland May 20, 2026
35cddec
field via aliased relationship calculation
matt-beanland May 20, 2026
1124574
Merge pull request #163 from diffo-dev/157-fieldviaaliasedrelationshi…
matt-beanland May 20, 2026
f2cedd9
field from assignment calculation
matt-beanland May 20, 2026
f218604
Merge pull request #164 from diffo-dev/158-fieldfromassignment-calcul…
matt-beanland May 20, 2026
5b0f435
field via relationship with type, alias (nil wild)
matt-beanland May 20, 2026
f8460c4
Merge pull request #165 from diffo-dev/157-fieldviaaliasedrelationshi…
matt-beanland May 20, 2026
dd8e5c5
update docs and guidance
matt-beanland May 20, 2026
b9c4ffb
Merge pull request #166 from diffo-dev/160-docs-pass-inherited-dsl-al…
matt-beanland May 20, 2026
cdbbea4
release 0.4.0
matt-beanland May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ spark_locals_without_parens = [
feature: 1,
feature: 2,
id: 1,
inherited_party: 1,
inherited_party: 2,
inherited_place: 1,
inherited_place: 2,
instance_ref: 2,
is_enabled?: 1,
major_version: 1,
minor_version: 1,
Expand All @@ -23,14 +28,21 @@ spark_locals_without_parens = [
parties: 3,
party: 2,
party: 3,
party_ref: 2,
party_ref: 3,
patch_version: 1,
place: 2,
place: 3,
place_ref: 2,
place_ref: 3,
places: 2,
places: 3,
pool: 2,
reference: 1,
role: 2,
role: 3,
source: 1,
target: 1,
tmf_version: 1,
type: 1,
update: 1,
Expand Down
220 changes: 205 additions & 15 deletions AGENTS.md

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,54 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline

<!-- changelog -->

## [v0.4.0](https://github.com/diffo-dev/diffo/compare/v0.3.0...v0.4.0) (2026-05-20)

### Breaking Changes

* `Diffo.Provider.AssignedToRelationship` replaced by `Diffo.Provider.AssignmentRelationship` — stores pool assignments with top-level `pool`, `thing`, `value`, and `alias` scalar attributes, enabling graph-level filtering in AshNeo4j queries. Any existing graph data on `AssignedToRelationship` nodes must be migrated.
* `create_assigned_to_relationship` code interface removed — use `create_assignment_relationship` instead.
* `instance.assignments` now returns `AssignmentRelationship` records (struct name change only).

### Features

* **`DefinedSimpleRelationship`** — new resource for relationships carrying an optional single embedded `NameValuePrimitive` characteristic, frozen at creation. Used by the Assigner and available as a general-purpose committed-relationship primitive. Accessible via `instance.assignments`.
* **`AssignmentRelationship` aliases** — the `alias` attribute on `AssignmentRelationship` (identity `[:target_id, :alias]`) gives a consuming instance a stable name for an assignment slot. Mirrors the `[:source_id, :alias]` identity on `DefinedSimpleRelationship`. Alias semantics are the foundation of the first-order expectation system (#74).
* **`relationships do` DSL** — source and target validation pipeline for Instance resources. `ValidateRelationshipPermitted` is injected automatically into relate actions. Supports `:all`, `:none`, and explicit role-name lists.
* **Resource lifecycle states** — `resource_state` attribute on Instance resources with standard TMF states (`:installed`, `:operating`, `:retired`, etc.). The Assigner enforces `:operating` before allowing assignment.
* **`inherited_place` / `inherited_party` DSL** — declare inside `places do` / `parties do` on an Instance resource to generate an Ash calculation that traverses the assignment graph by alias and inherits a place or party from the source instance. No `PlaceRef`/`PartyRef` edge is created — the calculation is the reference. Supports single-hop (default: role name as alias) and multi-hop (`via:` list).
* **`FieldFromAssignment`** (`Diffo.Provider.Calculations.FieldFromAssignment`) — reads a field directly from an `AssignmentRelationship` record (`:value`, `:pool`, `:thing`, `:alias`). Filtered by optional `alias:`. Returns a list.
* **`FieldViaAssignedRelationship`** (`Diffo.Provider.Calculations.FieldViaAssignedRelationship`) — traverses `AssignmentRelationship` in reverse (target → source) and reads a named field from each source instance. Supports multi-hop `via:` traversal. Returns a list.
* **`FieldViaRelationship`** (`Diffo.Provider.Calculations.FieldViaRelationship`) — traverses `DefinedSimpleRelationship` forward (source → target) filtered by optional `alias:` and/or `type:`, and reads a named field from each target instance. Returns a list.

### Notable Changes

* Assigner rearchitected — `AssignmentRelationship` carries `pool`, `thing`, `value`, `alias` as top-level attributes for AshNeo4j-level filtering; `assigned_values` and `free_values` use query-level filtering rather than in-memory computation where possible.
* `TransformBehaviour` moved from persister pipeline to transformer pipeline for correct Spark ordering relative to Ash's own transformers.
* Characteristic type verifier improved — rejects `characteristic` DSL declarations whose type module is not derived from `BaseCharacteristic`.

### Documentation

* `usage-rules.md` — new sections covering alias semantics, `inherited_place`/`inherited_party` DSL, and all three field calculation modules including a decision table.
* `AGENTS.md` — updated project structure, DSL inline examples for inherited refs, and new common mistakes section entries.
* Provider Extension livebook — new section "Aliases, Inherited DSL, and Field Calculations" with Compute-domain examples.

### What's Changed

* defined_simple_relationship by @matt-beanland in https://github.com/diffo-dev/diffo/pull/142
* refactored assigner using defined_simple_relationship by @matt-beanland in https://github.com/diffo-dev/diffo/pull/143
* relationships DSL by @matt-beanland in https://github.com/diffo-dev/diffo/pull/146
* relationships target side validation by @matt-beanlanda in https://github.com/diffo-dev/diffo/pull/148
* clean code by @matt-beanland in https://github.com/diffo-dev/diffo/pull/150
* improved assigner using aggregates by @matt-beanland in https://github.com/diffo-dev/diffo/pull/151
* refactor transformers and persisters by @matt-beanland in https://github.com/diffo-dev/diffo/pull/152
* resource lifecycle state by @matt-beanland in https://github.com/diffo-dev/diffo/pull/154
* inherited party and place via instance DSL by @matt-beanland in https://github.com/diffo-dev/diffo/pull/155
* agent guidance by @matt-beanland in https://github.com/diffo-dev/diffo/pull/161
* FieldViaAssignedRelationship calculation by @matt-beanland in https://github.com/diffo-dev/diffo/pull/162
* FieldViaRelationship calculation by @matt-beanland in https://github.com/diffo-dev/diffo/pull/165
* FieldFromAssignment calculation by @matt-beanland in https://github.com/diffo-dev/diffo/pull/164
* docs pass — inherited DSL, aliases, and field calculations by @matt-beanland in https://github.com/diffo-dev/diffo/pull/166

## [v0.3.0](https://github.com/diffo-dev/diffo/compare/v0.2.2...v0.3.0) (2026-05-17)

### Breaking Changes
Expand Down
147 changes: 145 additions & 2 deletions documentation/dsls/DSL-Diffo.Provider.Extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,19 @@ Provider DSL — structure, roles, and behaviour for this resource kind
* parties
* party_ref
* role
* inherited_party
* [places](#provider-places)
* place
* places
* place_ref
* role
* inherited_place
* [instances](#provider-instances)
* role
* instance_ref
* [relationships](#provider-relationships)
* source
* target
* [behaviour](#provider-behaviour)
* actions
* create
Expand Down Expand Up @@ -327,13 +332,14 @@ Declares an assignable pool — a named range of values for auto-assignment


### provider.parties
Party roles on this resource — `party`/`parties`/`party_ref` for Instance kinds; `role` for Party and Place kinds
Party roles on this resource — `party`/`parties`/`party_ref`/`inherited_party` for Instance kinds; `role` for Party and Place kinds

### Nested DSLs
* [party](#provider-parties-party)
* [parties](#provider-parties-parties)
* [party_ref](#provider-parties-party_ref)
* [role](#provider-parties-role)
* [inherited_party](#provider-parties-inherited_party)


### Examples
Expand All @@ -343,6 +349,7 @@ parties do
party :provider, MyApp.Provider
party_ref :owner, MyApp.InfrastructureCo
parties :technicians, MyApp.Technician, constraints: [min: 1]
inherited_party :customer, source_role: :owner
end

# Party or Place
Expand Down Expand Up @@ -480,15 +487,48 @@ Declares a role this Party or Place kind plays with respect to other Parties

Target: `Diffo.Provider.Extension.PartyRole`

### provider.parties.inherited_party
```elixir
inherited_party role
```


Declares a party derived by traversing the assignment graph — generates a calculation, no PartyRef node created





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`role`](#provider-parties-inherited_party-role){: #provider-parties-inherited_party-role .spark-required} | `atom` | | The role name — also the default alias to follow on AssignmentRelationship. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`source_role`](#provider-parties-inherited_party-source_role){: #provider-parties-inherited_party-source_role .spark-required} | `atom` | | The PartyRef role to pick up on the arrived-at instance. |
| [`via`](#provider-parties-inherited_party-via){: #provider-parties-inherited_party-via } | `list(atom)` | | Sequence of assignment aliases to traverse. Defaults to [role] for single-hop. Use a list for multi-level. |





### Introspection

Target: `Diffo.Provider.Extension.InheritedPartyDeclaration`


### provider.places
Place roles on this resource — `place`/`places`/`place_ref` for Instance kinds; `role` for Party and Place kinds
Place roles on this resource — `place`/`places`/`place_ref`/`inherited_place` for Instance kinds; `role` for Party and Place kinds

### Nested DSLs
* [place](#provider-places-place)
* [places](#provider-places-places)
* [place_ref](#provider-places-place_ref)
* [role](#provider-places-role)
* [inherited_place](#provider-places-inherited_place)


### Examples
Expand All @@ -497,6 +537,8 @@ Place roles on this resource — `place`/`places`/`place_ref` for Instance kinds
places do
place :installation_site, MyApp.GeographicSite
place_ref :billing_address, MyApp.GeographicAddress
inherited_place :a_end, source_role: :location
inherited_place :poi, via: [:cvc_link, :nni_link], source_role: :poi
end

# Party or Place
Expand Down Expand Up @@ -634,6 +676,38 @@ Declares a role this Party or Place kind plays with respect to Places

Target: `Diffo.Provider.Extension.PlaceRole`

### provider.places.inherited_place
```elixir
inherited_place role
```


Declares a place derived by traversing the assignment graph — generates a calculation, no PlaceRef node created





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`role`](#provider-places-inherited_place-role){: #provider-places-inherited_place-role .spark-required} | `atom` | | The role name — also the default alias to follow on AssignmentRelationship. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`source_role`](#provider-places-inherited_place-source_role){: #provider-places-inherited_place-source_role .spark-required} | `atom` | | The PlaceRef role to pick up on the arrived-at instance. |
| [`via`](#provider-places-inherited_place-via){: #provider-places-inherited_place-via } | `list(atom)` | | Sequence of assignment aliases to traverse. Defaults to [role] for single-hop. Use a list for multi-level. |





### Introspection

Target: `Diffo.Provider.Extension.InheritedPlaceDeclaration`


### provider.instances
Declares the roles this Party or Place kind plays with respect to Instances
Expand Down Expand Up @@ -712,6 +786,75 @@ Declares a reference instance role — no direct edge created, reachable by grap
Target: `Diffo.Provider.Extension.InstanceRole`


### provider.relationships
Relationship role permissions for this Instance — declares which aliases it may participate in as source or target. Omitting defaults to `:none` per direction.

### Nested DSLs
* [source](#provider-relationships-source)
* [target](#provider-relationships-target)


### Examples
```
relationships do
source [:provides, :requires]
target :all
end

```




### provider.relationships.source
```elixir
source roles
```


Declares permitted source relationship roles — pipeline step, last declaration wins





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`roles`](#provider-relationships-source-roles){: #provider-relationships-source-roles .spark-required} | `any` | | `:all`, `:none`, or a list of role name atoms. |







### provider.relationships.target
```elixir
target roles
```


Declares permitted target relationship roles — pipeline step, last declaration wins





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`roles`](#provider-relationships-target-roles){: #provider-relationships-target-roles .spark-required} | `any` | | `:all`, `:none`, or a list of role name atoms. |








### provider.behaviour
Defines the behavioural wiring for the Instance — actions, and in future triggers

Expand Down
Loading
Loading