rails_ai_admin 0.1.0

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 (193) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +458 -0
  3. data/LICENSE +21 -0
  4. data/README.md +292 -0
  5. data/SECURITY.md +14 -0
  6. data/THIRD_PARTY_NOTICES.md +19 -0
  7. data/app/assets/builds/rails_ai_admin.LICENSE.txt +55 -0
  8. data/app/assets/builds/rails_ai_admin.css +345 -0
  9. data/app/assets/builds/rails_ai_admin.js +33 -0
  10. data/app/controllers/rails_ai_admin/application_controller.rb +255 -0
  11. data/app/controllers/rails_ai_admin/assistant_controller.rb +164 -0
  12. data/app/controllers/rails_ai_admin/audit_controller.rb +16 -0
  13. data/app/controllers/rails_ai_admin/collection_jobs_controller.rb +33 -0
  14. data/app/controllers/rails_ai_admin/collection_operations_controller.rb +79 -0
  15. data/app/controllers/rails_ai_admin/custom_controller.rb +26 -0
  16. data/app/controllers/rails_ai_admin/dashboard_controller.rb +17 -0
  17. data/app/controllers/rails_ai_admin/exports_controller.rb +31 -0
  18. data/app/controllers/rails_ai_admin/files_controller.rb +37 -0
  19. data/app/controllers/rails_ai_admin/imports_controller.rb +41 -0
  20. data/app/controllers/rails_ai_admin/mcp_controller.rb +81 -0
  21. data/app/controllers/rails_ai_admin/mcp_tokens_controller.rb +45 -0
  22. data/app/controllers/rails_ai_admin/operations_controller.rb +105 -0
  23. data/app/controllers/rails_ai_admin/references_controller.rb +16 -0
  24. data/app/controllers/rails_ai_admin/resources_controller.rb +290 -0
  25. data/app/controllers/rails_ai_admin/search_controller.rb +39 -0
  26. data/app/controllers/rails_ai_admin/selections_controller.rb +95 -0
  27. data/app/controllers/rails_ai_admin/surfaces_controller.rb +122 -0
  28. data/app/helpers/rails_ai_admin/dashboard_helper.rb +28 -0
  29. data/app/helpers/rails_ai_admin/fields_helper.rb +242 -0
  30. data/app/helpers/rails_ai_admin/filters_helper.rb +40 -0
  31. data/app/helpers/rails_ai_admin/history_helper.rb +36 -0
  32. data/app/helpers/rails_ai_admin/navigation_helper.rb +54 -0
  33. data/app/helpers/rails_ai_admin/tool_views_helper.rb +48 -0
  34. data/app/jobs/rails_ai_admin/assistant_turn_job.rb +15 -0
  35. data/app/jobs/rails_ai_admin/collections/execution_job.rb +12 -0
  36. data/app/jobs/rails_ai_admin/outbox/delivery_job.rb +13 -0
  37. data/app/models/rails_ai_admin/application_record.rb +8 -0
  38. data/app/models/rails_ai_admin/audit_event.rb +12 -0
  39. data/app/models/rails_ai_admin/batch_item.rb +8 -0
  40. data/app/models/rails_ai_admin/operation_run.rb +20 -0
  41. data/app/models/rails_ai_admin/selection.rb +9 -0
  42. data/app/models/rails_ai_admin/selection_item.rb +9 -0
  43. data/app/models/rails_ai_admin/work_item.rb +18 -0
  44. data/app/views/layouts/rails_ai_admin/application.html.erb +49 -0
  45. data/app/views/layouts/rails_ai_admin/frame.html.erb +5 -0
  46. data/app/views/layouts/rails_ai_admin/status.html.erb +13 -0
  47. data/app/views/rails_ai_admin/assistant/_ask.html.erb +16 -0
  48. data/app/views/rails_ai_admin/assistant/_transcript.html.erb +45 -0
  49. data/app/views/rails_ai_admin/assistant/frame.html.erb +1 -0
  50. data/app/views/rails_ai_admin/assistant/index.html.erb +14 -0
  51. data/app/views/rails_ai_admin/assistant/show.html.erb +44 -0
  52. data/app/views/rails_ai_admin/audit/index.html.erb +40 -0
  53. data/app/views/rails_ai_admin/collection_jobs/index.html.erb +5 -0
  54. data/app/views/rails_ai_admin/collection_jobs/show.html.erb +24 -0
  55. data/app/views/rails_ai_admin/collection_operations/confirmation.html.erb +25 -0
  56. data/app/views/rails_ai_admin/collection_operations/failure.html.erb +10 -0
  57. data/app/views/rails_ai_admin/collection_operations/new.html.erb +11 -0
  58. data/app/views/rails_ai_admin/dashboard/index.html.erb +33 -0
  59. data/app/views/rails_ai_admin/fields/_index.html.erb +1 -0
  60. data/app/views/rails_ai_admin/fields/_input.html.erb +21 -0
  61. data/app/views/rails_ai_admin/fields/_reference.html.erb +1 -0
  62. data/app/views/rails_ai_admin/fields/_reference_picker.html.erb +14 -0
  63. data/app/views/rails_ai_admin/fields/_row.html.erb +27 -0
  64. data/app/views/rails_ai_admin/fields/_show.html.erb +1 -0
  65. data/app/views/rails_ai_admin/imports/new.html.erb +34 -0
  66. data/app/views/rails_ai_admin/mcp_tokens/index.html.erb +33 -0
  67. data/app/views/rails_ai_admin/operations/confirmation.html.erb +32 -0
  68. data/app/views/rails_ai_admin/operations/failure.html.erb +5 -0
  69. data/app/views/rails_ai_admin/operations/form.html.erb +13 -0
  70. data/app/views/rails_ai_admin/resources/_associations.html.erb +12 -0
  71. data/app/views/rails_ai_admin/resources/_errors.html.erb +14 -0
  72. data/app/views/rails_ai_admin/resources/_recovery.html.erb +5 -0
  73. data/app/views/rails_ai_admin/resources/confirm_destroy.html.erb +11 -0
  74. data/app/views/rails_ai_admin/resources/edit.html.erb +1 -0
  75. data/app/views/rails_ai_admin/resources/form.html.erb +16 -0
  76. data/app/views/rails_ai_admin/resources/history.html.erb +27 -0
  77. data/app/views/rails_ai_admin/resources/index.html.erb +88 -0
  78. data/app/views/rails_ai_admin/resources/new.html.erb +1 -0
  79. data/app/views/rails_ai_admin/resources/show.html.erb +12 -0
  80. data/app/views/rails_ai_admin/search/index.html.erb +20 -0
  81. data/app/views/rails_ai_admin/selections/confirm_destroy.html.erb +13 -0
  82. data/app/views/rails_ai_admin/selections/destroyed.html.erb +15 -0
  83. data/app/views/rails_ai_admin/selections/show.html.erb +19 -0
  84. data/app/views/rails_ai_admin/shared/_input_fields.html.erb +23 -0
  85. data/app/views/rails_ai_admin/shared/_navigation.html.erb +8 -0
  86. data/app/views/rails_ai_admin/shared/_session.html.erb +5 -0
  87. data/app/views/rails_ai_admin/statuses/show.html.erb +4 -0
  88. data/app/views/rails_ai_admin/surfaces/_operation_review.html.erb +43 -0
  89. data/app/views/rails_ai_admin/surfaces/show.html.erb +4 -0
  90. data/config/locales/en.yml +549 -0
  91. data/config/routes.rb +64 -0
  92. data/db/assistant_migrate/20261103000001_create_rails_ai_admin_assistant.rb +138 -0
  93. data/db/assistant_migrate/20261112000001_upgrade_rails_ai_admin_assistant_to_ruby_llm_2_2.rb +102 -0
  94. data/db/assistant_migrate/20261114000001_add_streaming_and_access_tokens_to_rails_ai_admin_assistant.rb +29 -0
  95. data/db/migrate/20261029000001_create_rails_ai_admin_execution_tables.rb +35 -0
  96. data/db/migrate/20261029000002_add_callback_warning_to_rails_ai_admin_runs.rb +7 -0
  97. data/db/migrate/20261030000003_create_rails_ai_admin_work_items.rb +26 -0
  98. data/db/migrate/20261030000004_create_rails_ai_admin_selections.rb +28 -0
  99. data/db/migrate/20261030000005_create_rails_ai_admin_collection_runs.rb +41 -0
  100. data/db/migrate/20261113000001_add_record_index_to_rails_ai_admin_audit_events.rb +8 -0
  101. data/lib/generators/rails_ai_admin/assistant/assistant_generator.rb +25 -0
  102. data/lib/generators/rails_ai_admin/assistant/templates/admin_assistant.rb +18 -0
  103. data/lib/generators/rails_ai_admin/engine_migrations.rb +42 -0
  104. data/lib/generators/rails_ai_admin/install/engine_mounts.rb +19 -0
  105. data/lib/generators/rails_ai_admin/install/install_generator.rb +53 -0
  106. data/lib/generators/rails_ai_admin/install/templates/access_test.rb +17 -0
  107. data/lib/generators/rails_ai_admin/install/templates/admin_context.rb +25 -0
  108. data/lib/generators/rails_ai_admin/install/templates/admin_policy_adapter.rb +28 -0
  109. data/lib/generators/rails_ai_admin/install/templates/example_admin.rb +10 -0
  110. data/lib/generators/rails_ai_admin/install/templates/initializer.rb +7 -0
  111. data/lib/generators/rails_ai_admin/override/override_generator.rb +46 -0
  112. data/lib/generators/rails_ai_admin/resource/resource_generator.rb +88 -0
  113. data/lib/rails_ai_admin/assistant/continuation.rb +33 -0
  114. data/lib/rails_ai_admin/assistant/coordinator.rb +306 -0
  115. data/lib/rails_ai_admin/assistant/records.rb +71 -0
  116. data/lib/rails_ai_admin/assistant/runtime.rb +49 -0
  117. data/lib/rails_ai_admin/assistant/tools.rb +477 -0
  118. data/lib/rails_ai_admin/assistant/transcript.rb +140 -0
  119. data/lib/rails_ai_admin/assistant.rb +50 -0
  120. data/lib/rails_ai_admin/authorization/access.rb +296 -0
  121. data/lib/rails_ai_admin/authorization/adapter.rb +92 -0
  122. data/lib/rails_ai_admin/authorization/pundit_adapter.rb +195 -0
  123. data/lib/rails_ai_admin/collections/claim.rb +91 -0
  124. data/lib/rails_ai_admin/collections/contract.rb +113 -0
  125. data/lib/rails_ai_admin/collections/dispatcher.rb +126 -0
  126. data/lib/rails_ai_admin/collections/queries.rb +79 -0
  127. data/lib/rails_ai_admin/collections/result.rb +15 -0
  128. data/lib/rails_ai_admin/collections/runner.rb +208 -0
  129. data/lib/rails_ai_admin/configuration.rb +178 -0
  130. data/lib/rails_ai_admin/context.rb +29 -0
  131. data/lib/rails_ai_admin/doctor.rb +301 -0
  132. data/lib/rails_ai_admin/engine.rb +24 -0
  133. data/lib/rails_ai_admin/error.rb +16 -0
  134. data/lib/rails_ai_admin/field.rb +625 -0
  135. data/lib/rails_ai_admin/fields/association.rb +188 -0
  136. data/lib/rails_ai_admin/fields/computation.rb +43 -0
  137. data/lib/rails_ai_admin/fields/dependency_graph.rb +45 -0
  138. data/lib/rails_ai_admin/fields/file_value.rb +23 -0
  139. data/lib/rails_ai_admin/fields/hook_signatures.rb +18 -0
  140. data/lib/rails_ai_admin/fields/projection.rb +78 -0
  141. data/lib/rails_ai_admin/fields/registry.rb +48 -0
  142. data/lib/rails_ai_admin/fields/scalar_schema.rb +49 -0
  143. data/lib/rails_ai_admin/fields/type.rb +50 -0
  144. data/lib/rails_ai_admin/forms/plan.rb +90 -0
  145. data/lib/rails_ai_admin/input_schema.rb +76 -0
  146. data/lib/rails_ai_admin/integrations/propose_operation.rb +150 -0
  147. data/lib/rails_ai_admin/integrations/tool_views.rb +367 -0
  148. data/lib/rails_ai_admin/mcp.rb +130 -0
  149. data/lib/rails_ai_admin/navigation/list_state.rb +194 -0
  150. data/lib/rails_ai_admin/navigation/menu.rb +31 -0
  151. data/lib/rails_ai_admin/navigation/settings.rb +28 -0
  152. data/lib/rails_ai_admin/operation.rb +120 -0
  153. data/lib/rails_ai_admin/operations/default_handlers.rb +17 -0
  154. data/lib/rails_ai_admin/operations/execution_context.rb +38 -0
  155. data/lib/rails_ai_admin/operations/form_intent.rb +69 -0
  156. data/lib/rails_ai_admin/operations/registry.rb +80 -0
  157. data/lib/rails_ai_admin/operations/result.rb +21 -0
  158. data/lib/rails_ai_admin/operations/runner.rb +633 -0
  159. data/lib/rails_ai_admin/operations/runner_fingerprint.rb +12 -0
  160. data/lib/rails_ai_admin/outbox/delivery_context.rb +51 -0
  161. data/lib/rails_ai_admin/outbox/dispatcher.rb +189 -0
  162. data/lib/rails_ai_admin/outbox/registry.rb +36 -0
  163. data/lib/rails_ai_admin/outbox/request_digest.rb +42 -0
  164. data/lib/rails_ai_admin/outbox/writer.rb +43 -0
  165. data/lib/rails_ai_admin/presentation/association_panel.rb +90 -0
  166. data/lib/rails_ai_admin/presentation/audit_log.rb +63 -0
  167. data/lib/rails_ai_admin/presentation/csv_export.rb +85 -0
  168. data/lib/rails_ai_admin/presentation/csv_import.rb +142 -0
  169. data/lib/rails_ai_admin/presentation/dashboard.rb +122 -0
  170. data/lib/rails_ai_admin/presentation/history.rb +46 -0
  171. data/lib/rails_ai_admin/presentation/index_settings.rb +77 -0
  172. data/lib/rails_ai_admin/presentation/outcomes.rb +44 -0
  173. data/lib/rails_ai_admin/presentation/status.rb +40 -0
  174. data/lib/rails_ai_admin/prune.rb +61 -0
  175. data/lib/rails_ai_admin/queries/list.rb +162 -0
  176. data/lib/rails_ai_admin/queries/named_scope.rb +65 -0
  177. data/lib/rails_ai_admin/record_version.rb +40 -0
  178. data/lib/rails_ai_admin/registry.rb +45 -0
  179. data/lib/rails_ai_admin/request_log_filter.rb +24 -0
  180. data/lib/rails_ai_admin/resource.rb +249 -0
  181. data/lib/rails_ai_admin/resource_identity.rb +15 -0
  182. data/lib/rails_ai_admin/schema_suggestions.rb +105 -0
  183. data/lib/rails_ai_admin/selections/builder.rb +162 -0
  184. data/lib/rails_ai_admin/templates/catalog.rb +84 -0
  185. data/lib/rails_ai_admin/templates/inspector.rb +94 -0
  186. data/lib/rails_ai_admin/templates/metadata.rb +48 -0
  187. data/lib/rails_ai_admin/templates/safe_paths.rb +30 -0
  188. data/lib/rails_ai_admin/test_kit.rb +103 -0
  189. data/lib/rails_ai_admin/version.rb +5 -0
  190. data/lib/rails_ai_admin/work.rb +48 -0
  191. data/lib/rails_ai_admin.rb +112 -0
  192. data/lib/tasks/rails_ai_admin.rake +58 -0
  193. metadata +328 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7042f0c3064d4167940e117fd383145a5895c30b994d278af6027356c0cf0c0f
4
+ data.tar.gz: b10059058a63f1db272d5d70094056647f9136efb461072d29a1c64d37a4f158
5
+ SHA512:
6
+ metadata.gz: 8c1982280acc535eda89d0e4f82992fe0e337880f60839777ede4294100b1345c7719e378cba727d0d1913a8e77b5aca92801c500cd84fad367b4ca4dddf16aa
7
+ data.tar.gz: a0b82dd63d10aa94bae4550de5331cebd4a5834b6d624a7c32f3e9e60276cd2995aa778126f2f1898b3934ec9e504d74239a0e4b75a5b25c15e3f93f89b04f70
data/CHANGELOG.md ADDED
@@ -0,0 +1,458 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-11-13)
4
+
5
+ First Public Preview. Requires Ruby 3.3 or newer, Rails 8.0.5.2 or newer
6
+ below 8.2 and SQLite or PostgreSQL. Use Rails 8.1.4.1 or newer on the 8.1
7
+ series and keep `json` below 3 on Rails 8.0. Native admin works without AI.
8
+
9
+ Preview limits include association sorting, polymorphic writes, nested child
10
+ forms and separate attach/detach grants. Collection selections cover at most
11
+ 100 explicitly selected targets. Chat has a per-person daily message limit.
12
+ Token and cost budgets, automatic conversation retention and native-provider
13
+ and live failure-recovery verification are open. Live provider evidence
14
+ covers an earlier build via OpenRouter. English ships with the engine. A
15
+ human screen-reader pass remains open. APIs, templates and storage may
16
+ change across 0.x releases. See the [upgrade guide](docs/site/_reference/upgrading.md)
17
+ for existing development hosts.
18
+
19
+ ### Changes
20
+
21
+ - Give Admin Chat a scrollable conversation and a persistent composer, with
22
+ keyboard shortcuts, live reply following and inline tool and review cards.
23
+ Update the offline demo to stream readable tool summaries and confirm reviewed
24
+ changes in the same conversation.
25
+ - Refine the overview, navigation, list controls, tables and forms in light and
26
+ dark mode. Bound list searches so wide records scroll inside their table region.
27
+
28
+ - MCP server: with `config.mcp = true` (on top of the assistant setup),
29
+ `POST <admin>/mcp` serves the admin Chat tools to agents such as Claude Code or
30
+ Cursor over MCP's Streamable HTTP transport. People issue, list and revoke
31
+ personal access tokens on an MCP access page (shown once, stored as SHA-256,
32
+ bound to owner, tenant and security version and re-resolved through
33
+ `resolve_job` on every request). Proposals return a `review_url` the person
34
+ confirms in the admin. New assistant migration
35
+ `add_streaming_and_access_tokens_to_rails_ai_admin_assistant`; `mcp` is a
36
+ reserved resource key.
37
+ - Streaming: admin Chat replies stream into the conversation as they are
38
+ written (saved on the turn under its lease and polled), and chat text is now
39
+ escaped before formatting so model markup never renders as links or images.
40
+ - Admin Chat: resources may declare `assistant_changes :create, :update,
41
+ :destroy`, and a new `propose_change` tool turns a model's suggestion into a
42
+ review showing before → after (creates included); only the person's
43
+ confirmation writes, as that person, with a version check and audit. A new
44
+ `record_history` tool reads audited changes behind `view_history?`. Record
45
+ and list pages offer "Ask the assistant", which starts a chat with a
46
+ server-checked `Context:` line. `describe_resource` lists allowed changes;
47
+ the prompt is version 3; the offline evaluation set has 23 questions.
48
+ - Dashboard widgets: `dashboard { metric :drafts, scope: :drafts; trend
49
+ :created_at, days: 30 }` adds counts over granted list tabs and daily trend
50
+ charts (inline SVG with a data table) to the overview, through the list's
51
+ policy relation and field read grants.
52
+ - CSV import: with `import_records?` and the create grant, an Import CSV page
53
+ checks a file without writing, then creates one record per valid row through
54
+ the native create operation (own policy check, validations and audit), and
55
+ lists the rows it could not create. Columns match writable create fields by
56
+ label or name; exported files import back. `config.import_limit` (default
57
+ 500) bounds a file.
58
+ - Audit log: `<admin>/audit` lists the tenant's audit events across records for
59
+ resources granting `view_audit_log?(context:, resource:)`, filterable by
60
+ resource, change, outcome and actor, with field names under current grants.
61
+ - Association panels offer "Add <child>" when the actor may create a child with a
62
+ writable reference back to the parent. New forms accept
63
+ `prefill[<belongs_to>]=<key>` for writable references to visible targets;
64
+ other prefills are ignored.
65
+ - `files` fields edit `has_many_attached` attachments: remove ticked files and add
66
+ new uploads without replacing the list, with per-file `accept`/`max_size` and a
67
+ `max_files` bound (default 20). Removed blobs are purged after commit; the
68
+ record is touched and audited; show pages render a gallery whose downloads
69
+ name their attachment and are checked like single files.
70
+ - `bin/demo` now adds articles, tags and summaries to the demo host by default
71
+ (`--plain` leaves them out): every field type, cover and gallery images, rich
72
+ text, tags, history, the audit log, CSV export and import (with a sample file),
73
+ bulk delete and overview metrics and trends for articles and orders. `json` and `rich_text` fields stay off list pages unless declared
74
+ `index: true`. The selection page no longer shows raw record versions, and
75
+ rich-text and many-to-many inputs are named by their visible label instead of
76
+ a `<label for>` that pointed at a non-form element.
77
+ - Search everything: a header search box (shown when the actor may search at
78
+ least one menu resource) opens `<admin>/search`, which runs each resource's own
79
+ list search and shows up to five records per resource through their show
80
+ grants. **Breaking:** `search` is now a reserved resource key.
81
+ - The overview shows record counts for resources whose list opts into exact
82
+ counts, with the list's bound. Dark mode already follows the system setting.
83
+ - Associations: `has_one :profile` shows a record's single child as a panel,
84
+ with the same grants as `has_many` panels. A `references :tags` field edits a
85
+ `has_many`/`:through`/HABTM list through `tag_ids=`: checkboxes for up to 100
86
+ visible targets (a search picker beyond), only currently visible targets may be
87
+ added, hidden stored targets are always kept, a changed list touches the record
88
+ so its version advances and the audit names the field, and CSV, Chat and show
89
+ pages label targets through their own grants.
90
+ - Rich text: a `rich_text` field edits a `has_rich_text` attribute with Trix from
91
+ the host's Action Text assets (loaded only on forms that need it; file
92
+ attachments refused). Show pages sanitize the stored HTML; lists, CSV and
93
+ Chat use plain text; audit names the field when the content changes.
94
+ - File uploads: a `file` field for a `has_one_attached` attachment, with
95
+ `accept:` content types and `max_size:` (default 10 MB). Uploads become new
96
+ blobs only for fields the actor may write; the Runner accepts only new,
97
+ unattached blobs that fit; refused writes purge them; a remove box clears an
98
+ optional file; audit names the field. Downloads go through
99
+ `<admin>/<resource>/<id>/files/<field>` with the record's scope, show grant
100
+ and field read grant, streamed with a sandboxed CSP; only raster images show
101
+ inline. Form recovery skips chosen files instead of failing.
102
+ - Bulk delete: a fixed selection offers "Delete the N selected records" when the
103
+ resource allows `destroy` and the actor may delete at least one of them. After
104
+ a review page, each record is deleted on its own through the native destroy
105
+ operation (own policy check, version, transaction and audit); records that
106
+ cannot be deleted are kept and listed with the reason. A changed selection
107
+ deletes nothing. `Selections::Builder#revalidate` now yields current records
108
+ to a block.
109
+ - CSV export: a default-deny `export_records?(context:, resource:)` grant (Pundit:
110
+ `export_records?`) adds an Export CSV button that POSTs the current search,
111
+ list tab, filters and sort to `<admin>/<resource>/exports`. Rows and columns
112
+ follow the index, show and read grants; references export their labels;
113
+ formula-like text is neutralized; `config.export_limit` (default 10,000)
114
+ bounds a file, and each export is audited.
115
+ - Record History: with a new default-deny `view_history?(context:, resource:,
116
+ record:)` grant (Pundit: `view_history?`), a record's page links to
117
+ `<admin>/<resource>/<id>/history`, its audit trail newest first (50 per
118
+ page): time, change, changed fields named only when currently readable or
119
+ writable, actor and origin. Rejected writes now record their target, so a
120
+ lost edit appears as "Not saved". A context adapter may answer
121
+ `actor_labels(context:, actor_refs:)` to show names. New engine migration
122
+ `add_record_index_to_rails_ai_admin_audit_events`.
123
+ - New field types: `time` (time of day), `email` (mailto link), `url` (only
124
+ http/https addresses become links), `json` (indented editing and display on
125
+ json/jsonb columns) and write-only `password` for `has_secure_password`. No
126
+ read grant reveals a password; an empty box keeps the current one; audit
127
+ names the field; input digests store a keyed hash of it. Schema suggestions
128
+ offer `email`, `url`, `time` and `json` from column types and names.
129
+ **Breaking:** a registered field type named `email`, `url`, `time`, `json` or
130
+ `password` must be renamed, because those keys are now built in.
131
+ - Models no longer need a `lock_version` column. Without one, `updated_at`
132
+ carries the record version (whole microseconds), compared after a row-locked
133
+ load inside the write transaction; forms, intents, selections, collection
134
+ items and Work delivery all use it. `updated_at` then cannot be a writable
135
+ field, and doctor reports `version=lock_version`, `version=updated_at` or
136
+ `version=missing` instead of `lock_version=true/false`.
137
+ - Framework I18n: every page heading, button, notice, status page, field
138
+ validation message, Chat message and script message reads
139
+ `config/locales/en.yml` (`rails_ai_admin.*`), and `<html lang>` follows
140
+ `I18n.locale`. A new Translations guide shows how to add a locale. The
141
+ English text is unchanged, except that the collection job backlog hint now
142
+ renders the queue name as code instead of escaped `<code>` text. Host
143
+ layout overrides keep working; their script messages stay English until
144
+ they add `data-raa-messages` to `<body>`.
145
+ - Security regression sweep (RAA-0210): every state-changing engine route,
146
+ including Surface and Chat routes, rejects a missing CSRF token without a
147
+ side effect; unwritable, framework and tenant attributes are never mass
148
+ assigned; record text and request values are escaped on every page; list
149
+ and selection pages keep a constant query count as rows grow.
150
+ - Reference inputs past 100 targets keep the typed key input and add a search
151
+ box that fills it. `GET <admin>/<target>/references/search?q=` returns at
152
+ most 20 `{id, label}` results through the target's own policy relation,
153
+ search grants and per-record show grant, plus an exact key match; filters
154
+ use the same picker (RAA-030).
155
+ - Dependencies are on their latest releases: minitest 6.1.0, prism 2.1.0,
156
+ Bundler 4.0.24, jekyll-vitepress-theme 1.12.0, Host B esbuild 0.28.2, and
157
+ CI on ruby/setup-ruby v1.338.0 and Node 26. Ruby 4.0.9 and Rails 8.1.4.1
158
+ were already current; the Rails 8.0 lock stays on 8.0.5.2 and json 2.x.
159
+ - Admin Chat runs on RubyLLM 2.2.0 and now requires it (`>= 2.2.0, < 3`).
160
+ RubyLLM 2.2 broke Chat on the old 2.1 schema: a new
161
+ `upgrade_rails_ai_admin_assistant_to_ruby_llm_2_2` migration adds its claim,
162
+ phase, provider call id and usage columns and its queued-message and
163
+ chat-file tables, skipping what a host already has. The provider context is
164
+ bound before a turn's message is saved, since RubyLLM 2.2 builds its chat
165
+ then, and usage ownership uses `RubyLLM.with_owner`.
166
+ - `bin/demo` copies the packaged session/SQLite host to `tmp/demo`, seeds it
167
+ and serves it on 127.0.0.1 until Ctrl-C; `--assistant` adds admin Chat and a
168
+ review Surface against an offline fake provider in `script/demo`.
169
+ - Schema suggestions and doctor's sensitivity check treat `admin` and
170
+ `superuser` name parts as authority, so `users.admin` is no longer offered
171
+ as an editable field.
172
+ - A ten-minute quickstart guide goes from a Rails 8 app with the
173
+ authentication generator to a working Users admin, then to editing. The
174
+ generated `AdminContext` and `AdminPolicyAdapter` stay closed but carry a
175
+ commented, working example for that kind of app.
176
+ - `rails_ai_admin:resource Model --fields name:text points` writes the named
177
+ schema suggestions as active (still readonly) fields, titles the resource by
178
+ the first text field, and refuses a field the schema would not suggest or a
179
+ type that differs from it.
180
+ - Generator output links the guides in the source repository instead of
181
+ local `docs/` paths the gem does not ship, and the Chat generator names the
182
+ supported ruby_llm range. The overview no longer calls Chat, Surfaces and
183
+ associations later milestones (RAA-026).
184
+ - Support Ruby 3.3+ and Rails 8.0.5.2+ (was Ruby 4.0.9+ and Rails 8.1.4.1+).
185
+ A CI compatibility job runs the engine suite on Ruby 3.3 and 4.0 with Rails
186
+ 8.0 and 8.1, on SQLite and PostgreSQL. Engine migrations declare
187
+ `Migration[8.0]` (the same schema on 8.1); `json >= 2.13` is a dependency so
188
+ override headers reject duplicate keys on json 2.x too; doctor reports a
189
+ Rails 8.1 below the patched 8.1.4.1.
190
+ - The install and assistant generators keep an engine migration the host
191
+ already has, even with `--force`. Rails would otherwise remove a changed
192
+ one and copy it under a new timestamp, so an already-run migration ran
193
+ again.
194
+ - `ruby_llm` and `rails_tool_views` are no longer runtime dependencies, so a
195
+ conventional install pulls no AI code. Hosts that enable `config.assistant`
196
+ or `config.surfaces` add the gem themselves; boot checks the supported range
197
+ (`Configuration::OPTIONAL_GEMS`) (RAA-026).
198
+ - Make daily use pleasant (audit 2026-11-10). Model validation messages reach
199
+ the page for writable fields (`config.validation_messages = :generic` keeps
200
+ "is invalid"), and a field type's `valid?` may return a message (RAA-011).
201
+ Timestamps use a native `datetime-local` input in the context zone and display
202
+ as "30 Oct 2026 01:30 UTC" inside `<time>`; an unchanged save keeps stored
203
+ fractions of a second; long text keeps line breaks (RAA-015). Required fields
204
+ carry `required`, `aria-required` and a marker; readonly values are no longer
205
+ `<output>` live regions (RAA-023). Pages have specific titles and headings,
206
+ Cancel on edit returns to the record, the fixed "Development preview" became
207
+ `config.environment_label`, a `session_links` partial holds the signed-in
208
+ user, and a signed-out page visit redirects to `authentication_path` with
209
+ `return_to` (RAA-024). Lists put search beside the heading, fold filters into
210
+ `<details>`, add a page select-all and an Edit link per row (RAA-025). Codes
211
+ become sentences on forms, failure pages and job tables (RAA-027). Search is
212
+ trimmed and states its match mode; doctor names the fields it counts and gives
213
+ index advice that matches the SQL (RAA-021, RAA-026). Empty values sort last
214
+ (RAA-028); the collection review uses labels and formatting (RAA-029); only
215
+ canonical ids address a record (RAA-022); `/jobs` follows its menu grant
216
+ (RAA-030). Strings touched here moved to `config/locales/en.yml`.
217
+ - Make the assistant more trustworthy (audit 2026-11-10, partial). Searches
218
+ cover the whole policy relation unless the model names a granted scope, and
219
+ accept `sort`/`direction`; every result reports `applied_scope` and
220
+ `applied_sort`, and `describe_resource` lists scopes, sortable fields and each
221
+ search field's match mode (RAA-007, RAA-021). A new `count_records` tool
222
+ answers "how many" with the capped index count. Tool values are typed JSON
223
+ (null, booleans, integers, exact decimals, ISO times, `{value, label}`
224
+ selects, `{id, label, resource}` references); `PROMPT_VERSION` is 2
225
+ (RAA-017). Retryable provider failures schedule their own retry and the chat
226
+ shows "Retrying (n of 3)" (RAA-008). Activity lines come from the stored
227
+ tool result (RAA-018). A short assistant note precedes a new message after
228
+ an unanswered one (RAA-030). `config.assistant_daily_message_limit`
229
+ (default 100 per actor per 24 hours) is the minimal spend guard.
230
+ Review Surfaces show the proposed visible changes, offer **Dismiss** (which
231
+ expires the intent and tells the chat once), return to the chat after either
232
+ action, and get rails_tool_views' Stimulus controller from the admin bundle
233
+ (RAA-019).
234
+ - Unbreak ordinary flows (audit 2026-11-10). A list page leaves out an in-scope
235
+ row whose `show` is denied and says so instead of returning 404 for the whole
236
+ page; `TestKit.assert_scope_matches_show` finds the disagreement (RAA-001). An
237
+ association panel's "View all" link carries the new `scope=_none` list state so
238
+ the child's default tab no longer hides children the panel showed (RAA-006).
239
+ "Capture selection" with nothing ticked returns to the list with a notice,
240
+ duplicate ids collapse, and the button stays disabled until a row is ticked
241
+ (RAA-013). A delete blocked by a foreign key or `restrict_with_error` returns
242
+ the new `RESTRICTED` code with the model's reason instead of "Conflict… open a
243
+ fresh form" (RAA-012). Form pages no longer write: they issue a signed form
244
+ reference that becomes the intent on first submit or recovery, and
245
+ `rails_ai_admin:prune` removes expired unused intents and selections (RAA-005,
246
+ ADR 0025). Boot and doctor report a rails_tool_views `parent_controller` that
247
+ does not resolve when Surfaces are on (RAA-009). Job pages say when work is
248
+ waiting for a worker, doctor reports a backlog, and `config.queue_name`
249
+ makes the `rails_ai_admin` queue name configurable (RAA-020). Error summaries use
250
+ a sentence per result code with the code as secondary text.
251
+ - Stop silent data changes from conventional forms (audit 2026-11-10):
252
+ blank or whitespace-only text is stored as null in a nullable field and
253
+ rejected with "cannot be blank" when the field is `required` or
254
+ `nullable: false` (RAA-002, RAA-003); decimals honour the column's precision
255
+ and scale, or new `precision:`/`scale:` options, reject extra digits instead
256
+ of rounding and display padded to the scale (RAA-004, RAA-014); impossible
257
+ date-times such as `2026-02-30T10:00` are rejected (RAA-010); NUL and other
258
+ control characters are rejected in text input, with tab and line breaks
259
+ still allowed in `textarea` (RAA-016). The admin layout disables Turbo hover
260
+ prefetch so hovering a link no longer prepares an intent (RAA-005).
261
+ `required: true` now also rejects a null value.
262
+ - Reconcile the association/Chat branch with remote main, retaining the standalone
263
+ assistant proposal API and its explicit `assistant: true` opt-in. Admin Chat
264
+ now honors that flag too; native Surface permission alone grants no proposal.
265
+ - Fence assistant message persistence atomically against the current turn lease,
266
+ including late provider answers/tool calls and stale-worker cleanup. Recovery
267
+ removes abandoned placeholders without dropping billed usage.
268
+ - Fix Chat search pagination independently of native page size; byte-truncated
269
+ results return `next_offset` so omitted records remain reachable.
270
+ - Distinguish `.dev` builds from approved alpha/beta/RC versions in release checks;
271
+ published prereleases need versioned changelog/docs metadata and owner approval.
272
+ - Pin packaged consumers to Rails 8.1.4.1, discard stale generated locks and
273
+ verify installed candidate metadata and all files before acceptance. The
274
+ release checker rejects host Rails pins below the runtime floor.
275
+ - Raise the Rails dependency floor to 8.1.4.1 and refresh affected Ruby lockfiles
276
+ (Rails, Addressable, Loofah, Nokogiri and rails-html-sanitizer).
277
+
278
+ - Add opt-in admin Chat (`config.assistant`, ADR 0022). The
279
+ `rails_ai_admin:assistant` generator adds Engine-owned chat, message and turn
280
+ tables and a closed `AdminAssistant` adapter whose `llm_context(context:)`
281
+ returns a per-request `RubyLLM::Context`; global RubyLLM settings are never
282
+ read or changed, and conventional hosts load no RubyLLM code.
283
+ - Add the default-deny `assistant?(context:, resource:)` grant (Pundit:
284
+ `assistant?`). Read tools (`list_resources`, `describe_resource`,
285
+ `search_records`, `get_record`) apply every current grant and return bounded
286
+ JSON with fixed error codes.
287
+ - Add `propose_operation`, which prepares an `origin: assistant` intent and
288
+ shows the existing review Surface in the conversation. The human's Surface
289
+ confirmation writes once and admits one continuation turn in the same
290
+ transaction.
291
+ - Add a persistent per-chat turn inbox: keyed admission, strict ordering,
292
+ leases with fencing, a once-only human message, reconciliation of an answer
293
+ persisted before a crash, retry, Stop and archive, plus
294
+ `rails_ai_admin:assistant:scan`/`drain`. Doctor reports the assistant setup
295
+ without calling the adapter or a provider.
296
+ - Fix `describe_resource` omitting the allowed values of an operation's `enum`
297
+ input. A live model guessed `triaged` for the triage `decision` and needed two
298
+ rejected proposals before trying `triage`; it now receives the choices.
299
+
300
+ - Add `belongs_to` reference fields. A reference is labelled and linked only
301
+ through the target resource's current relation, show grant and title, and an
302
+ index loads each reference column with one query. Missing, foreign and hidden
303
+ targets render the same `Customer #42` placeholder. Forms offer up to 100
304
+ visible targets (else a typed key); the Runner rejects a changed reference the
305
+ actor cannot see, keeps an unchanged one and maps a foreign-key race to
306
+ CONFLICT. References filter by `eq`; they cannot search or sort yet.
307
+ - Add readonly `has_many` show-page panels read through the child resource's
308
+ index grant, policy relation and a readable reference field, with a filtered
309
+ "View all" link while that field is filter-granted.
310
+ - Add `Field#column`; reads, writes, list queries, audit field names and doctor
311
+ checks now distinguish a field's name from its column. Doctor adds an
312
+ `associations:<resource>` reflection check.
313
+ - Add the `field_reference` and `resource_associations` override entries
314
+ (catalog now 29). **Review overrides:** `resource_show` advances to revision 3
315
+ and `field_form` to revision 2.
316
+ - The resource generator suggests a declared non-polymorphic, non-sensitive
317
+ `belongs_to` as a commented `belongs_to` field; tenant-like references
318
+ (account, tenant, organization, workspace, company, team) and other key
319
+ columns stay omitted.
320
+ - `rake build` names the package from `RailsAiAdmin::VERSION`, and
321
+ `rake release:check` reports release readiness without publishing.
322
+
323
+ - Merge Dependabot updates after verification: actions/checkout 7.0.1 and
324
+ actions/setup-node 7.1.0 (still SHA-pinned), jekyll-vitepress-theme 1.11.0,
325
+ esbuild 0.28.2 (prebuilt bundle rebuilt) and Minitest 6.0.6. Minitest 6
326
+ extracted `minitest/mock`, so `minitest-mock` is now a development dependency
327
+ and the packaged hosts pin Minitest `~> 6.0`.
328
+ - Add assistant operation proposals: `operation ..., assistant: true` and the
329
+ on-demand `Integrations::ProposeOperation` RubyLLM tool, which preflights an
330
+ `assistant`-origin intent and presents the review Surface; only the human's
331
+ Surface confirmation executes. Tool-call replays are idempotent.
332
+ - Record open rails_tool_views integration findings DEP-008..012.
333
+ - Add opt-in admin review Surfaces on the host-owned rails_tool_views runtime:
334
+ `config.surfaces`, `operation ..., surface: true`, admin-owned endpoints with an
335
+ explicit `raa:` Scope and a constant `raa_operation_review` component. A
336
+ Surface confirms the same native intent once through the shared Runner;
337
+ completed reviews need the receipt grant. Host settings are never changed.
338
+ - Add index table settings: declared columns, a default sort applied only while
339
+ granted, page sizes of 1..100 and exact counts bounded at 10,000 (no
340
+ tenant-global estimates). Cells no longer split words and compact values stay
341
+ on one line, so wide tables scroll (resource_index revision 5).
342
+ - Add gemspec homepage and source/changelog/bug-tracker metadata.
343
+ - Add typed list filters: `filterable:` fields with eq/gte/lte by scalar type, a
344
+ separate default-deny `:filter` field grant (Pundit `filterable_fields`),
345
+ contract-coerced Arel-bound values, canonical nested filter list hints and a
346
+ native filter form (resource_index revision 4). Doctor reviews unindexed
347
+ filterable columns. **Breaking:** TestKit field snapshots and
348
+ `assert_field_grants` now require a `filter` group.
349
+ - Update rack to 3.2.8 for GHSA-2j8w-xcrc-x985, GHSA-5v64-555j-wjxm,
350
+ GHSA-p8x9-v4hv-2w4g and GHSA-wvg4-6p58-3gh3.
351
+ - Add named list scopes: bounded index tabs with an optional default that are
352
+ intersected with the policy relation by primary key, need an independent
353
+ default-deny `named_scopes` grant (Pundit `permitted_named_scopes`), travel in
354
+ list hints and render as current-grant tabs (resource_index revision 3).
355
+ - Require Ruby 4.0.9 or newer; development, RuboCop and every CI job use the
356
+ `.ruby-version` pin (4.0.9) instead of a Ruby 3.4/4.0 matrix.
357
+ - Establish the implementation baseline from the reviewed v0.3 development plan.
358
+ - Add an isolated, default-deny Engine with explicit resources and scalar fields.
359
+ - Add synchronous CRUD intents with identity/input/version/expiry binding, current
360
+ authorization, atomic receipts/audit, replay protection and callback outcome checks.
361
+ - Add conventional pages, bounded search/sort, readonly resource aliases, prebuilt
362
+ Turbo/Stimulus assets and request-local log redaction.
363
+ - Add closed installation/resource generators, basic doctor/TestKit, a packaged
364
+ session/SQLite consumer, database contracts and local public documentation.
365
+ - Add the optional explicit Pundit adapter, a distinct packaged Devise/PostgreSQL
366
+ host, Propshaft and Sprockets/jsbundling variants, real development reload and
367
+ process crash/response-loss recovery probes. Keep host product SDK settings intact.
368
+ - Add schema-only commented field suggestions, preserved default-deny install
369
+ scaffolds and actual-route preflight checks. Expand doctor metadata diagnostics
370
+ and host TestKit policy/field-grant assertions; run generated anonymous tests in
371
+ both packaged consumers.
372
+ - Add registered member Operations with typed pure preflight, native human
373
+ confirmation, independent input/receipt authority and guarded versioned writes.
374
+ - Add atomic outbox intents, fresh delivery authority, bounded leases/fencing,
375
+ stable request fingerprints, explicit unknown outcomes and pending-work scans.
376
+ Keep delivery outcomes separate from committed business receipts.
377
+
378
+ - Restrict scalar projection and record titles to model attributes before invoking
379
+ getters, preventing accidental mutating-method calls during readonly display.
380
+ Normal attribute getter overrides remain trusted host code.
381
+
382
+ - Add immutable fixed selections with independent default-deny grants, canonical
383
+ target/version manifests, native capture/preview and fresh revalidation.
384
+ - Bind operation/selection identity to the physical table and primary-key contract,
385
+ preventing stale references from changing meaning after a model remapping.
386
+
387
+ - Add asynchronous fixed-manifest collection operations with one parent approval,
388
+ current collection/record grants, leased item transactions, fenced receipts,
389
+ bounded recovery, partial cancellation and native job/result controls.
390
+ - Select rails_tool_views 1.0.2, close DEP-001/DEP-006 and verify the released
391
+ installer preserves an existing custom mount without route restoration.
392
+
393
+ - Add a reloadable scalar field-type registry with pure normalization/validation,
394
+ intersected JSON Schemas, plain-text formatting and trusted field partials.
395
+ Bind plugin versions/schema to operation, selection and Work fingerprints.
396
+ - Add fixed Select labels, a readonly scalar shorthand and disabled placeholders
397
+ for unavailable selections. Respect per-record field denial before rendering.
398
+ - Accept typed Date/Time operation proposals during confirmation/replay without
399
+ freezing caller-owned temporal values; preserve timestamp microseconds in hooks
400
+ and native forms, and reject nonfinite decimals.
401
+ - Exercise custom fields in both packaged consumers and initialize domain fixture
402
+ schema before transactional request tests so fresh databases are deterministic.
403
+
404
+ - Add bounded readonly computed fields with declared dependency graphs, recursive
405
+ read grants, immutable scalar snapshots and fresh versioned host computations.
406
+ - Share cached row projections and formatted titles across pages, selections and
407
+ jobs; block physical-getter writes and reject fabricated virtual previews.
408
+ - Verify graph/size/time bounds, dependency denial, current result projection,
409
+ query counts, stale contracts and actual computation reload in packaged hosts.
410
+
411
+ - Add individual template overrides with a public catalog, deterministic source/
412
+ context headers, exclusive Unicode-preserving copies and non-destructive reruns.
413
+ - Add bounded doctor diagnostics for stale/manual/invalid override metadata without
414
+ evaluating ERB. Keep host-body review separate from source metadata agreement.
415
+ - Add independent new/edit wrappers for GET/validation/conflict and default field
416
+ display partials; verify standard host view precedence and live template reload.
417
+
418
+ - Add per-view resource presentation masks, global hidden fields, plain help text
419
+ and authorized readonly context in bounded tab/panel form plans. Keep write-only
420
+ prefills blank and enforce fresh create/edit masks in the shared Runner.
421
+ - Add progressive keyboard tabs, native invalid-control revelation, error-summary
422
+ focus/links and collision-free help/error IDs. Preserve hidden-panel FormData.
423
+ - Add the field-row override and advance changed form context revisions to 2.
424
+
425
+
426
+ - Preserve open generic forms on explicitly marked session/CSRF failures and add
427
+ manual reauthentication recovery with a fresh CSRF form, current editable fields
428
+ and the same unconsumed intent. Bound recovery to one hour and require Save.
429
+ - Keep snapshots in the open DOM only; preserve edits while recovery waits and
430
+ reject stale/completed/foreign intents without reissuing or replaying a write.
431
+ - Add the recovery partial/host login-path setting, private response handshake and
432
+ revision 3 new/edit/shared-form contracts. Verify actual Devise timeout recovery.
433
+
434
+ - Preserve structured resource list hints through CRUD, member review, selections
435
+ and collection job controls without accepting arbitrary redirect URLs.
436
+ - Add authorized sortable headers, stable pagination/return links and bounded
437
+ same-filter empty-page recovery. Revalidate stale settings with a visible fallback.
438
+ - Carry Unicode list hints through open-tab recovery using a bounded ASCII codec;
439
+ retain the original business intent and fresh hidden security fields.
440
+ - Reject malformed search/page encodings and control searches before database
441
+ serialization. Declare the already-resolved base64 codec as a direct dependency.
442
+
443
+ - Add public host CustomController entry points for current Context, scoped Access,
444
+ shared Runner, mounted routes and layout CSP nonce without replacing host helpers.
445
+ - Add eight fixed minimal status kinds with HTML/Turbo reload, anti-enumeration,
446
+ status-template plain fallback and two individual override catalog entries.
447
+ - Add packaged Order CRUD and a host-owned review workbench sharing the native
448
+ operation/intent, plus real controller/operation reload and browser recovery proof.
449
+ - Return CONFLICT for unique-index rejection with full transaction rollback. Isolate
450
+ temporary mounted-route probes so randomized tests use the real host prefix.
451
+
452
+ - Add static resource menu groups, plain labels, fixed decorative icons, ordering
453
+ and `navigation false`, built per request from current index grants. Hiding a
454
+ menu entry grants or revokes nothing and leaves approval/Selection identity intact.
455
+ - Add the resource_navigation partial (catalog now 27 entries) and advance the
456
+ layout/dashboard contracts to revisions 3/2; legacy visible_resources is kept.
457
+ - Reject an unusable fallback menu label at registration instead of making every
458
+ admin page unavailable at render time.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andy Wang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.