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.
- checksums.yaml +4 -4
- data/.ai-assistance/code/diff_pairing_engine.md +243 -0
- data/.ai-assistance/code/graphql_domain_knowledge.md +20 -10
- data/.ai-assistance/code/template_diff_pairing_domain.md +175 -0
- data/.ai-assistance/code/workflow-command-guide.md +28 -0
- data/.ai-assistance/projects/TODO.md +21 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +136 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +6 -1
- data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +93 -0
- data/.ai-assistance/projects/qa-services-delivery/INTENT.md +76 -0
- data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +115 -0
- data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +99 -0
- data/.ai-assistance/projects/qa-services-delivery/TODO.md +81 -0
- data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +77 -0
- data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +97 -0
- data/.ai-assistance/projects/template-diff-deploy/INTENT.md +12 -0
- data/.ai-assistance/projects/template-diff-deploy/TODO.md +9 -0
- data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +93 -0
- data/.ai-assistance/projects/template-maintenance/README.md +14 -0
- data/CHANGELOG.md +116 -0
- data/docs/worklog.md +408 -0
- data/ecoportal-api-graphql.gemspec +1 -1
- data/lib/ecoportal/api/graphql/base/page/data_field.rb +1 -1
- data/lib/ecoportal/api/graphql/builder/template_builder.rb +174 -0
- data/lib/ecoportal/api/graphql/builder.rb +17 -16
- data/lib/ecoportal/api/graphql/diff/change.rb +59 -0
- data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +329 -0
- data/lib/ecoportal/api/graphql/diff/cross_object_diff.rb +165 -0
- data/lib/ecoportal/api/graphql/diff/deploy.rb +121 -0
- data/lib/ecoportal/api/graphql/diff/id_resolver.rb +64 -0
- data/lib/ecoportal/api/graphql/diff/pairing/candidate.rb +32 -0
- data/lib/ecoportal/api/graphql/diff/pairing/engine.rb +173 -0
- data/lib/ecoportal/api/graphql/diff/pairing/ledger.rb +119 -0
- data/lib/ecoportal/api/graphql/diff/pairing/signals.rb +104 -0
- data/lib/ecoportal/api/graphql/diff/strategy.rb +113 -0
- data/lib/ecoportal/api/graphql/diff/version_diff.rb +332 -0
- data/lib/ecoportal/api/graphql/diff.rb +34 -0
- data/lib/ecoportal/api/graphql/fragment/location_draft.rb +53 -53
- data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +1 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +27 -18
- data/lib/ecoportal/api/graphql/mutation/action/archive.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/action/create.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/action/update.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/contractor_entity/create.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/contractor_entity/destroy.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/contractor_entity/update.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +1 -1
- data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +62 -62
- data/lib/ecoportal/api/graphql/query/location_structure.rb +61 -61
- data/lib/ecoportal/api/graphql.rb +139 -138
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- data/tests/dump_template_model.rb +90 -0
- data/tests/validate_queries.rb +127 -0
- 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.
|
|
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.
|
|
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.
|
|
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
|