Skip to content

feat: remove scope inheritance, add do-block form for scope options#2

Merged
C-Sinclair merged 1 commit intomainfrom
feat/scope-do-block-remove-inheritance
Apr 21, 2026
Merged

feat: remove scope inheritance, add do-block form for scope options#2
C-Sinclair merged 1 commit intomainfrom
feat/scope-do-block-remove-inheritance

Conversation

@C-Sinclair
Copy link
Copy Markdown

Summary

Removes inherits from the scope DSL and enables a do-block form for setting description (and any future scope option):

scope :my_scope_name, expr(...) do
  description "This is important"
end

Breaking change: inherits is gone. The old positional form (scope :own_draft, [:own], expr(status == :draft)) and the keyword form (scope :name, expr(...), inherits: [:parent]) no longer compile. Write each scope as one expression:

# Before
scope :own, expr(author_id == ^actor(:id))
scope :own_draft, [:own], expr(status == :draft)

# After
scope :own, expr(author_id == ^actor(:id))
scope :own_draft, expr(author_id == ^actor(:id) and status == :draft)

Why: scope inheritance added hidden coupling (child behaviour depended on parent filters that might live in a different module), interacted awkwardly with write: and argument-based scopes, and — because inherits was an optional positional arg — blocked scope from supporting Spark do-blocks at all. Inlining with and is mechanically trivial, reads plainly, and shows up straight in AshGrant.explain/4.

Domain-level scope merging is unchanged — a resource still sees scopes defined on its domain. Only scope-to-scope inheritance is removed.

Net change

Net −191 LoC across lib/. Info's resolve_scope_filter/3 is now a direct lookup; AddArgumentResolvers lost the recursive DSL-state walker.

Docs

  • usage-rules.md: scope entity section updated, inheritance rule replaced with "combine inline" DO.
  • README.md, guides/scopes.md, guides/authorization-patterns.md, guides/scope-naming-convention.md, guides/getting-started.md, guides/advanced-patterns.md: removed inheritance references, updated examples.
  • guides/migration.md: new section explaining the removal and migration path.
  • CHANGELOG.md (Unreleased): breaking change + added do-block form.

Test plan

  • mix compile --warnings-as-errors clean
  • mix test — 1045 tests pass (1 pre-existing failure in default_field_policies_test.exs, unrelated)
  • mix format --check-formatted clean
  • mix credo — only pre-existing non-blocking suggestions
  • Test resources and guide examples all compile after inlining combined filters
  • Do-block form verified via new tests in test/ash_grant/scope_dsl_test.exs

- Remove `inherits` option and positional-list arg from the scope DSL.
- Remove `:inherits` field from AshGrant.Dsl.Scope struct.
- Simplify Info.resolve_scope_filter/3 and resolve_write_scope_filter/3
  to direct lookups (no parent walking).
- Remove inheritance-aware DSL resolution from AddArgumentResolvers.
- Move `inherits` from positional arg to a removed concept so the
  2-arg + do-block form works: `scope :name, expr(...) do description ... end`.
- Migrate all test resources and guides to inline combined filters with `and`.
- Update usage-rules.md, README, CHANGELOG, and migration guide.
@C-Sinclair C-Sinclair merged commit 5c83a8d into main Apr 21, 2026
1 check passed
C-Sinclair added a commit that referenced this pull request Apr 21, 2026
Resolves conflicts from two changes landed on main:

- #2 removed scope inheritance (no impact here — grants don't use scope
  inheritance; tests still combine conditions inline with `and`).
- #4 broke the compile-time cycle between resource and domain by removing
  the MergeDomainConfig transformer and the ValidateResolverPresent
  transformer, moving resolver-merge logic into AshGrant.Info.resolver/1
  at runtime and turning ValidateResolverPresent into a verifier.

Adjustments to this branch:

- Dropped lib/ash_grant/transformers/validate_resolver_present.ex — the
  file was deleted on main (replaced by a verifier). My earlier explicit
  before?/after? guards in that file were no longer needed.
- Reintegrated NormalizeGrants and SynthesizeGrantsResolver into the
  new transformer list (main-first ordering, no references to the now-gone
  MergeDomainConfig).
- Added ValidateGrantReferences to the verifier list alongside the new
  ValidateResolverPresent and ValidateScopes verifiers.
- Cleaned before?/after? in NormalizeGrants and SynthesizeGrantsResolver
  to reference only transformers that still exist.

Full suite still green (1089 tests, 1 pre-existing unrelated failure).
Credo clean on all new files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant