Skip to content

Commit d678402

Browse files
Merge pull request #130 from diffo-dev/103-provider-extension-consolidation
103 provider extension consolidation
2 parents 160e946 + 1f2d279 commit d678402

63 files changed

Lines changed: 3435 additions & 1630 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2025 diffo contributors <https://github.com/diffo-dev/diffo/graphs.contributors>
3+
4+
SPDX-License-Identifier: MIT
5+
-->
6+
7+
# AGENTS.md — Diffo
8+
9+
AI agent guidance for the Diffo source repository.
10+
11+
## What this project is
12+
13+
Diffo is a Telecommunications Management Forum (TMF) Service and Resource Manager, built
14+
on [Ash Framework](https://www.ash-hq.org/) + [AshNeo4j](https://github.com/diffo-dev/ash_neo4j) + [Neo4j](https://github.com/neo4j/neo4j). It models TMF 638/639 Service and Resource inventory and provides a Spark DSL for defining domain-specific instance, party, and place kinds.
15+
16+
## Before making changes
17+
18+
1. Read `usage-rules.md` — Diffo-specific DSL rules.
19+
2. Read `CLAUDE.md` — dependency usage rules (Ash, Elixir, OTP, AshNeo4j, Spark).
20+
3. Consult the skill at `.claude/skills/diffo-framework/` for Ash ecosystem patterns.
21+
22+
## Project structure
23+
24+
```
25+
lib/diffo/provider/
26+
extension.ex # Unified Spark DSL extension (provider do)
27+
extension/
28+
info.ex # Runtime introspection via Spark.InfoGenerator
29+
characteristic.ex # Characteristic build helpers
30+
feature.ex # Feature build helpers
31+
instance_role.ex # InstanceRole struct
32+
party_declaration.ex # PartyDeclaration struct
33+
place_declaration.ex # PlaceDeclaration struct
34+
party_role.ex # PartyRole struct (Party/Place kinds)
35+
place_role.ex # PlaceRole struct (Party/Place kinds)
36+
persisters/ # Spark transformers — bake DSL state into module
37+
transformers/ # TransformBehaviour — action argument injection
38+
verifiers/ # Compile-time DSL correctness checks
39+
base_instance.ex # Ash Fragment for Instance resources
40+
base_party.ex # Ash Fragment for Party resources
41+
base_place.ex # Ash Fragment for Place resources
42+
components/
43+
instance/extension.ex # Thin marker (sections: []) — kind identification
44+
party/extension.ex # Thin marker
45+
place/extension.ex # Thin marker
46+
47+
test/provider/extension/ # All provider extension tests
48+
instance_transformer_test.exs
49+
party_transformer_test.exs
50+
place_transformer_test.exs
51+
instance_verifier_test.exs
52+
party_verifier_test.exs
53+
place_verifier_test.exs
54+
party_test.exs # Integration: parties enforcement
55+
place_test.exs # Integration: places enforcement
56+
specification_test.exs # Integration: spec roundtrip
57+
characteristic_test.exs # Integration: characteristic creation
58+
feature_test.exs # Integration: feature creation
59+
assigner_test.exs # Integration: resource assignment
60+
61+
test/support/
62+
resources/ # Test domain resources (Shelf, Card, Organization, etc.)
63+
domains/ # Test domains (Servo, Nbn)
64+
```
65+
66+
## The unified `provider do` DSL
67+
68+
All DSL declarations use a single `provider do` section — there is no `structure do`,
69+
top-level `behaviour do`, or bare `instances/parties/places do`.
70+
71+
### Instance resources (`BaseInstance`)
72+
73+
```elixir
74+
provider do
75+
specification do
76+
id "da9b207a-..." # stable UUID4 — never change after first commit
77+
name "myService" # camelCase
78+
type :serviceSpecification
79+
major_version 1
80+
description "..."
81+
category "..."
82+
end
83+
84+
characteristics do
85+
characteristic :slot_value, MyApp.SlotValue
86+
characteristic :ports, {:array, MyApp.Port}
87+
end
88+
89+
features do
90+
feature :advanced_routing, is_enabled?: false do
91+
characteristic :policy, MyApp.RoutingPolicy
92+
end
93+
end
94+
95+
parties do
96+
party :provider, MyApp.RSP # singular, direct edge
97+
parties :engineers, MyApp.Engineer, constraints: [min: 1, max: 5]
98+
party_ref :owner, MyApp.Organization # no direct edge
99+
party :operator, MyApp.RSP, calculate: :derive_operator
100+
end
101+
102+
places do
103+
place :installation_site, MyApp.GeographicSite
104+
place_ref :billing_address, MyApp.GeographicAddress
105+
end
106+
107+
behaviour do
108+
actions do
109+
create :build # injects :specified_by, :features, :characteristics
110+
end
111+
end
112+
end
113+
```
114+
115+
### Party and Place resources (`BaseParty` / `BasePlace`)
116+
117+
```elixir
118+
provider do
119+
instances do
120+
role :provider, MyApp.BroadbandService
121+
instance_ref :manages, MyApp.InternalService # no direct edge
122+
end
123+
parties do
124+
role :employer, MyApp.Organization
125+
end
126+
places do
127+
role :headquarters, MyApp.GeographicSite
128+
end
129+
end
130+
```
131+
132+
## Running tests
133+
134+
Integration tests require a running Neo4j instance.
135+
136+
```sh
137+
mix test # full suite
138+
mix test test/provider/extension/ # extension tests only
139+
mix test path/to/test.exs:LINE # single test
140+
mix test --max-failures 5 # stop early
141+
```
142+
143+
## Common agent mistakes
144+
145+
- Using old `structure do` / top-level `instances do` — use `provider do` only.
146+
- Using `party :role, Type, reference: true` — use `party_ref :role, Type`.
147+
- Calling `build_before/1` or `build_after/2` in actions — these run automatically.
148+
- Declaring `:specified_by`, `:features`, `:characteristics` as action arguments.
149+
- Editing `documentation/dsls/DSL-Diffo.Provider.Extension.md` — it is Spark-generated;
150+
run `mix spark.cheat_sheets` to regenerate it.
151+
- Editing content between `<!-- usage-rules-start -->` markers in `CLAUDE.md` — that is
152+
auto-generated by `mix usage_rules.sync`.

0 commit comments

Comments
 (0)