ecoportal-api-graphql 1.3.9 → 1.3.11

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ai-assistance/code/diff_pairing_engine.md +243 -0
  3. data/.ai-assistance/code/graphql_domain_knowledge.md +20 -10
  4. data/.ai-assistance/code/template_diff_pairing_domain.md +175 -0
  5. data/.ai-assistance/code/workflow-command-guide.md +28 -0
  6. data/.ai-assistance/projects/TODO.md +21 -0
  7. data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +136 -0
  8. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +6 -1
  9. data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +93 -0
  10. data/.ai-assistance/projects/qa-services-delivery/INTENT.md +76 -0
  11. data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +115 -0
  12. data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +99 -0
  13. data/.ai-assistance/projects/qa-services-delivery/TODO.md +81 -0
  14. data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +77 -0
  15. data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +97 -0
  16. data/.ai-assistance/projects/template-diff-deploy/INTENT.md +12 -0
  17. data/.ai-assistance/projects/template-diff-deploy/TODO.md +9 -0
  18. data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +93 -0
  19. data/.ai-assistance/projects/template-maintenance/README.md +14 -0
  20. data/CHANGELOG.md +116 -0
  21. data/docs/worklog.md +408 -0
  22. data/ecoportal-api-graphql.gemspec +1 -1
  23. data/lib/ecoportal/api/graphql/base/page/data_field.rb +1 -1
  24. data/lib/ecoportal/api/graphql/builder/template_builder.rb +174 -0
  25. data/lib/ecoportal/api/graphql/builder.rb +17 -16
  26. data/lib/ecoportal/api/graphql/diff/change.rb +59 -0
  27. data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +329 -0
  28. data/lib/ecoportal/api/graphql/diff/cross_object_diff.rb +165 -0
  29. data/lib/ecoportal/api/graphql/diff/deploy.rb +121 -0
  30. data/lib/ecoportal/api/graphql/diff/id_resolver.rb +64 -0
  31. data/lib/ecoportal/api/graphql/diff/pairing/candidate.rb +32 -0
  32. data/lib/ecoportal/api/graphql/diff/pairing/engine.rb +173 -0
  33. data/lib/ecoportal/api/graphql/diff/pairing/ledger.rb +119 -0
  34. data/lib/ecoportal/api/graphql/diff/pairing/signals.rb +104 -0
  35. data/lib/ecoportal/api/graphql/diff/strategy.rb +113 -0
  36. data/lib/ecoportal/api/graphql/diff/version_diff.rb +332 -0
  37. data/lib/ecoportal/api/graphql/diff.rb +34 -0
  38. data/lib/ecoportal/api/graphql/fragment/location_draft.rb +53 -53
  39. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +1 -0
  40. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +27 -18
  41. data/lib/ecoportal/api/graphql/mutation/action/archive.rb +1 -1
  42. data/lib/ecoportal/api/graphql/mutation/action/create.rb +1 -1
  43. data/lib/ecoportal/api/graphql/mutation/action/update.rb +1 -1
  44. data/lib/ecoportal/api/graphql/mutation/contractor_entity/create.rb +1 -1
  45. data/lib/ecoportal/api/graphql/mutation/contractor_entity/destroy.rb +1 -1
  46. data/lib/ecoportal/api/graphql/mutation/contractor_entity/update.rb +1 -1
  47. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +1 -1
  48. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +1 -1
  49. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +1 -1
  50. data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +62 -62
  51. data/lib/ecoportal/api/graphql/query/location_structure.rb +61 -61
  52. data/lib/ecoportal/api/graphql.rb +139 -138
  53. data/lib/ecoportal/api/graphql_version.rb +1 -1
  54. data/tests/dump_template_model.rb +90 -0
  55. data/tests/validate_queries.rb +127 -0
  56. metadata +32 -3
@@ -0,0 +1,127 @@
1
+ require 'ecoportal/api-graphql'
2
+ require 'json'
3
+ require 'graphql'
4
+
5
+ # Validate EVERY gem query against a GraphQL schema, offline — catches the whole class of
6
+ # "field must have selections" (object field selected bare) and "selections can't be made on
7
+ # scalars" (scalar over-selected) bugs before they reach a client runner.
8
+ #
9
+ # This is how the 2026-07-03 LocationStructure `updatedAt` prod failure (and a sibling
10
+ # `createdAt` over-selection in the LocationDraft fragment) were found. Those queries had no
11
+ # spec; this script would have flagged them.
12
+ #
13
+ # It renders each query's block offline (auth is stubbed — no network), assembles its fragments,
14
+ # and validates the full document against a schema introspection JSON.
15
+ #
16
+ # Usage (run under bundler so the graphlient fork's #to_query_string is available):
17
+ # bundle exec ruby tests/validate_queries.rb [PATH_TO_SCHEMA_INTROSPECTION_JSON]
18
+ #
19
+ # Get a fresh schema JSON via an introspection query against the org's endpoint; the default
20
+ # below points at the last captured dump. Prefer a fresh dump — a stale one yields false
21
+ # "field doesn't exist" noise (harmless: this script only *fails* on the two structural classes).
22
+
23
+ DEFAULT_SCHEMA = File.expand_path('../.ai-assistance/tmp/20260605T101224_live_ep_graphql_schema.graphql.json', __dir__)
24
+ STRUCTURAL = ['must have selections', "can't be made on scalars"].freeze
25
+
26
+ schema_path = ARGV[0] || DEFAULT_SCHEMA
27
+ unless File.exist?(schema_path)
28
+ warn "Schema introspection JSON not found: #{schema_path}"
29
+ warn 'Pass a path: bundle exec ruby tests/validate_queries.rb <schema.json>'
30
+ exit 2
31
+ end
32
+
33
+ # Build a client offline — stub the session token so no network/creds are needed for rendering.
34
+ Ecoportal::API::Common::GraphQL::Client.class_eval do
35
+ def session_token(*_args, **_kwargs)
36
+ 'dummy'
37
+ end
38
+ end
39
+ client = Ecoportal::API::Common::GraphQL::Client.new(
40
+ email: 'validate@local', pass: 'x', org_id: 'validate', host: 'live.ecoportal.com', no_schema: true
41
+ )
42
+ schema = GraphQL::Schema.from_introspection(JSON.parse(File.read(schema_path)))
43
+
44
+ # Collect every concrete query AND mutation class (recursively, incl. nested like
45
+ # LocationStructure::Draft). Mutations are included because a dead fragment reference (e.g. the
46
+ # removed `___Const__Fragment` convention) only surfaces when the operation is RENDERED — and
47
+ # mutations were previously unscanned, which is exactly how the Action/ContractorEntity mutation
48
+ # fragment breakage reached production undetected.
49
+ op_classes = []
50
+ collect = lambda do |mod|
51
+ mod.constants.each do |const|
52
+ obj = begin
53
+ mod.const_get(const)
54
+ rescue StandardError
55
+ next
56
+ end
57
+ next unless obj.is_a?(Module)
58
+
59
+ op_classes << obj if obj.is_a?(Class) && obj.private_method_defined?(:basic_block)
60
+ collect.call(obj)
61
+ end
62
+ end
63
+ collect.call(Ecoportal::API::GraphQL::Query)
64
+ collect.call(Ecoportal::API::GraphQL::Mutation)
65
+ op_classes.uniq!
66
+
67
+ structural_bugs = {}
68
+ other_errors = {}
69
+ render_failures = {}
70
+ render_skips = []
71
+
72
+ op_classes.sort_by(&:name).each do |klass|
73
+ inst = klass.new(client)
74
+ begin
75
+ query_str = client.to_query_string(&inst.send(:basic_block))
76
+ rescue NameError => e
77
+ # The operation cannot even RENDER — an unresolved constant / dead fragment reference
78
+ # (e.g. the removed `___Const__Fragment` convention pointing at a Fragment:: constant that
79
+ # no longer exists now that fragments are a registry). Same bug class that crashed the live
80
+ # LocationDraft / Action / ContractorEntity paths. HARD FAIL.
81
+ render_failures[klass.name] = ["#{e.class}: #{e.message}"]
82
+ next
83
+ end
84
+ fragments = begin
85
+ inst.send(:assemble_fragments, query_str)
86
+ rescue StandardError
87
+ ''
88
+ end
89
+ full = fragments.to_s.empty? ? query_str : "#{query_str}\n\n#{fragments}"
90
+ messages = schema.validate(full).map(&:message)
91
+ bugs = messages.select { |m| STRUCTURAL.any? { |s| m.include?(s) } }
92
+ other = messages - bugs
93
+ structural_bugs[klass.name] = bugs unless bugs.empty?
94
+ other_errors[klass.name] = other unless other.empty?
95
+ rescue StandardError => e
96
+ render_skips << "#{klass.name} — #{e.class}: #{e.message}"
97
+ end
98
+
99
+ puts "Validated #{op_classes.size} query + mutation classes against #{File.basename(schema_path)}\n\n"
100
+
101
+ puts '## FRAGMENT / RENDER FAILURES (fail the build — operation could not render, e.g. dead fragment ref):'
102
+ if render_failures.empty?
103
+ puts ' none ✅'
104
+ else
105
+ render_failures.each { |name, msgs| puts " #{name}\n - #{msgs.join("\n - ")}" }
106
+ end
107
+
108
+ puts "\n## STRUCTURAL BUGS (fail the build — bare object / over-selected scalar):"
109
+ if structural_bugs.empty?
110
+ puts ' none ✅'
111
+ else
112
+ structural_bugs.each { |name, msgs| puts " #{name}\n - #{msgs.join("\n - ")}" }
113
+ end
114
+
115
+ puts "\n## OTHER validation findings (verify — may be schema-dump staleness or union handling):"
116
+ if other_errors.empty?
117
+ puts ' none'
118
+ else
119
+ other_errors.each { |name, msgs| puts " #{name}\n - #{msgs.first(3).join("\n - ")}" }
120
+ end
121
+
122
+ unless render_skips.empty?
123
+ puts "\n## RENDER-SKIPS (could not auto-render — check manually):"
124
+ render_skips.each { |s| puts " #{s}" }
125
+ end
126
+
127
+ exit(structural_bugs.empty? && render_failures.empty? ? 0 : 1)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecoportal-api-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.9
4
+ version: 1.3.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
@@ -160,7 +160,7 @@ dependencies:
160
160
  version: '3.3'
161
161
  - - ">="
162
162
  - !ruby/object:Gem::Version
163
- version: 3.3.2
163
+ version: 3.3.3
164
164
  type: :runtime
165
165
  prerelease: false
166
166
  version_requirements: !ruby/object:Gem::Requirement
@@ -170,7 +170,7 @@ dependencies:
170
170
  version: '3.3'
171
171
  - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: 3.3.2
173
+ version: 3.3.3
174
174
  - !ruby/object:Gem::Dependency
175
175
  name: graphlient
176
176
  requirement: !ruby/object:Gem::Requirement
@@ -219,6 +219,7 @@ files:
219
219
  - ".ai-assistance/code/data_fields.md"
220
220
  - ".ai-assistance/code/dependencies.md"
221
221
  - ".ai-assistance/code/diff_as_input.md"
222
+ - ".ai-assistance/code/diff_pairing_engine.md"
222
223
  - ".ai-assistance/code/diff_service_deep_dive.md"
223
224
  - ".ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md"
224
225
  - ".ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md"
@@ -241,6 +242,7 @@ files:
241
242
  - ".ai-assistance/code/schema_analysis.md"
242
243
  - ".ai-assistance/code/search_filters.md"
243
244
  - ".ai-assistance/code/spec_coverage.md"
245
+ - ".ai-assistance/code/template_diff_pairing_domain.md"
244
246
  - ".ai-assistance/code/workflow-command-guide.md"
245
247
  - ".ai-assistance/code/workflow-space.md"
246
248
  - ".ai-assistance/conventions/CLAUDE.md"
@@ -267,15 +269,27 @@ files:
267
269
  - ".ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md"
268
270
  - ".ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md"
269
271
  - ".ai-assistance/projects/ooze-graphql-native-migration/INTENT.md"
272
+ - ".ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md"
270
273
  - ".ai-assistance/projects/ooze-graphql-native-migration/RISKS.md"
271
274
  - ".ai-assistance/projects/ooze-graphql-native-migration/TODO.md"
272
275
  - ".ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md"
273
276
  - ".ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md"
274
277
  - ".ai-assistance/projects/page-model/DECISIONS.md"
275
278
  - ".ai-assistance/projects/page-model/TODO.md"
279
+ - ".ai-assistance/projects/qa-services-delivery/DECISIONS.md"
280
+ - ".ai-assistance/projects/qa-services-delivery/INTENT.md"
281
+ - ".ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md"
282
+ - ".ai-assistance/projects/qa-services-delivery/ROADMAP.md"
283
+ - ".ai-assistance/projects/qa-services-delivery/TODO.md"
276
284
  - ".ai-assistance/projects/search-filter-builder/INTENT.md"
277
285
  - ".ai-assistance/projects/search-filter-builder/TODO.md"
286
+ - ".ai-assistance/projects/template-automatic-build-maintenance/INTENT.md"
287
+ - ".ai-assistance/projects/template-automatic-build-maintenance/TODO.md"
288
+ - ".ai-assistance/projects/template-diff-deploy/INTENT.md"
289
+ - ".ai-assistance/projects/template-diff-deploy/TODO.md"
278
290
  - ".ai-assistance/projects/template-maintenance/DESIGN.md"
291
+ - ".ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md"
292
+ - ".ai-assistance/projects/template-maintenance/README.md"
279
293
  - ".ai-assistance/projects/workflow-space/TODO.md"
280
294
  - ".ai-assistance/reinstall-claude-desktop-windows.md"
281
295
  - ".ai-assistance/scripts/CLAUDE.md"
@@ -449,6 +463,7 @@ files:
449
463
  - lib/ecoportal/api/graphql/builder/register.rb
450
464
  - lib/ecoportal/api/graphql/builder/register/preset_view.rb
451
465
  - lib/ecoportal/api/graphql/builder/template.rb
466
+ - lib/ecoportal/api/graphql/builder/template_builder.rb
452
467
  - lib/ecoportal/api/graphql/compat.rb
453
468
  - lib/ecoportal/api/graphql/compat/filter_translator.rb
454
469
  - lib/ecoportal/api/graphql/compat/page_reference.rb
@@ -473,6 +488,18 @@ files:
473
488
  - lib/ecoportal/api/graphql/connection/person_member.rb
474
489
  - lib/ecoportal/api/graphql/connection/preset_view.rb
475
490
  - lib/ecoportal/api/graphql/connection/preview_page.rb
491
+ - lib/ecoportal/api/graphql/diff.rb
492
+ - lib/ecoportal/api/graphql/diff/change.rb
493
+ - lib/ecoportal/api/graphql/diff/command_synthesizer.rb
494
+ - lib/ecoportal/api/graphql/diff/cross_object_diff.rb
495
+ - lib/ecoportal/api/graphql/diff/deploy.rb
496
+ - lib/ecoportal/api/graphql/diff/id_resolver.rb
497
+ - lib/ecoportal/api/graphql/diff/pairing/candidate.rb
498
+ - lib/ecoportal/api/graphql/diff/pairing/engine.rb
499
+ - lib/ecoportal/api/graphql/diff/pairing/ledger.rb
500
+ - lib/ecoportal/api/graphql/diff/pairing/signals.rb
501
+ - lib/ecoportal/api/graphql/diff/strategy.rb
502
+ - lib/ecoportal/api/graphql/diff/version_diff.rb
476
503
  - lib/ecoportal/api/graphql/error.rb
477
504
  - lib/ecoportal/api/graphql/error/locations_error.rb
478
505
  - lib/ecoportal/api/graphql/error/locations_error/fetch_nested.rb
@@ -826,10 +853,12 @@ files:
826
853
  - tests/contractor_entity_create.rb
827
854
  - tests/contractor_entity_udpate.rb
828
855
  - tests/dump_page_model.rb
856
+ - tests/dump_template_model.rb
829
857
  - tests/loc_structure_get.rb
830
858
  - tests/loc_structure_update.rb
831
859
  - tests/loc_structures_get.rb
832
860
  - tests/local_libs.rb
861
+ - tests/validate_queries.rb
833
862
  homepage: https://www.ecoportal.com
834
863
  licenses:
835
864
  - MIT