ecoportal-api-graphql 1.3.10 → 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 (52) 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/ooze-graphql-native-migration/INVENTORY.md +136 -0
  7. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +6 -1
  8. data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +93 -0
  9. data/.ai-assistance/projects/qa-services-delivery/INTENT.md +76 -0
  10. data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +115 -0
  11. data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +99 -0
  12. data/.ai-assistance/projects/qa-services-delivery/TODO.md +81 -0
  13. data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +77 -0
  14. data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +97 -0
  15. data/.ai-assistance/projects/template-diff-deploy/INTENT.md +12 -0
  16. data/.ai-assistance/projects/template-diff-deploy/TODO.md +9 -0
  17. data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +93 -0
  18. data/.ai-assistance/projects/template-maintenance/README.md +14 -0
  19. data/CHANGELOG.md +87 -0
  20. data/docs/worklog.md +279 -0
  21. data/ecoportal-api-graphql.gemspec +1 -1
  22. data/lib/ecoportal/api/graphql/base/page/data_field.rb +1 -1
  23. data/lib/ecoportal/api/graphql/builder/template_builder.rb +174 -0
  24. data/lib/ecoportal/api/graphql/builder.rb +17 -16
  25. data/lib/ecoportal/api/graphql/diff/change.rb +59 -0
  26. data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +329 -0
  27. data/lib/ecoportal/api/graphql/diff/cross_object_diff.rb +165 -0
  28. data/lib/ecoportal/api/graphql/diff/deploy.rb +121 -0
  29. data/lib/ecoportal/api/graphql/diff/id_resolver.rb +64 -0
  30. data/lib/ecoportal/api/graphql/diff/pairing/candidate.rb +32 -0
  31. data/lib/ecoportal/api/graphql/diff/pairing/engine.rb +173 -0
  32. data/lib/ecoportal/api/graphql/diff/pairing/ledger.rb +119 -0
  33. data/lib/ecoportal/api/graphql/diff/pairing/signals.rb +104 -0
  34. data/lib/ecoportal/api/graphql/diff/strategy.rb +113 -0
  35. data/lib/ecoportal/api/graphql/diff/version_diff.rb +332 -0
  36. data/lib/ecoportal/api/graphql/diff.rb +34 -0
  37. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +1 -0
  38. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +27 -18
  39. data/lib/ecoportal/api/graphql/mutation/action/archive.rb +1 -1
  40. data/lib/ecoportal/api/graphql/mutation/action/create.rb +1 -1
  41. data/lib/ecoportal/api/graphql/mutation/action/update.rb +1 -1
  42. data/lib/ecoportal/api/graphql/mutation/contractor_entity/create.rb +1 -1
  43. data/lib/ecoportal/api/graphql/mutation/contractor_entity/destroy.rb +1 -1
  44. data/lib/ecoportal/api/graphql/mutation/contractor_entity/update.rb +1 -1
  45. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +1 -1
  46. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +1 -1
  47. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +1 -1
  48. data/lib/ecoportal/api/graphql.rb +1 -0
  49. data/lib/ecoportal/api/graphql_version.rb +1 -1
  50. data/tests/dump_template_model.rb +90 -0
  51. data/tests/validate_queries.rb +31 -9
  52. metadata +31 -3
@@ -28,7 +28,7 @@ module Ecoportal
28
28
  fullMessages
29
29
  }
30
30
  item {
31
- ___Fragment__ContractorEntity
31
+ spread :ContractorEntity
32
32
  }
33
33
  }
34
34
  end
@@ -28,7 +28,7 @@ module Ecoportal
28
28
  fullMessages
29
29
  }
30
30
  item {
31
- ___Fragment__ContractorEntity
31
+ spread :ContractorEntity
32
32
  }
33
33
  }
34
34
  end
@@ -28,7 +28,7 @@ module Ecoportal
28
28
  fullMessages
29
29
  }
30
30
  item {
31
- ___Fragment__ContractorEntity
31
+ spread :ContractorEntity
32
32
  }
33
33
  }
34
34
  end
@@ -27,7 +27,7 @@ module Ecoportal
27
27
 
28
28
  def default_payload_block
29
29
  proc {
30
- item { id name status failedAt }
30
+ item { id name status failedAt { dateTime timeZone } }
31
31
  errors { details fullMessages }
32
32
  }
33
33
  end
@@ -27,7 +27,7 @@ module Ecoportal
27
27
 
28
28
  def default_payload_block
29
29
  proc {
30
- item { id name status startedAt }
30
+ item { id name status startedAt { dateTime timeZone } }
31
31
  errors { details fullMessages }
32
32
  }
33
33
  end
@@ -27,7 +27,7 @@ module Ecoportal
27
27
 
28
28
  def default_payload_block
29
29
  proc {
30
- item { id name status stoppedAt }
30
+ item { id name status stoppedAt { dateTime timeZone } }
31
31
  errors { details fullMessages }
32
32
  }
33
33
  end
@@ -136,3 +136,4 @@ require_relative 'graphql/mutation'
136
136
  require_relative 'graphql/builder'
137
137
  require_relative 'graphql/compat'
138
138
  require_relative 'graphql/file_upload'
139
+ require_relative 'graphql/diff'
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- GRAPQL_VERSION = '1.3.10'.freeze
3
+ GRAPQL_VERSION = '1.3.11'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,90 @@
1
+ require_relative 'local_libs'
2
+ require 'json'
3
+ require 'fileutils'
4
+
5
+ # Dump a TEMPLATE's GraphQL model to JSON, so a real template can be captured as the golden
6
+ # fixture for the template-editing pipeline (build-from-scratch + diff-and-update).
7
+ #
8
+ # A template IS a page in this API (Query::Templates returns PageUnion nodes), so its structural
9
+ # skeleton — stages -> sections -> components(fields) — comes from the ordinary page model, exactly
10
+ # like tests/dump_page_model.rb. On top of that, this tool also captures the page's *workflow
11
+ # command log* (Query::PagesWorkflowCommands) — the applied command history that drives the
12
+ # workflow builder (callbacks / operations / strategies / recipients config).
13
+ #
14
+ # Two artefacts are written per template:
15
+ # spec/fixtures/templates/<id>[_<label>].json -> structural page doc (golden master)
16
+ # spec/fixtures/templates/<id>[_<label>].commands.json -> workflow command log (if readable)
17
+ #
18
+ # Usage (run where the GraphQL connection is configured, like the other tests/):
19
+ # ruby tests/dump_template_model.rb <TEMPLATE_ID> [--out PATH] [--label before|after]
20
+ #
21
+ # Reference target (see .ai-assistance/projects/template-maintenance/DESIGN.md):
22
+ # ruby tests/dump_template_model.rb 6a3fa5b8f89e07c758df622b --label golden
23
+ #
24
+ # Run --label before / --label after around an executeWorkflowCommands batch to diff exactly
25
+ # what a command sequence changed — the same before/after workflow dump_page_model.rb enables.
26
+
27
+ def parse_args(argv)
28
+ opts = { template_id: nil, out: nil, label: nil }
29
+ rest = argv.dup
30
+ opts[:template_id] = rest.shift
31
+ until rest.empty?
32
+ flag = rest.shift
33
+ case flag
34
+ when '--out' then opts[:out] = rest.shift
35
+ when '--label' then opts[:label] = rest.shift
36
+ else
37
+ warn "Unknown argument: #{flag}"
38
+ end
39
+ end
40
+ opts
41
+ end
42
+
43
+ opts = parse_args(ARGV)
44
+
45
+ unless opts[:template_id]
46
+ warn 'Usage: ruby tests/dump_template_model.rb <TEMPLATE_ID> [--out PATH] [--label before|after]'
47
+ exit 1
48
+ end
49
+
50
+ default_dir = File.expand_path('../spec/fixtures/templates', __dir__)
51
+ default_name = [opts[:template_id], opts[:label]].compact.join('_')
52
+ struct_path = opts[:out] || File.join(default_dir, "#{default_name}.json")
53
+ commands_path = File.join(File.dirname(struct_path), "#{File.basename(struct_path, '.json')}.commands.json")
54
+
55
+ api = Ecoportal::API::GraphQL.new
56
+
57
+ # 1) Structural skeleton — a template is a page, so fetch it via the page model.
58
+ page = api.pages.get(opts[:template_id])
59
+
60
+ if page.nil?
61
+ warn "Could not fetch template '#{opts[:template_id]}' as a page"
62
+ exit 2
63
+ end
64
+
65
+ doc = page.respond_to?(:doc) ? page.doc : page.instance_variable_get(:@page)&.doc
66
+
67
+ FileUtils.mkdir_p(File.dirname(struct_path))
68
+ File.write(struct_path, JSON.pretty_generate(doc))
69
+
70
+ puts "Dumped template structure '#{opts[:template_id]}' -> #{struct_path}"
71
+ puts " name: #{page.respond_to?(:name) ? page.name : '(n/a)'}"
72
+ puts " patchVer: #{page.respond_to?(:patchVer) ? page.patchVer : '(n/a)'}"
73
+
74
+ # 2) Workflow command log — the applied-command history behind the workflow builder.
75
+ # Wrapped in a rescue: the PagesWorkflow read model is still partial (stages is a bare
76
+ # passarray as of SCHEMA_VERSION 20260605), so treat this as best-effort.
77
+ begin
78
+ query = Ecoportal::API::GraphQL::Query::PagesWorkflowCommands.new(api.client)
79
+ commands = []
80
+ query.each(id: opts[:template_id], first: 100) do |cmd|
81
+ commands << (cmd.respond_to?(:doc) ? cmd.doc : cmd)
82
+ end
83
+ File.write(commands_path, JSON.pretty_generate(commands))
84
+ puts "Dumped #{commands.size} workflow command(s) -> #{commands_path}"
85
+ rescue StandardError => e
86
+ warn "Workflow command log not captured (#{e.class}: #{e.message})"
87
+ warn ' -> structural fixture is still valid; the command log read may be WIP for this org.'
88
+ end
89
+
90
+ puts 'Tip: capture --label before and --label after an executeWorkflowCommands batch, then diff the JSON.'
@@ -41,8 +41,12 @@ client = Ecoportal::API::Common::GraphQL::Client.new(
41
41
  )
42
42
  schema = GraphQL::Schema.from_introspection(JSON.parse(File.read(schema_path)))
43
43
 
44
- # Collect every concrete query class (recursively, incl. nested like LocationStructure::Draft).
45
- query_classes = []
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 = []
46
50
  collect = lambda do |mod|
47
51
  mod.constants.each do |const|
48
52
  obj = begin
@@ -52,20 +56,31 @@ collect = lambda do |mod|
52
56
  end
53
57
  next unless obj.is_a?(Module)
54
58
 
55
- query_classes << obj if obj.is_a?(Class) && obj.private_method_defined?(:basic_block)
59
+ op_classes << obj if obj.is_a?(Class) && obj.private_method_defined?(:basic_block)
56
60
  collect.call(obj)
57
61
  end
58
62
  end
59
63
  collect.call(Ecoportal::API::GraphQL::Query)
60
- query_classes.uniq!
64
+ collect.call(Ecoportal::API::GraphQL::Mutation)
65
+ op_classes.uniq!
61
66
 
62
67
  structural_bugs = {}
63
68
  other_errors = {}
69
+ render_failures = {}
64
70
  render_skips = []
65
71
 
66
- query_classes.sort_by(&:name).each do |klass|
72
+ op_classes.sort_by(&:name).each do |klass|
67
73
  inst = klass.new(client)
68
- query_str = client.to_query_string(&inst.send(:basic_block))
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
69
84
  fragments = begin
70
85
  inst.send(:assemble_fragments, query_str)
71
86
  rescue StandardError
@@ -81,9 +96,16 @@ rescue StandardError => e
81
96
  render_skips << "#{klass.name} — #{e.class}: #{e.message}"
82
97
  end
83
98
 
84
- puts "Validated #{query_classes.size} query classes against #{File.basename(schema_path)}\n\n"
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
85
107
 
86
- puts '## STRUCTURAL BUGS (fail the build — bare object / over-selected scalar):'
108
+ puts "\n## STRUCTURAL BUGS (fail the build — bare object / over-selected scalar):"
87
109
  if structural_bugs.empty?
88
110
  puts ' none ✅'
89
111
  else
@@ -102,4 +124,4 @@ unless render_skips.empty?
102
124
  render_skips.each { |s| puts " #{s}" }
103
125
  end
104
126
 
105
- exit(structural_bugs.empty? ? 0 : 1)
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.10
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,6 +853,7 @@ 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