Description
A resource that declares typed characteristics through the unified provider do characteristics do DSL — and pools via pools do — ends up with those records present in the graph as their own per-type resources (labels like :PathCharacteristic, :AssignableCharacteristic), wired to the Instance via :HAS. But the Instance's JSON encoding only picks up the dynamic Diffo.Provider.Characteristic records flowing through instance.characteristics, so the typed records and pool records are absent from serviceCharacteristic / resourceCharacteristic.
defmodule MyApp.Path do
use Ash.Resource, fragments: [Diffo.Provider.BaseInstance], domain: MyApp.Access
provider do
specification do
id "1d507914-…"
type :resourceSpecification
name "path"
end
characteristics do
characteristic :path, MyApp.PathCharacteristic
end
end
end
After build, the PathCharacteristic record exists and exposes its own :value calculation; encoding the Instance still produces JSON without a resourceCharacteristic field.
What we need
That what was declared as a characteristic is also visible as one when the Instance is read — directly or through JSON encoding. The DSL declarations (characteristics/0, pools/0) are already exposed at compile time and the records are reachable in the graph; the gap is between "declared and stored" and "visible in the read view."
Why it matters
Typed characteristics and pools were introduced specifically so domain modellers could give characteristic values structure and lifecycle. If those records don't surface alongside the dynamic ones, every Extended domain has to either build the gather-and-merge view themselves or live with a partial round-trip. The risk for downstream consumers is a quiet one — defined values just don't appear — and the rediscovery cost happens once per domain.
There's a real question underneath this about where Diffo's responsibility ends and the consumer's begins (we ended up exploring both sides as we hit this), but landing the observation first feels more useful than leading with the abstract question.
A possible direction
The Util.suppress_rename(:characteristics, …) step is the natural place a wider input could land — characteristics/0 and pools/0 are already the inputs the DSL holds. Worth checking the symmetric story for features (featureCharacteristic).
A bigger-picture thought we drifted toward while exploring this: today Diffo's Provider domain effectively is the TMF638 projection — implicit, partial, and baked in. Making the projection explicit and opt-in (something like a tmf638 do DSL section a consumer declares when they want TMF638-compliant reads) would put the projection in the foreground, let Diffo do the gathering completely when asked, and leave Extended domains free to expose whatever shape they want when not. Equally, the right answer might just be a how-to in the usage rules pointing consumers at the building blocks for their own view. Both feel like valid evolutions — happy either way.
Description
A resource that declares typed characteristics through the unified
provider do characteristics doDSL — and pools viapools do— ends up with those records present in the graph as their own per-type resources (labels like:PathCharacteristic,:AssignableCharacteristic), wired to the Instance via:HAS. But the Instance's JSON encoding only picks up the dynamicDiffo.Provider.Characteristicrecords flowing throughinstance.characteristics, so the typed records and pool records are absent fromserviceCharacteristic/resourceCharacteristic.After
build, thePathCharacteristicrecord exists and exposes its own:valuecalculation; encoding the Instance still produces JSON without aresourceCharacteristicfield.What we need
That what was declared as a characteristic is also visible as one when the Instance is read — directly or through JSON encoding. The DSL declarations (
characteristics/0,pools/0) are already exposed at compile time and the records are reachable in the graph; the gap is between "declared and stored" and "visible in the read view."Why it matters
Typed characteristics and pools were introduced specifically so domain modellers could give characteristic values structure and lifecycle. If those records don't surface alongside the dynamic ones, every Extended domain has to either build the gather-and-merge view themselves or live with a partial round-trip. The risk for downstream consumers is a quiet one — defined values just don't appear — and the rediscovery cost happens once per domain.
There's a real question underneath this about where Diffo's responsibility ends and the consumer's begins (we ended up exploring both sides as we hit this), but landing the observation first feels more useful than leading with the abstract question.
A possible direction
The
Util.suppress_rename(:characteristics, …)step is the natural place a wider input could land —characteristics/0andpools/0are already the inputs the DSL holds. Worth checking the symmetric story for features (featureCharacteristic).A bigger-picture thought we drifted toward while exploring this: today Diffo's Provider domain effectively is the TMF638 projection — implicit, partial, and baked in. Making the projection explicit and opt-in (something like a
tmf638 doDSL section a consumer declares when they want TMF638-compliant reads) would put the projection in the foreground, let Diffo do the gathering completely when asked, and leave Extended domains free to expose whatever shape they want when not. Equally, the right answer might just be a how-to in the usage rules pointing consumers at the building blocks for their own view. Both feel like valid evolutions — happy either way.