Skip to content

Commit acaac31

Browse files
committed
agent guidance
1 parent b4f99bb commit acaac31

2 files changed

Lines changed: 96 additions & 7 deletions

File tree

AGENTS.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,27 @@ Spark runs two separate pipelines during compilation, in this order:
271271

272272
New transformers go under `transformers:`. New persisters go under `persisters:`.
273273

274+
## DSL shape changes
275+
276+
Whenever you add, rename, or remove a DSL entity or section in `Diffo.Provider.Extension`
277+
(or any Spark extension in this project), run this checklist in order:
278+
279+
1. **Update `.formatter.exs`** — add new entity names to `spark_locals_without_parens` with
280+
each supported arity. Without this, `mix format` will add unwanted parentheses to every
281+
DSL call site.
282+
283+
2. **Run `mix format`** — apply formatting across the codebase and verify the output looks
284+
correct. Run `mix format --check-formatted` to confirm nothing was missed.
285+
286+
3. **Run `mix spark.cheat_sheets`** — regenerates
287+
`documentation/dsls/DSL-Diffo.Provider.Extension.md`. This file is Spark-generated;
288+
never edit it by hand. Commit the regenerated file alongside the DSL change.
289+
290+
4. **Run `mix test`** — confirm no regressions.
291+
292+
Do not skip step 1 even for a "small" entity addition — the formatter will silently reformat
293+
every call site in CI and produce noisy diffs in future PRs.
294+
274295
## Raising upstream bugs
275296

276297
When a bug is found in a dependency (e.g. AshNeo4j, Bolty), raise a GitHub issue on that
@@ -309,11 +330,8 @@ not. Add any useful hypotheses as a follow-up comment on the issue, then leave i
309330
- Using module names (e.g. `MyApp.CardInstance`) as role values in `relationships do` — roles are atoms like `:provides`, not module references.
310331
- Forgetting that `relationships do` omitted means `:none` for both source and target — any update action with `argument :relationships, {:array, :struct}` will fail unless the resource declares permissions.
311332
- Thinking the Assigner requires `relationships do` permissions — it does not. The Assigner writes `DefinedSimpleRelationship` records directly via the Provider domain; `ValidateRelationshipPermitted` only runs on actions that carry `argument :relationships, {:array, :struct}`, which the Assigner's `assign_*` actions do not.
312-
- Editing `documentation/dsls/DSL-Diffo.Provider.Extension.md` — it is Spark-generated;
313-
run `mix spark.cheat_sheets` to regenerate it. Whenever you add, rename, or remove a DSL
314-
entity or section, also check `.formatter.exs` — new entity names must be added to
315-
`spark_locals_without_parens` (with each arity) so the Spark formatter omits parentheses.
316-
Run `mix format` afterward to verify.
333+
- Editing `documentation/dsls/DSL-Diffo.Provider.Extension.md` — it is Spark-generated.
334+
See the **DSL shape changes** section above for the full checklist.
317335
- Editing content between `<!-- usage-rules-start -->` markers in `CLAUDE.md` — that is
318336
auto-generated by `mix usage_rules.sync`.
319337
- Forgetting `Diffo.Provider.DomainFragment` on a scenario 3 domain — any domain whose

documentation/dsls/DSL-Diffo.Provider.Extension.md

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,13 @@ Provider DSL — structure, roles, and behaviour for this resource kind
103103
* parties
104104
* party_ref
105105
* role
106+
* inherited_party
106107
* [places](#provider-places)
107108
* place
108109
* places
109110
* place_ref
110111
* role
112+
* inherited_place
111113
* [instances](#provider-instances)
112114
* role
113115
* instance_ref
@@ -330,13 +332,14 @@ Declares an assignable pool — a named range of values for auto-assignment
330332

331333

332334
### provider.parties
333-
Party roles on this resource — `party`/`parties`/`party_ref` for Instance kinds; `role` for Party and Place kinds
335+
Party roles on this resource — `party`/`parties`/`party_ref`/`inherited_party` for Instance kinds; `role` for Party and Place kinds
334336

335337
### Nested DSLs
336338
* [party](#provider-parties-party)
337339
* [parties](#provider-parties-parties)
338340
* [party_ref](#provider-parties-party_ref)
339341
* [role](#provider-parties-role)
342+
* [inherited_party](#provider-parties-inherited_party)
340343

341344

342345
### Examples
@@ -346,6 +349,7 @@ parties do
346349
party :provider, MyApp.Provider
347350
party_ref :owner, MyApp.InfrastructureCo
348351
parties :technicians, MyApp.Technician, constraints: [min: 1]
352+
inherited_party :customer, source_role: :owner
349353
end
350354
351355
# Party or Place
@@ -483,15 +487,48 @@ Declares a role this Party or Place kind plays with respect to other Parties
483487

484488
Target: `Diffo.Provider.Extension.PartyRole`
485489

490+
### provider.parties.inherited_party
491+
```elixir
492+
inherited_party role
493+
```
494+
495+
496+
Declares a party derived by traversing the assignment graph — generates a calculation, no PartyRef node created
497+
498+
499+
500+
501+
502+
### Arguments
503+
504+
| Name | Type | Default | Docs |
505+
|------|------|---------|------|
506+
| [`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. |
507+
### Options
508+
509+
| Name | Type | Default | Docs |
510+
|------|------|---------|------|
511+
| [`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. |
512+
| [`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. |
513+
514+
515+
516+
517+
518+
### Introspection
519+
520+
Target: `Diffo.Provider.Extension.InheritedPartyDeclaration`
521+
486522

487523
### provider.places
488-
Place roles on this resource — `place`/`places`/`place_ref` for Instance kinds; `role` for Party and Place kinds
524+
Place roles on this resource — `place`/`places`/`place_ref`/`inherited_place` for Instance kinds; `role` for Party and Place kinds
489525

490526
### Nested DSLs
491527
* [place](#provider-places-place)
492528
* [places](#provider-places-places)
493529
* [place_ref](#provider-places-place_ref)
494530
* [role](#provider-places-role)
531+
* [inherited_place](#provider-places-inherited_place)
495532

496533

497534
### Examples
@@ -500,6 +537,8 @@ Place roles on this resource — `place`/`places`/`place_ref` for Instance kinds
500537
places do
501538
place :installation_site, MyApp.GeographicSite
502539
place_ref :billing_address, MyApp.GeographicAddress
540+
inherited_place :a_end, source_role: :location
541+
inherited_place :poi, via: [:cvc_link, :nni_link], source_role: :poi
503542
end
504543
505544
# Party or Place
@@ -637,6 +676,38 @@ Declares a role this Party or Place kind plays with respect to Places
637676

638677
Target: `Diffo.Provider.Extension.PlaceRole`
639678

679+
### provider.places.inherited_place
680+
```elixir
681+
inherited_place role
682+
```
683+
684+
685+
Declares a place derived by traversing the assignment graph — generates a calculation, no PlaceRef node created
686+
687+
688+
689+
690+
691+
### Arguments
692+
693+
| Name | Type | Default | Docs |
694+
|------|------|---------|------|
695+
| [`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. |
696+
### Options
697+
698+
| Name | Type | Default | Docs |
699+
|------|------|---------|------|
700+
| [`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. |
701+
| [`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. |
702+
703+
704+
705+
706+
707+
### Introspection
708+
709+
Target: `Diffo.Provider.Extension.InheritedPlaceDeclaration`
710+
640711

641712
### provider.instances
642713
Declares the roles this Party or Place kind plays with respect to Instances

0 commit comments

Comments
 (0)