enola-guides 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +1 -1
  4. data/examples/laws/cluster-laws/README.md +1 -1
  5. data/examples/laws/cluster-laws/enola/constraints/a-mutating-action-is-authorized.rb +10 -0
  6. data/examples/laws/cluster-laws/enola/constraints/every-api-route-has-a-consumer.rb +9 -0
  7. data/examples/laws/cluster-laws/enola/constraints/one-owner-per-table.rb +9 -0
  8. data/examples/laws/maintenance-tasks/README.md +1 -1
  9. data/examples/laws/maintenance-tasks/enola/constraints/a-maintenance-task-never-invokes-controller-code.rb +9 -0
  10. data/examples/laws/maintenance-tasks/enola/constraints/{maintenance-tasks.rb → every-maintenance-task-lives-in-the-maintenance-namespace.rb} +0 -7
  11. data/examples/rails-shop/enola/constraints/a-concern-never-reaches-the-class-that-includes-it.rb +9 -0
  12. data/examples/rails-shop/enola/constraints/a-mutating-action-is-authorized.rb +10 -0
  13. data/examples/rails-shop/enola/constraints/a-service-answers-to-call.rb +9 -0
  14. data/examples/rails-shop/enola/constraints/background-jobs-never-invoke-controller-code.rb +9 -0
  15. data/examples/rails-shop/enola/constraints/billing-is-documented.rb +10 -0
  16. data/examples/rails-shop/enola/constraints/billing-keeps-to-its-own-tables.rb +9 -0
  17. data/examples/rails-shop/enola/constraints/frames-keep-their-query-budget.rb +9 -0
  18. data/examples/rails-shop/enola/constraints/jobs-models-and-mailers-never-depend-on-each-other-in-a-circle.rb +9 -0
  19. data/examples/rails-shop/enola/constraints/orders-are-reached-through-their-public-surface.rb +9 -0
  20. data/examples/rails-shop/enola/constraints/reach-for-an-existing-service.rb +8 -0
  21. data/examples/rails-shop/enola/constraints/scopes-come-in-pairs.rb +9 -0
  22. data/examples/rails-shop/enola/constraints/the-public-api-stays-small.rb +10 -0
  23. data/examples/rails-shop/enola/constraints/the-request-api-stays-in-controllers.rb +9 -0
  24. data/lib/enola-guides.rb +1 -1
  25. data/templates/constraints-starter/background-jobs-never-invoke-controller-code.rb +9 -0
  26. data/templates/constraints-starter/models-do-not-reach-controllers.rb +9 -0
  27. data/templates/constraints-starter/policies-only-answer.rb +9 -0
  28. data/templates/constraints-starter/the-request-api-stays-in-controllers.rb +9 -0
  29. metadata +23 -5
  30. data/examples/laws/cluster-laws/enola/constraints/cluster.rb +0 -24
  31. data/examples/rails-shop/enola/constraints/laws.rb +0 -93
  32. data/templates/constraints-starter.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 103217d2be760b0b582027a9119e6acc6fae874ffc1171f8e59df35ac5ffb09b
4
- data.tar.gz: 65f13f8cd1c54cafec16aca3f50a80710dcc77df8f6e66077c54fb346afeaf3a
3
+ metadata.gz: df9b7b5b2b3fc6589f9353c4f2198b08283fe80fafd2dacda91dea2d66c5a2fb
4
+ data.tar.gz: 20172bf3167db5fb3d690d401f3313d38861d10f86f7010607c4ccae98353b68
5
5
  SHA512:
6
- metadata.gz: 9cac7aed45a1041aeaeb66c46040f165dfa4156b05d5c2c088890dd18912930b6924059b5f0b1bcc00c4379b7574e524ab8794a43c936a5e5915a4afccf7572c
7
- data.tar.gz: fe230a7e9daac6c8c88662bdcce76f1be1ff8019992c48f57a95afb469fc4bad58bd02e6171d62603e796b80cd31938826d59a5c8010adada9fa116d5a16e13d
6
+ metadata.gz: f705dc88218a61a94d6261b624e6744d8fd14212e6524b062f2f9f9520751013968f4a208382861516265ac4ca41db11ca483e09acf52792120aa704f01251a0
7
+ data.tar.gz: 65b0c4c5cd94ca30b85d3528737489c83c0ff73b8a7b3402dd2d39c45742af8ca679cfaef2ec04ea8837e3ac5d92a1881960b2a7429df198e758ef7b7d8c8435
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 (2026-08-22)
4
+
5
+ One law per file: the Rails shop, the cluster laws, the maintenance-task laws
6
+ and the starter each put every law in a file of its own that declares the parts it
7
+ speaks about, so a reader finds a law by its name and a reviewer sees one
8
+ law per diff.
9
+
3
10
  ## 0.1.1 (2026-08-22)
4
11
 
5
12
  The laws catalogue: `examples/laws/`, twenty-six complete declarations one
data/README.md CHANGED
@@ -18,7 +18,7 @@ gem contents enola-guides
18
18
  ## Start with an example
19
19
 
20
20
  [`examples/rails-shop`](examples/rails-shop): a Rails application declaring
21
- thirteen laws in the Ruby DSL, from "jobs never invoke controller code" to
21
+ thirteen laws in the Ruby DSL, one file each, from "jobs never invoke controller code" to
22
22
  "billing keeps to its own tables" and "a mutating action is authorized",
23
23
  with Prism and Rubydex configured as providers beside the extractors.
24
24
  [`examples/ember-app`](examples/ember-app): an Ember application bound to
@@ -5,5 +5,5 @@ repositories, mutating actions selected through the routes they handle, and
5
5
  routes no loaded client calls. Each refuses by name in a single-repository
6
6
  snapshot rather than reporting silence as compliance.
7
7
 
8
- Declaration under `enola/constraints/`. Copy it, run `enola constraints lint .`,
8
+ One file per law under `enola/constraints/`, each file declaring the parts it speaks about. Copy it, run `enola constraints lint .`,
9
9
  then `enola --generate . && enola check .`.
@@ -0,0 +1,10 @@
1
+ Enola.architecture "platform" do
2
+ part :mutating_actions, service: :backend, files: "app/controllers/**", handles: [:post, :put, :patch, :delete]
3
+ part :policies, service: :backend, files: "app/policies/**"
4
+
5
+ law "a mutating action is authorized" do
6
+ mutating_actions.must_reach :policies
7
+ why "an action behind a POST, PUT, PATCH or DELETE route changes state, and the policy call is the one place the change is authorized"
8
+ mode :advisory
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "platform" do
2
+ part :api, service: :backend, files: "config/**", kind: :route
3
+
4
+ law "every api route has a consumer" do
5
+ api.must_have_consumer
6
+ why "a route nobody calls is a surface nobody maintains"
7
+ mode :advisory
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "platform" do
2
+ part :tables, files: "app/models/**", kind: :storage
3
+
4
+ law "one owner per table" do
5
+ tables.must_be_unique_across by: :table
6
+ why "a table two repositories both model is written by two codebases that never see each other's validations or callbacks"
7
+ mode :advisory
8
+ end
9
+ end
@@ -5,5 +5,5 @@ depends on, and a boundary against controller code that has no request to
5
5
  read. Both were mined from a codebase where they already held, which is the
6
6
  right moment to declare a law.
7
7
 
8
- Declaration under `enola/constraints/`. Copy it, run `enola constraints lint .`,
8
+ One file per law under `enola/constraints/`, each file declaring the parts it speaks about. Copy it, run `enola constraints lint .`,
9
9
  then `enola --generate . && enola check .`.
@@ -0,0 +1,9 @@
1
+ Enola.architecture "app" do
2
+ part :tasks, files: "app/tasks/**"
3
+ part :controllers, files: "app/controllers/**"
4
+
5
+ law "a maintenance task never invokes controller code" do
6
+ tasks.must_not_call controllers
7
+ why "a task runs from the runner or the console with no request around it, so controller code reached from one has nothing to read"
8
+ end
9
+ end
@@ -1,15 +1,8 @@
1
1
  Enola.architecture "app" do
2
2
  part :maintenance_tasks, files: "app/tasks/**", kind: :symbol, where: { symbol_kind: "class" }
3
- part :tasks, files: "app/tasks/**"
4
- part :controllers, files: "app/controllers/**"
5
3
 
6
4
  law "every maintenance task lives in the Maintenance namespace" do
7
5
  maintenance_tasks.names_must_match "Maintenance::*"
8
6
  why "the task runner resolves task constants from that namespace, so a task declared outside it never appears in the runner and cannot be run by anyone"
9
7
  end
10
-
11
- law "a maintenance task never invokes controller code" do
12
- tasks.must_not_call controllers
13
- why "a task runs from the runner or the console with no request around it, so controller code reached from one has nothing to read"
14
- end
15
8
  end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+
4
+ law "a concern never reaches the class that includes it" do
5
+ concerns.must_not_reach_includers
6
+ why "a mixin that knows its includer is half a class in hiding"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+ part :mutating_actions, files: "app/controllers/**", handles: [:post, :put, :patch, :delete]
4
+
5
+ law "a mutating action is authorized" do
6
+ mutating_actions.must_reach :policies
7
+ why "every write passes a policy before it touches a record"
8
+ mode :ratchet
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ part :service_objects, files: "app/services/**", kind: :symbol, where: { symbol_kind: "class" }, owns: :methods
3
+
4
+ law "a service answers to call" do
5
+ service_objects.must_define :call
6
+ why "one door per service, so a caller never reads it to find the verb"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+
4
+ law "background jobs never invoke controller code" do
5
+ jobs.must_not_call controllers
6
+ why "rendering from a job goes through ApplicationController.renderer"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ Enola.architecture "shop" do
2
+ part :billing, files: ["app/billing/**", "app/models/invoice.rb"]
3
+
4
+ law "billing is documented" do
5
+ billing.must_be_governed
6
+ since "2026-09-01"
7
+ why "code under a decision needs the page that decided it"
8
+ mode :ratchet
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ part :billing, files: ["app/billing/**", "app/models/invoice.rb"]
3
+
4
+ law "billing keeps to its own tables" do
5
+ billing.storage_must_stay_home
6
+ why "a part that writes another part's table owns a bug it cannot see"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+
4
+ law "frames keep their query budget" do
5
+ controllers.must_keep_budget metric: :queries, max: 20
6
+ why "a frame past twenty queries is a page that will not scale; refused by name until a capture exists"
7
+ mode :advisory
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+
4
+ law "jobs, models and mailers never depend on each other in a circle" do
5
+ jobs.must_not_cycle_with :models, :mailers
6
+ why "parts that reach each other in a circle cannot be taken apart"
7
+ mode :advisory
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ part :orders, files: ["app/orders/**", "app/models/order.rb"], public: ["app/orders/public/**"]
3
+
4
+ law "orders are reached through their public surface" do
5
+ orders.stays_inside
6
+ why "the public directory is the contract; everything else may change"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ Enola.architecture "shop" do
2
+ part :service_objects, files: "app/services/**", kind: :symbol, where: { symbol_kind: "class" }, owns: :methods
3
+
4
+ law "reach for an existing service" do
5
+ service_objects.advises "look in app/services before writing a new one"
6
+ why "duplication is a judgement no fact answers; advice where the edit happens is what can be offered honestly"
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ part :records, ancestor: "ApplicationRecord"
3
+
4
+ law "scopes come in pairs" do
5
+ records.names_must_match "with_*", requires: "without_*"
6
+ why "every with_ scope has a without_ sibling, or the query reads half a thought"
7
+ mode :advisory
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ Enola.architecture "shop" do
2
+ part :api, files: "config/**", kind: :route
3
+
4
+ law "the public api stays small" do
5
+ api.at_most 120
6
+ growth 5
7
+ why "a route is a promise; the count may grow, but only on purpose"
8
+ mode :ratchet
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "shop" do
2
+ rails
3
+
4
+ law "the request api stays in controllers" do
5
+ models.must_not_call "params", receiver: :none
6
+ why "params without a receiver is the controller's; a model reading it only works inside a request"
7
+ mode :ratchet
8
+ end
9
+ end
data/lib/enola-guides.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Enola
4
4
  module Guides
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "app" do
2
+ rails
3
+
4
+ law "background jobs never invoke controller code" do
5
+ jobs.must_not_call controllers
6
+ why "rendering from a job goes through ApplicationController.renderer"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "app" do
2
+ rails
3
+
4
+ law "models do not reach controllers" do
5
+ models.must_not_call controllers
6
+ why "a model that knows the request cannot be used off the request"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "app" do
2
+ rails
3
+
4
+ law "policies only answer" do
5
+ policies.must_not_call jobs
6
+ why "authorization is asked many times per request and sometimes speculatively"
7
+ mode :ratchet
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ Enola.architecture "app" do
2
+ rails
3
+
4
+ law "the request api stays in controllers" do
5
+ models.must_not_call "params", receiver: :none
6
+ why "params without a receiver is the controller's; a model reading it only works inside a request"
7
+ mode :ratchet
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enola-guides
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muhamed Isabegovic
@@ -29,7 +29,9 @@ files:
29
29
  - examples/laws/clean-rings/README.md
30
30
  - examples/laws/clean-rings/enola/constraints/clean.yaml
31
31
  - examples/laws/cluster-laws/README.md
32
- - examples/laws/cluster-laws/enola/constraints/cluster.rb
32
+ - examples/laws/cluster-laws/enola/constraints/a-mutating-action-is-authorized.rb
33
+ - examples/laws/cluster-laws/enola/constraints/every-api-route-has-a-consumer.rb
34
+ - examples/laws/cluster-laws/enola/constraints/one-owner-per-table.rb
33
35
  - examples/laws/cqrs-queries-never-write/README.md
34
36
  - examples/laws/cqrs-queries-never-write/enola/constraints/cqrs.yaml
35
37
  - examples/laws/foreign-keys/README.md
@@ -39,7 +41,8 @@ files:
39
41
  - examples/laws/instantiation/README.md
40
42
  - examples/laws/instantiation/enola/constraints/ceremony.yaml
41
43
  - examples/laws/maintenance-tasks/README.md
42
- - examples/laws/maintenance-tasks/enola/constraints/maintenance-tasks.rb
44
+ - examples/laws/maintenance-tasks/enola/constraints/a-maintenance-task-never-invokes-controller-code.rb
45
+ - examples/laws/maintenance-tasks/enola/constraints/every-maintenance-task-lives-in-the-maintenance-namespace.rb
43
46
  - examples/laws/mixins-stay-independent/README.md
44
47
  - examples/laws/mixins-stay-independent/enola/constraints/concerns.yaml
45
48
  - examples/laws/naming-conventions/README.md
@@ -79,7 +82,19 @@ files:
79
82
  - examples/laws/vanilla-rails-stays-empty/README.md
80
83
  - examples/laws/vanilla-rails-stays-empty/enola/constraints/vanilla.yaml
81
84
  - examples/rails-shop/enola.yaml
82
- - examples/rails-shop/enola/constraints/laws.rb
85
+ - examples/rails-shop/enola/constraints/a-concern-never-reaches-the-class-that-includes-it.rb
86
+ - examples/rails-shop/enola/constraints/a-mutating-action-is-authorized.rb
87
+ - examples/rails-shop/enola/constraints/a-service-answers-to-call.rb
88
+ - examples/rails-shop/enola/constraints/background-jobs-never-invoke-controller-code.rb
89
+ - examples/rails-shop/enola/constraints/billing-is-documented.rb
90
+ - examples/rails-shop/enola/constraints/billing-keeps-to-its-own-tables.rb
91
+ - examples/rails-shop/enola/constraints/frames-keep-their-query-budget.rb
92
+ - examples/rails-shop/enola/constraints/jobs-models-and-mailers-never-depend-on-each-other-in-a-circle.rb
93
+ - examples/rails-shop/enola/constraints/orders-are-reached-through-their-public-surface.rb
94
+ - examples/rails-shop/enola/constraints/reach-for-an-existing-service.rb
95
+ - examples/rails-shop/enola/constraints/scopes-come-in-pairs.rb
96
+ - examples/rails-shop/enola/constraints/the-public-api-stays-small.rb
97
+ - examples/rails-shop/enola/constraints/the-request-api-stays-in-controllers.rb
83
98
  - guides/01-start-here.md
84
99
  - guides/02-rails.md
85
100
  - guides/03-ember.md
@@ -92,7 +107,10 @@ files:
92
107
  - recipes/README.md
93
108
  - recipes/ember-conventions.yaml
94
109
  - recipes/house-recipe-template.yaml
95
- - templates/constraints-starter.rb
110
+ - templates/constraints-starter/background-jobs-never-invoke-controller-code.rb
111
+ - templates/constraints-starter/models-do-not-reach-controllers.rb
112
+ - templates/constraints-starter/policies-only-answer.rb
113
+ - templates/constraints-starter/the-request-api-stays-in-controllers.rb
96
114
  - templates/enola-check.sh
97
115
  - templates/enola-cluster.yaml
98
116
  - templates/enola-findings.rb
@@ -1,24 +0,0 @@
1
- Enola.architecture "platform" do
2
- part :tables, files: "app/models/**", kind: :storage
3
- part :mutating_actions, service: :backend, files: "app/controllers/**", handles: [:post, :put, :patch, :delete]
4
- part :policies, service: :backend, files: "app/policies/**"
5
- part :api, service: :backend, files: "config/**", kind: :route
6
-
7
- law "one owner per table" do
8
- tables.must_be_unique_across by: :table
9
- why "a table two repositories both model is written by two codebases that never see each other's validations or callbacks"
10
- mode :advisory
11
- end
12
-
13
- law "a mutating action is authorized" do
14
- mutating_actions.must_reach :policies
15
- why "an action behind a POST, PUT, PATCH or DELETE route changes state, and the policy call is the one place the change is authorized"
16
- mode :advisory
17
- end
18
-
19
- law "every api route has a consumer" do
20
- api.must_have_consumer
21
- why "a route nobody calls is a surface nobody maintains"
22
- mode :advisory
23
- end
24
- end
@@ -1,93 +0,0 @@
1
- # The Ruby DSL, end to end, for a Rails shop. Parsed by enola, never
2
- # executed. Every sentence below compiles to a rule form the YAML also
3
- # accepts; `enola constraints lint .` shows what each part resolved to.
4
- Enola.architecture "shop" do
5
- rails
6
-
7
- part :billing, files: ["app/billing/**", "app/models/invoice.rb"]
8
- part :orders, files: ["app/orders/**", "app/models/order.rb"], public: ["app/orders/public/**"]
9
- part :records, ancestor: "ApplicationRecord"
10
- part :mutating_actions, files: "app/controllers/**", handles: [:post, :put, :patch, :delete]
11
- part :service_objects, files: "app/services/**", kind: :symbol, where: { symbol_kind: "class" }, owns: :methods
12
- part :api, files: "config/**", kind: :route
13
- part :tables, files: "app/models/**", kind: :storage
14
-
15
- law "background jobs never invoke controller code" do
16
- jobs.must_not_call controllers
17
- why "rendering from a job goes through ApplicationController.renderer"
18
- mode :ratchet
19
- end
20
-
21
- law "the request api stays in controllers" do
22
- models.must_not_call "params", receiver: :none
23
- why "params without a receiver is the controller's; a model reading it only works inside a request"
24
- mode :ratchet
25
- end
26
-
27
- law "billing keeps to its own tables" do
28
- billing.storage_must_stay_home
29
- why "a part that writes another part's table owns a bug it cannot see"
30
- mode :ratchet
31
- end
32
-
33
- law "orders are reached through their public surface" do
34
- orders.stays_inside
35
- why "the public directory is the contract; everything else may change"
36
- mode :ratchet
37
- end
38
-
39
- law "a mutating action is authorized" do
40
- mutating_actions.must_reach :policies
41
- why "every write passes a policy before it touches a record"
42
- mode :ratchet
43
- end
44
-
45
- law "a concern never reaches the class that includes it" do
46
- concerns.must_not_reach_includers
47
- why "a mixin that knows its includer is half a class in hiding"
48
- mode :ratchet
49
- end
50
-
51
- law "jobs, models and mailers never depend on each other in a circle" do
52
- jobs.must_not_cycle_with :models, :mailers
53
- why "parts that reach each other in a circle cannot be taken apart"
54
- mode :advisory
55
- end
56
-
57
- law "a service answers to call" do
58
- service_objects.must_define :call
59
- why "one door per service, so a caller never reads it to find the verb"
60
- mode :ratchet
61
- end
62
-
63
- law "scopes come in pairs" do
64
- records.names_must_match "with_*", requires: "without_*"
65
- why "every with_ scope has a without_ sibling, or the query reads half a thought"
66
- mode :advisory
67
- end
68
-
69
- law "the public api stays small" do
70
- api.at_most 120
71
- growth 5
72
- why "a route is a promise; the count may grow, but only on purpose"
73
- mode :ratchet
74
- end
75
-
76
- law "frames keep their query budget" do
77
- controllers.must_keep_budget metric: :queries, max: 20
78
- why "a frame past twenty queries is a page that will not scale; refused by name until a capture exists"
79
- mode :advisory
80
- end
81
-
82
- law "billing is documented" do
83
- billing.must_be_governed
84
- since "2026-09-01"
85
- why "code under a decision needs the page that decided it"
86
- mode :ratchet
87
- end
88
-
89
- law "reach for an existing service" do
90
- service_objects.advises "look in app/services before writing a new one"
91
- why "duplication is a judgement no fact answers; advice where the edit happens is what can be offered honestly"
92
- end
93
- end
@@ -1,30 +0,0 @@
1
- # A first declaration for a Rails application. Copy to enola/constraints/
2
- # and keep the laws you agree with; every law carries its reason, and
3
- # ratchet mode fails only what a change adds.
4
- Enola.architecture "app" do
5
- rails
6
-
7
- law "background jobs never invoke controller code" do
8
- jobs.must_not_call controllers
9
- why "rendering from a job goes through ApplicationController.renderer"
10
- mode :ratchet
11
- end
12
-
13
- law "models do not reach controllers" do
14
- models.must_not_call controllers
15
- why "a model that knows the request cannot be used off the request"
16
- mode :ratchet
17
- end
18
-
19
- law "policies only answer" do
20
- policies.must_not_call jobs
21
- why "authorization is asked many times per request and sometimes speculatively"
22
- mode :ratchet
23
- end
24
-
25
- law "the request api stays in controllers" do
26
- models.must_not_call "params", receiver: :none
27
- why "params without a receiver is the controller's; a model reading it only works inside a request"
28
- mode :ratchet
29
- end
30
- end