agris 0.18.0 → 1.0.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/agents/app-explorer.md +212 -0
  3. data/.claude/agents/cross-review.md +152 -0
  4. data/.claude/agents/developer.md +215 -0
  5. data/.claude/agents/pm.md +401 -0
  6. data/.claude/agents/qa.md +235 -0
  7. data/.claude/agents/reviewer.md +185 -0
  8. data/.claude/agents/spec-preflight.md +167 -0
  9. data/.claude/agents/spec.md +244 -0
  10. data/.claude/ai/agent-rules.md +36 -0
  11. data/.claude/ai/spec-writing-guide.md +43 -0
  12. data/.claude/commands/app-explorer.md +87 -0
  13. data/.claude/commands/cross-review.md +91 -0
  14. data/.claude/commands/developer.md +118 -0
  15. data/.claude/commands/pm.md +166 -0
  16. data/.claude/commands/qa.md +111 -0
  17. data/.claude/commands/reviewer.md +86 -0
  18. data/.claude/commands/spec.md +172 -0
  19. data/.github/workflows/ci.yml +62 -0
  20. data/.gitignore +5 -0
  21. data/.rubocop.yml +10 -103
  22. data/.ruby-version +1 -0
  23. data/CHANGELOG.md +79 -0
  24. data/CLAUDE.md +98 -0
  25. data/README.md +9 -1
  26. data/agris.gemspec +3 -2
  27. data/docs/RELEASING.md +147 -0
  28. data/docs/specs/README.md +26 -0
  29. data/docs/specs/accounts-payables/.gitkeep +0 -0
  30. data/docs/specs/accounts-receivables/.gitkeep +0 -0
  31. data/docs/specs/grain/.gitkeep +0 -0
  32. data/docs/specs/inventory/.gitkeep +0 -0
  33. data/docs/specs/messages/.gitkeep +0 -0
  34. data/docs/specs/rename-folder.example.md +82 -0
  35. data/docs/specs/spec-template.md +68 -0
  36. data/docs/specs/support/.gitkeep +0 -0
  37. data/lib/agris/api/accounts_payables/disbursements.rb +19 -0
  38. data/lib/agris/api/accounts_payables/new_disbursement.rb +42 -0
  39. data/lib/agris/api/accounts_payables.rb +3 -0
  40. data/lib/agris/api/accounts_receivables/invoices.rb +1 -1
  41. data/lib/agris/api/accounts_receivables/new_payment.rb +96 -0
  42. data/lib/agris/api/accounts_receivables/new_payment_remark.rb +38 -0
  43. data/lib/agris/api/accounts_receivables/payment_post_result.rb +35 -0
  44. data/lib/agris/api/accounts_receivables/payments.rb +33 -0
  45. data/lib/agris/api/accounts_receivables.rb +6 -0
  46. data/lib/agris/api/document_query_response.rb +6 -2
  47. data/lib/agris/api/grain/contract.rb +3 -3
  48. data/lib/agris/api/grain/new_ticket.rb +1 -0
  49. data/lib/agris/api/grain/purchase_contracts.rb +1 -1
  50. data/lib/agris/api/grain/sales_contracts.rb +1 -1
  51. data/lib/agris/api/grain.rb +4 -2
  52. data/lib/agris/api/inventory/delivery_tickets.rb +1 -1
  53. data/lib/agris/api/inventory/orders.rb +1 -1
  54. data/lib/agris/api/messages/changed_query_base.rb +1 -0
  55. data/lib/agris/api/messages/document_query_base.rb +1 -0
  56. data/lib/agris/api/messages/import.rb +1 -0
  57. data/lib/agris/api/name/new_farm_field.rb +5 -0
  58. data/lib/agris/api/new_voucher.rb +1 -3
  59. data/lib/agris/api/post_result.rb +9 -1
  60. data/lib/agris/client.rb +3 -1
  61. data/lib/agris/version.rb +1 -1
  62. data/lib/agris.rb +1 -0
  63. data/lib/hash.rb +1 -0
  64. metadata +48 -13
  65. data/.circleci/config.yml +0 -45
  66. data/.codeclimate.yml +0 -5
@@ -0,0 +1,172 @@
1
+ # /spec
2
+
3
+ Generate and maintain implementation-ready specs from Jira work items or developer descriptions.
4
+
5
+ **Agent:** `~/.config/claude-playbook/global/agents/spec.md`
6
+
7
+ ## Mode Detection
8
+
9
+ **Pull mode (default):** Ask ONE question at a time with numbered options. Never ask two questions in one message.
10
+
11
+ **Push mode:** If `$ARGUMENTS` contains `--push`, or if both `issue` AND `spec` arguments are provided, skip questions and execute directly using the full protocol below.
12
+
13
+ ## Arguments
14
+ | Key | Required | Description | Example |
15
+ |-----|----------|-------------|---------|
16
+ | issue | No | Jira issue key to generate spec from | `issue=PROJ-42` |
17
+ | spec | No | Path to existing spec to update | `spec=docs/specs/SPEC-003-auth.md` |
18
+ | --push | No | Skip pull prompting, execute directly | `--push` |
19
+
20
+ ---
21
+
22
+ ## Pull Prompting Flow
23
+
24
+ ### Step 1 — Intent
25
+
26
+ If no arguments or only partial arguments are provided, start here:
27
+
28
+ > **What would you like to do?**
29
+ >
30
+ > 1. Generate a spec from a Jira issue (epic/story/subtask)
31
+ > 2. Update an existing spec with changes from Jira
32
+ > 3. Generate a spec from scratch (no Jira issue)
33
+ > 4. Review/audit an existing spec
34
+
35
+ Wait for the user's answer before proceeding.
36
+
37
+ ### Step 2 — Source Material
38
+
39
+ Based on the answer, ask ONE follow-up:
40
+
41
+ - **If option 1:** "What is the Jira issue key? (e.g., PROJ-42)"
42
+ Then execute the Jira Hierarchy Crawl: fetch the issue, crawl upward (subtask → story → epic), follow `blocks`/`is blocked by` links, pull sibling names if context is thin, search Confluence for related BRDs/PRDs. Summarize what you found. Ask: "Does this capture the scope? (1) Yes, proceed (2) No, let me clarify"
43
+ - **If option 2:** "Which spec?" List existing specs in `docs/specs/` as numbered options.
44
+ Then fetch current Jira state for linked issues and diff against the spec.
45
+ - **If option 3:** "Describe the feature in 1-2 sentences. Who is the user and what problem does it solve?"
46
+ - **If option 4:** "Which spec?" List existing specs as numbered options.
47
+
48
+ ### Step 3 — Scope Confirmation
49
+
50
+ After gathering source material, present a scope proposal:
51
+
52
+ > **Based on what I found, I think the spec should cover:**
53
+ > - Feature: {name}
54
+ > - Scope level: {epic / story / subset}
55
+ > - In scope: {1-3 bullet summary}
56
+ > - Out of scope: {what this does NOT cover}
57
+ > - Related specs: {any existing specs that overlap}
58
+ >
59
+ > **Does this scope look right?**
60
+ > 1. Yes, write the spec
61
+ > 2. Add something
62
+ > 3. Remove something
63
+ > 4. Start over
64
+
65
+ ### Step 4 — Infrastructure Check
66
+
67
+ If the scope includes Docker, Terraform, CI/CD, or deployment:
68
+
69
+ > **This feature includes infrastructure components. Recommendation:**
70
+ > 1. Split into separate app spec + infra spec (recommended)
71
+ > 2. Keep as one spec
72
+ > 3. Spec only the app portion, flag infra for DevOps
73
+
74
+ ### Step 5 — Execute
75
+
76
+ Proceed to the Protocol below.
77
+
78
+ ---
79
+
80
+ ## Protocol
81
+
82
+ ### Standards — Read When Relevant
83
+
84
+ Read these files when your spec work touches each area:
85
+
86
+ | When writing about | Read this file |
87
+ |-------------------|---------------|
88
+ | Naming conventions | `~/.config/claude-playbook/global/standards/practices/naming.md` |
89
+ | Spec format | `~/.config/claude-playbook/global/templates/ai/spec-writing-guide.md` (scaffolded to `.claude/ai/` in projects) |
90
+ | Architecture or layering | `~/.config/claude-playbook/global/standards/practices/architecture.md` |
91
+ | Testing strategy | `~/.config/claude-playbook/global/standards/practices/testing.md` |
92
+
93
+ ### Jira Hierarchy Crawl
94
+
95
+ When generating from a Jira issue:
96
+ 1. Fetch the given issue.
97
+ 2. Crawl upward: subtask → parent story → parent epic (as far as the chain goes).
98
+ 3. Follow `blocks` and `is blocked by` links (not `relates to`).
99
+ 4. If story/epic description is thin, pull sibling names and summaries for scope context.
100
+ 5. Search Confluence for BRDs/PRDs linked from the epic or matching keywords.
101
+
102
+ ### Existing Spec Check
103
+
104
+ Before writing any spec:
105
+ 1. Scan `docs/specs/` for specs referencing the same Jira issue keys, epic, or feature area.
106
+ 2. If a matching spec exists: switch to update flow.
107
+ 3. If related specs exist: present to developer for cross-referencing.
108
+
109
+ ### Spec Authoring
110
+
111
+ 1. **Read the spec template** at `~/.config/claude-playbook/global/templates/specs/spec-template.md` — do not rely on memory.
112
+ 2. Scan `docs/specs/` for existing specs. Determine next SPEC ID number.
113
+ 3. Write the spec in `docs/specs/SPEC-{###}-{kebab-title}.md`.
114
+ 4. Include: numbered rules (R#), acceptance criteria (AC-#), acceptance tests (AT#) in Given/When/Then, edge cases (E#).
115
+ 5. Every AT must include `Covers: R#` references.
116
+ 6. Include all sections that apply, omit sections that genuinely don't (no "N/A" filler).
117
+ 7. Keep spec under 500 lines. If larger, propose decomposition.
118
+ 8. Present draft to developer for approval before writing to disk.
119
+
120
+ ### Task Breakdown
121
+
122
+ 1. Propose tasks from spec ACs, sized for small PRs (1-3 points).
123
+ 2. Estimate Fibonacci complexity per task (1, 2, 3, 5, 8, 13). These are preliminary — PM may adjust.
124
+ 3. Split tasks >= 5 points or document rationale for keeping whole.
125
+ 4. Output tasks in Jira-ready format (operational mode) or track in spec (GitHub-only mode).
126
+ 5. Verify all ACs are covered by at least one proposed task.
127
+
128
+ The spec agent does NOT create Jira issues. The PM or developer creates them from the proposed breakdown.
129
+
130
+ ---
131
+
132
+ ## Self-Test Checklist
133
+
134
+ Before handoff, verify ALL of these. Output the checklist with pass/fail:
135
+
136
+ ```
137
+ SELF-TEST
138
+ - [ ] Every rule has a unique R# ID
139
+ - [ ] Every AC has a unique AC-# ID
140
+ - [ ] Every AT has a unique AT# ID and Covers: R# reference
141
+ - [ ] No ambiguous language (should probably, generally, maybe)
142
+ - [ ] No duplicate IDs
143
+ - [ ] Every R# is covered by at least one AT#
144
+ - [ ] Every AC is mapped to at least one proposed task
145
+ - [ ] Tasks >= 5 points have split review or documented rationale
146
+ - [ ] Out-of-scope section is explicit
147
+ - [ ] Cross-referenced specs listed in Dependencies
148
+ Standards consulted: [{list of practice files actually read}]
149
+ ```
150
+
151
+ ## Handoff (MANDATORY)
152
+
153
+ Output a SPEC_TO_DEV handoff summary:
154
+ - Spec path and SPEC ID
155
+ - Proposed task list with AC mappings and complexity estimates
156
+ - Risks and dependencies
157
+ - State: "Spec ready for development — see {spec path}. Proposed tasks ready for Jira creation."
158
+
159
+ Do NOT assume a developer will automatically pick up the work.
160
+
161
+ ## Hard Rules
162
+ - **NEVER write, edit, or create application code.** You may only write to `docs/specs/` and handoff files. Implementation is the developer's job.
163
+ - **NEVER write to Jira.** Read-only access. Propose tasks; human or PM creates them.
164
+ - **NEVER write to Confluence.** Read-only access for context gathering.
165
+ - Do not add unapproved scope.
166
+ - Do not leave ambiguous criteria or missing AC IDs.
167
+ - Do not allow tasks >= 5 points without documented split review.
168
+ - Do not write specs without developer approval of scope first.
169
+ - NEVER merge PRs. Only human users merge.
170
+ - If blocked >30 minutes, create blocker report.
171
+
172
+ $ARGUMENTS
@@ -0,0 +1,62 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ # Split from lint deliberately: a spec failure and a lint failure are
10
+ # different problems, and each reports its own status check. Specs run
11
+ # across a Ruby matrix; lint does not — rubocop's output does not vary
12
+ # by Ruby, so one run on the floor is enough.
13
+ test:
14
+ runs-on: ubuntu-latest
15
+
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ # Floor, current, next, and 4.0 — which a consuming application
20
+ # already runs. The floor must stay green for the gemspec's
21
+ # required_ruby_version to mean anything.
22
+ ruby: ['3.1', '3.3', '3.4', '4.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+
27
+ - name: Set up Ruby ${{ matrix.ruby }}
28
+ uses: ruby/setup-ruby@v1
29
+ with:
30
+ ruby-version: ${{ matrix.ruby }}
31
+ bundler-cache: true
32
+
33
+ - name: Run specs
34
+ run: |
35
+ bundle exec rspec \
36
+ --format progress \
37
+ --format RspecJunitFormatter \
38
+ --out tmp/test-results/rspec.xml
39
+
40
+ # upload-artifact@v4 rejects duplicate names, so each matrix leg
41
+ # needs its own.
42
+ - name: Upload test results
43
+ uses: actions/upload-artifact@v4
44
+ if: ${{ !cancelled() }}
45
+ with:
46
+ name: test-results-ruby-${{ matrix.ruby }}
47
+ path: tmp/test-results/
48
+
49
+ lint:
50
+ runs-on: ubuntu-latest
51
+
52
+ steps:
53
+ - uses: actions/checkout@v4
54
+
55
+ - name: Set up Ruby
56
+ uses: ruby/setup-ruby@v1
57
+ with:
58
+ ruby-version-file: .ruby-version
59
+ bundler-cache: true
60
+
61
+ - name: Run rubocop
62
+ run: bundle exec rubocop
data/.gitignore CHANGED
@@ -12,3 +12,8 @@
12
12
  .rspec_status
13
13
  .DS_Store
14
14
  /vendor
15
+
16
+ # Claude Playbook (auto-added)
17
+ .claude/state/
18
+ .claude/settings.local.json
19
+ .claude/agent-memory-local/
data/.rubocop.yml CHANGED
@@ -1,23 +1,14 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
- Rails:
4
- Enabled: false
5
3
  AllCops:
6
- TargetRubyVersion: 2.4
4
+ TargetRubyVersion: 3.1
7
5
  Exclude:
8
6
  - "vendor/**/*"
9
7
  - "db/schema.rb"
10
8
  - "node_modules/**/*"
11
9
  - bin/*
12
10
  UseCache: false
13
- Layout/DotPosition:
14
- Description: Checks the position of the dot in multi-line method calls.
15
- StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains
16
- Enabled: true
17
- EnforcedStyle: trailing
18
- SupportedStyles:
19
- - leading
20
- - trailing
11
+ SuggestExtensions: false
21
12
  Layout/EmptyLineAfterMagicComment:
22
13
  Description: 'Add an empty line after magic comments to separate them from code.'
23
14
  StyleGuide: '#separate-magic-comments-from-code'
@@ -66,16 +57,9 @@ Style/PercentLiteralDelimiters:
66
57
  "%w": "()"
67
58
  "%W": "()"
68
59
  "%x": "()"
69
- Naming/PredicateName:
60
+ Naming/PredicatePrefix:
70
61
  Description: Check the names of predicate methods.
71
- StyleGuide: https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark
72
62
  Enabled: true
73
- NamePrefix:
74
- - is_
75
- - has_
76
- - have_
77
- NamePrefixBlacklist:
78
- - is_
79
63
  Exclude:
80
64
  - spec/**/*
81
65
  Style/RaiseArgs:
@@ -241,7 +225,7 @@ Style/WhenThen:
241
225
  Lint/EachWithObjectArgument:
242
226
  Description: Check for immutable argument given to each_with_object.
243
227
  Enabled: true
244
- Lint/HandleExceptions:
228
+ Lint/SuppressedException:
245
229
  Description: Don't suppress exception.
246
230
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions
247
231
  Enabled: false
@@ -252,82 +236,6 @@ Lint/LiteralInInterpolation:
252
236
  Description: Checks for literals used in interpolation.
253
237
  Enabled: false
254
238
 
255
- ##################### Rails ##################################
256
-
257
- Rails/ActionFilter:
258
- Description: 'Enforces consistent use of action filter methods.'
259
- Enabled: true
260
- Rails/Date:
261
- Description: >-
262
- Checks the correct usage of date aware methods,
263
- such as Date.today, Date.current etc.
264
- Enabled: true
265
- Rails/Delegate:
266
- Description: 'Prefer delegate method for delegations.'
267
- Enabled: true
268
- Rails/Exit:
269
- Description: >-
270
- Favor `fail`, `break`, `return`, etc. over `exit` in
271
- application or library code outside of Rake files to avoid
272
- exits during unit testing or running in production.
273
- Enabled: true
274
- Rails/FindBy:
275
- Description: 'Prefer find_by over where.first.'
276
- StyleGuide: 'https://github.com/bbatsov/rails-style-guide#find_by'
277
- Enabled: true
278
- Rails/FindEach:
279
- Description: 'Prefer all.find_each over all.find.'
280
- StyleGuide: 'https://github.com/bbatsov/rails-style-guide#find-each'
281
- Enabled: true
282
- Rails/HasAndBelongsToMany:
283
- Description: 'Prefer has_many :through to has_and_belongs_to_many.'
284
- StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has-many-through'
285
- Enabled: true
286
- Rails/HttpPositionalArguments:
287
- Description: 'Rails 5 only, disabled to keep Hound quiet'
288
- Enabled: false
289
- Rails/NotNullColumn:
290
- Description: 'Do not add a NOT NULL column without a default value'
291
- Enabled: false
292
- Rails/Output:
293
- Description: 'Checks for calls to puts, print, etc.'
294
- Enabled: true
295
- Rails/OutputSafety:
296
- Description: 'The use of `html_safe` or `raw` may be a security risk.'
297
- Enabled: true
298
- Rails/PluralizationGrammar:
299
- Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.'
300
- Enabled: true
301
- Rails/ReadWriteAttribute:
302
- Description: >-
303
- Checks for read_attribute(:attr) and
304
- write_attribute(:attr, val).
305
- StyleGuide: 'https://github.com/bbatsov/rails-style-guide#read-attribute'
306
- Enabled: true
307
- Rails/RequestReferer:
308
- Description: 'Use consistent syntax for request.referer.'
309
- Enabled: true
310
- Rails/SafeNavigation:
311
- Description: "Use Ruby's safe navigation operator (`&.`) instead of `try!`"
312
- Enabled: true
313
- Rails/ScopeArgs:
314
- Description: 'Checks the arguments of ActiveRecord scopes.'
315
- Enabled: true
316
- Rails/TimeZone:
317
- Description: 'Checks the correct usage of time zone aware methods.'
318
- StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time'
319
- Reference: 'http://danilenko.org/2012/7/6/rails_timezones'
320
- Enabled: true
321
- Rails/UniqBeforePluck:
322
- Description: 'Prefer the use of uniq or distinct before pluck.'
323
- Enabled: true
324
- Rails/Validation:
325
- Description: 'Use validates :attribute, hash of validations.'
326
- Enabled: true
327
- Security/JSONLoad:
328
- Description : 'Prefer usage of JSON.parse'
329
- Enabled: true
330
-
331
239
  Layout/DotPosition:
332
240
  Description: Checks the position of the dot in multi-line method calls.
333
241
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains
@@ -354,11 +262,10 @@ Style/ClassAndModuleChildren:
354
262
  - nested
355
263
  Style/MultilineIfModifier:
356
264
  Enabled: false
357
- Style/StringLiterals:
358
- Description: Checks if uses of quotes match the configured preference.
359
- StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals
265
+ Naming/VariableNumber:
266
+ Description: >-
267
+ The codebase consistently uses trailing _1 / _2 to enumerate records,
268
+ mostly in spec `let` names. Match that rather than renaming for the
269
+ sake of the cop's default.
360
270
  Enabled: true
361
- EnforcedStyle: single_quotes
362
- SupportedStyles:
363
- - single_quotes
364
- - double_quotes
271
+ EnforcedStyle: snake_case
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,79 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Ruby support is expressed through `required_ruby_version` rather than the
9
+ version number — see [docs/RELEASING.md](docs/RELEASING.md). Raising that floor
10
+ is a breaking change and takes a major bump; adding support for a newer Ruby
11
+ takes none.
12
+
13
+ ## [1.0.0] - 2026-09-14
14
+
15
+ First release since `v0.19.0`. The `1.0.0` bump declares the public API stable
16
+ and makes semver's major-bump signal available, which `0.x` does not.
17
+
18
+ ### Added
19
+
20
+ - `Api::AccountsReceivables::Payments`, adding `#create_payment`,
21
+ `#apply_payment` and `#post_payment` to the client, with the `NewPayment`,
22
+ `NewPaymentRemark` and `PaymentPostResult` XML models. (#44)
23
+ - `Api::AccountsPayables::Disbursements`, adding `#create_disbursement` to the
24
+ client, with the `NewDisbursement` XML model. (#40)
25
+ - `freight_uom` declared on `Api::Grain::NewTicket`. (#43)
26
+
27
+ ### Changed
28
+
29
+ - **Ruby 3.1 or newer is now required.** The gemspec declares
30
+ `required_ruby_version >= 3.1`; previously it declared no floor at all, so
31
+ the gem could be installed on unsupported Rubies and fail at runtime.
32
+ Applications below 3.1 will resolve to `v0.19.0` and should stay there. (#52)
33
+ - **`*_changed_since` methods now take `detail:` as a keyword argument**
34
+ rather than a positional boolean. Calls such as
35
+ `client.orders_changed_since(time, true)` must become
36
+ `client.orders_changed_since(time, detail: true)`. Affects
37
+ `invoices_changed_since`, `purchase_contracts_changed_since`,
38
+ `sales_contracts_changed_since`, `delivery_tickets_changed_since` and
39
+ `orders_changed_since`. (#57)
40
+ - Versioning moved to a single line. An earlier scheme encoded the supported
41
+ Ruby in the version number (`0.19.x` for Ruby 3.1, `0.2x` for Ruby 3.3);
42
+ it fought semver and RubyGems has no concept of release lines, always serving
43
+ the highest version as `latest`. `0.20.0` and `0.21.0` were never published
44
+ and are superseded by this release. (#52)
45
+
46
+ ### Fixed
47
+
48
+ - `Api::PostResult#rejections` no longer raises when a post is processed
49
+ cleanly. A processed post reports an empty `<reject />`, which previously
50
+ produced a `NoMethodError` rather than an empty list. (#44)
51
+ - `bundle exec rake` runs to completion again. RuboCop had been unable to run
52
+ at all since the move to Ruby 3.x — it calls the positional
53
+ `Psych.safe_load` signature removed in Psych 4, and rejected any 3.x value in
54
+ `.ruby-version`. Separately, lint offences had accumulated since February
55
+ 2024 because nothing was running the linter. (#52)
56
+
57
+ ### Internal
58
+
59
+ - CI migrated from CircleCI to GitHub Actions, running specs and lint as
60
+ separate jobs so each reports its own status. CircleCI ran specs only, which
61
+ is why the RuboCop breakage went unnoticed across three releases' worth of
62
+ commits. (#52)
63
+ - Specs now run against Ruby 3.1, 3.3 and 3.4, so `required_ruby_version` is
64
+ verified rather than asserted. (#53)
65
+ - Release process documented in [docs/RELEASING.md](docs/RELEASING.md). (#54)
66
+ - RuboCop bumped from 0.54.0 to 1.x, retiring four workarounds that existed
67
+ only to keep a 2018 release running on Ruby 3.x — a `psych` pin and three
68
+ disabled or duplicated configuration entries. Ruby 4.0 added to the CI
69
+ matrix, which a consuming application already runs. (#57)
70
+
71
+ ---
72
+
73
+ ## Earlier releases
74
+
75
+ Releases up to and including `v0.19.0` predate this changelog. See the
76
+ [commit history](https://github.com/westernmilling/agris.rb/commits/master)
77
+ and [release tags](https://github.com/westernmilling/agris.rb/tags).
78
+
79
+ [1.0.0]: https://github.com/westernmilling/agris.rb/compare/v0.19.0...v1.0.0
data/CLAUDE.md ADDED
@@ -0,0 +1,98 @@
1
+ # CLAUDE.md — Project Configuration
2
+
3
+ ## Product Context
4
+ - **Product name:** agris (Ruby gem)
5
+ - **Primary user/persona:** Ruby application developers at Western Milling (and downstream consumers) who integrate with the Agris ERP Web Services SOAP API.
6
+ - **Problem statement:** Agris exposes its ERP data (grain contracts/tickets, inventory orders, delivery tickets, AR invoices, AP vouchers, commodity codes, document tracking) through a single SOAP `ProcessMessage` endpoint. This gem wraps that endpoint with a typed Ruby client so consumers don't construct/parse XML by hand.
7
+ - **Non-goals:**
8
+ - Not a Rails engine — pure library, no UI or persistence.
9
+ - Not a generic SOAP client — only models the Agris message catalog.
10
+ - Does not host or proxy Agris itself; callers supply their own endpoint, dataset, and credentials.
11
+
12
+ ## Stack and Dependencies
13
+ - **Languages/frameworks:** Ruby 3.1 (`.ruby-version`, which CI also reads). Rubocop still lints against `TargetRubyVersion: 2.4`.
14
+ - **Key applications/packages:**
15
+ - Runtime: `savon ~> 2.11` (SOAP client).
16
+ - Dev/test: `rspec ~> 3.0`, `rspec_junit_formatter ~> 0.4.1`, `webmock ~> 2.3`, `simplecov 0.17`, `rubocop 0.54.0`, `pry-byebug`, `rake ~> 12.3.3`, `bundler ~> 2.3.7`.
17
+ - **Data layer:** None local. Remote system of record is the Agris ERP database, accessed via its SOAP `ProcessMessage` endpoint (see `lib/agris/savon_request.rb` and `lib/agris/process_message_response.rb`).
18
+ - **Build command:** `bundle install` (or `bin/setup`).
19
+ - **Test command:** `bundle exec rspec` (or `bundle exec rake spec`).
20
+ - **Lint command:** `bundle exec rubocop`.
21
+ - **Dev server command:** N/A (library). For interactive exploration: `bin/console` (boots IRB with the gem loaded).
22
+
23
+ ## Verification Commands
24
+ - **Run tests:** `bundle exec rspec`
25
+ - **Run linter:** `bundle exec rubocop`
26
+ - **Type check:** N/A (no Sorbet/RBS in this project)
27
+ - **Run everything (default rake):** `bundle exec rake` — runs `spec` then `rubocop`.
28
+
29
+ ## Domain Glossary
30
+ Define key business terms unique to this project so agents use correct terminology.
31
+
32
+ | Term | Definition |
33
+ |------|-----------|
34
+ | Agris | Third-party agribusiness ERP. All API messages target this system. |
35
+ | Dataset | Agris tenancy/company identifier (e.g., `'001'`). Required as a keyword arg on every `Agris::Client.new`; scopes all requests. |
36
+ | Context | `Agris::Context` — endpoint config bundle: base URL, default dataset, dataset path, database name, user, password. |
37
+ | Credentials | `Agris::Credentials::Anonymous` or `Agris::Credentials::BasicAuth` — auth strategy passed to the underlying request. |
38
+ | ProcessMessage | The single SOAP operation Agris exposes; every API call serializes a typed request XML and parses a typed response XML through it. |
39
+ | Request type | Pluggable transport (`Agris::SavonRequest`). Selected via `Agris.request_type`. |
40
+ | XmlModel | `Agris::XmlModel` — base class for declarative request/response XML payloads used across `lib/agris/api/**`. |
41
+ | Grain module | `Agris::Api::Grain::*` — tickets, contracts (purchase/sales), commodity codes, grade factors, rates. |
42
+ | Inventory module | `Agris::Api::Inventory::*` — delivery tickets and orders. |
43
+ | Voucher / Invoice | AP voucher (`Api::AccountsPayables`) and AR invoice (`Api::AccountsReceivables`) postings. |
44
+ | Messages module | `Api::Messages::*` — document-tracking and "changed since" queries (invoices, sales contracts, delivery tickets, orders, commodity-code documents). |
45
+
46
+ ## Local Development Setup
47
+ - **Prerequisites:** Ruby 3.1.x and Bundler 2.3+. CI reads `.ruby-version`, so local dev and CI cannot drift; other Ruby versions may work but are unverified.
48
+ - **Install steps:**
49
+ 1. `git clone git@github.com:westernmilling/agris.rb.git`
50
+ 2. `cd agris.rb`
51
+ 3. `bin/setup` (runs `bundle install`)
52
+ - **How to run locally:** This is a library — no server. Use `bin/console` to load the gem in IRB and exercise the client interactively.
53
+ - **How to seed data:** N/A. Tests use fixture XML under `spec/fixtures/agris/**` (stubbed via WebMock); they do not require a live Agris endpoint.
54
+ - **How to run tests:** `bundle exec rspec` (full suite), `bundle exec rspec spec/lib/agris/client/grain/purchase_contracts_spec.rb` (one file), or `bundle exec rake` (specs + rubocop).
55
+ - **Key URLs:**
56
+ - Repo: https://github.com/westernmilling/agris.rb
57
+ - CI: GitHub Actions (workflow at `.github/workflows/ci.yml`).
58
+ - Coverage / quality: Code Climate (badges in `README.md`; config in `.codeclimate.yml`).
59
+
60
+ ## Common Gotchas
61
+ - **Ruby 2.4 target.** Rubocop's `TargetRubyVersion` is `2.4`. Avoid syntax/stdlib introduced after 2.4 unless you are intentionally bumping the floor.
62
+ - **Rubocop 0.54.0 is pinned and old.** Many newer cops do not exist; `.rubocop_todo.yml` carries existing exemptions. Don't auto-correct broadly without running the full suite afterward.
63
+ - **`Agris::HTTPartyRequest` is autoloaded but the file is not present** in `lib/agris/`. Only `SavonRequest` is implemented — configure `Agris.request_type = Agris::SavonRequest`. The dangling autoload is a known wart.
64
+ - **`dataset:` is keyword-required on `Client.new`.** `Agris::Client.new(dataset: '001')` — forgetting the keyword raises `ArgumentError`.
65
+ - **All requests funnel through Agris's single `ProcessMessage` SOAP op.** Errors come back in-band as `<MessageStatus>` payloads (see `lib/agris/process_message_response.rb`), not as HTTP errors. Inspect `ApiError` / `MessageError` / `SystemError` / `UnknownError` raised from the client.
66
+ - **Fixtures are XML, sometimes paired with JSON snapshots.** When adding a new endpoint, add both request and response fixtures under `spec/fixtures/agris/<area>/`.
67
+ - **`lib/hash.rb` monkey-patches core `Hash`.** Be careful when refactoring helpers — they may be in use across XML models.
68
+ - **Released to RubyGems as `agris`.** Bumping `lib/agris/version.rb` and running `bundle exec rake release` will tag, push, and publish. Do not run `rake release` casually.
69
+
70
+ ## Integrations
71
+ - **Jira project key:** _Not configured for this repo._ <!-- Fill in if/when this gem is tracked in Jira; used for branch naming and issue linking. -->
72
+ - **Staging URL:** N/A (library, no deployed environment).
73
+ - **CI pipeline:** GitHub Actions — `.github/workflows/ci.yml`. Two parallel jobs on pushes to `master` and on every pull request: `test` (`bundle exec rspec`, JUnit output uploaded as an artifact) and `lint` (`bundle exec rubocop`). They report separate status checks so a spec failure and a lint failure are distinguishable at a glance.
74
+
75
+ ## Project Overrides
76
+ Rules here override global CLAUDE.md rules for this project.
77
+
78
+ ### Architecture Rules
79
+ - **Layering rules:**
80
+ - `lib/agris.rb` — module-level configuration (`Agris.configure`) and autoloads.
81
+ - `lib/agris/client.rb` — single entry point; mixes in API modules from `lib/agris/api/**`.
82
+ - `lib/agris/api/<area>/<resource>.rb` — one Ruby module per Agris message; defines request building and response parsing using `XmlModel`.
83
+ - `lib/agris/{savon_request,process_message_response,context,credentials,...}.rb` — transport, response envelope, config primitives.
84
+ - Add new endpoints by creating a module under the appropriate `api/<area>/` namespace and including it in `Client`.
85
+ - **Dependency boundaries:**
86
+ - API modules must not call `Savon` directly — go through the configured `request_type`.
87
+ - Keep XML construction inside `XmlModel` subclasses, not inline in client methods.
88
+ - No Rails / ActiveSupport assumptions — this is a plain Ruby gem.
89
+ - **Error-handling conventions:**
90
+ - Surface Agris failures as one of the existing `Agris::*Error` classes defined in `lib/agris.rb`. Don't introduce new error hierarchies without discussion.
91
+ - Don't rescue and swallow inside API modules; let the caller decide.
92
+
93
+ ### Delivery Rules
94
+ - **Branch strategy:** Trunk-based off `master`. Feature branches per change; PRs target `master`.
95
+ - **PR size policy:** ~200 LOC per PR, one testable behavior. RSpec coverage required for behavior changes; map specs to acceptance criteria when specs exist under `docs/specs/`.
96
+
97
+ ### Model Overrides
98
+ _None._
data/README.md CHANGED
@@ -52,7 +52,15 @@ Enjoy!
52
52
 
53
53
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
54
 
55
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
55
+ To install this gem onto your local machine, run `bundle exec rake install`. For releases, see [Releasing](#releasing) below.
56
+
57
+ ## Releasing
58
+
59
+ The gem is published to RubyGems as `agris`, on a single version line from
60
+ `master`. Ruby support is expressed through `required_ruby_version` rather than
61
+ the version number, and `rake release` tags, pushes and publishes in one
62
+ irreversible step — see [docs/RELEASING.md](docs/RELEASING.md) before cutting a
63
+ release.
56
64
 
57
65
  ## Contributing
58
66
 
data/agris.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = 'Ruby client library for Agris API'
13
13
  spec.homepage = 'https://github.com/westernmilling/agris.rb'
14
14
  spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 3.1'
15
16
 
16
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
18
  f.match(%r{^(test|spec|features)/})
@@ -22,12 +23,12 @@ Gem::Specification.new do |spec|
22
23
 
23
24
  spec.add_dependency 'savon', '~> 2.11'
24
25
 
25
- spec.add_development_dependency 'bundler', '~> 2.3.7'
26
+ spec.add_development_dependency 'bundler', '>= 2.3'
26
27
  spec.add_development_dependency 'pry-byebug'
27
28
  spec.add_development_dependency 'rake', '~> 12.3.3'
28
29
  spec.add_development_dependency 'rspec', '~> 3.0'
29
30
  spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
30
- spec.add_development_dependency 'rubocop', '0.54.0'
31
+ spec.add_development_dependency 'rubocop', '~> 1.80'
31
32
  spec.add_development_dependency 'simplecov', '0.17'
32
33
  spec.add_development_dependency 'webmock', '~> 2.3'
33
34
  end