ecoportal-api-graphql 1.3.12 → 1.3.13
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/projects/compat-layer-audit/COMPAT_AUDIT.md +244 -0
- data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +236 -0
- data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +243 -0
- data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +154 -0
- data/.ai-assistance/scripts/bridge-inbox-check.sh +75 -0
- data/.ai-assistance/skills/project-self-docs/SKILL.md +181 -0
- data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +378 -0
- data/.ai-assistance/standards-version.json +9 -9
- data/.claude/settings.json +150 -146
- data/.gitlab-ci.yml +45 -0
- data/CHANGELOG.md +26 -0
- data/CLAUDE.md +1 -0
- data/docs/self-docs/ARCHITECTURE.md +3 -3
- data/docs/self-docs/CHANGES.jsonl +5 -0
- data/docs/self-docs/COMPLIANCE.md +79 -0
- data/docs/self-docs/CONVENTIONS.md +3 -3
- data/docs/self-docs/INTEGRATIONS.md +17 -15
- data/docs/self-docs/OPERATIONS.md +76 -0
- data/docs/self-docs/OVERVIEW.md +16 -3
- data/docs/self-docs/STATUS.md +9 -5
- data/docs/self-docs/self-docs-index.json +20 -8
- data/docs/worklog.md +18 -0
- data/lib/ecoportal/api/common/graphql/client.rb +2 -0
- data/lib/ecoportal/api/common/graphql/http_client.rb +189 -177
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- metadata +11 -1
data/.claude/settings.json
CHANGED
|
@@ -1,146 +1,150 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"defaultMode": "auto",
|
|
4
|
-
"allowedTools": [
|
|
5
|
-
"Read"
|
|
6
|
-
],
|
|
7
|
-
"permissionRules": [
|
|
8
|
-
{
|
|
9
|
-
"tool": "Write",
|
|
10
|
-
"pattern": "/**",
|
|
11
|
-
"action": "allow"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"tool": "StrReplace",
|
|
15
|
-
"pattern": "/**",
|
|
16
|
-
"action": "allow"
|
|
17
|
-
}
|
|
18
|
-
],
|
|
19
|
-
"allow": [
|
|
20
|
-
"WebFetch(domain:anthropic.com)",
|
|
21
|
-
"WebFetch(domain:npmjs.com)",
|
|
22
|
-
"Write(.glaudeignore)",
|
|
23
|
-
"Update(.glaudeignore)",
|
|
24
|
-
"Bash(rm .ai-assistance/bridge/LOCK)",
|
|
25
|
-
"Read(.git/**)",
|
|
26
|
-
"Read(**/rubygems/**)",
|
|
27
|
-
"Write(*.md)",
|
|
28
|
-
"Edit(.ai-assistance/**)",
|
|
29
|
-
"Update(.ai-assistance/**)",
|
|
30
|
-
"Write(.ai-assistance/**)",
|
|
31
|
-
"Write(lib/**)",
|
|
32
|
-
"Write(spec/**)",
|
|
33
|
-
"Bash(git status)",
|
|
34
|
-
"Bash(git diff *)",
|
|
35
|
-
"Bash(git log *)",
|
|
36
|
-
"Bash(git add *)",
|
|
37
|
-
"Bash(git commit *)",
|
|
38
|
-
"PowerShell(git status)",
|
|
39
|
-
"PowerShell(git diff *)",
|
|
40
|
-
"PowerShell(git log *)",
|
|
41
|
-
"PowerShell(git add *)",
|
|
42
|
-
"PowerShell(git commit *)",
|
|
43
|
-
"Bash(npm test)",
|
|
44
|
-
"Bash(npm run lint)",
|
|
45
|
-
"Bash(npm run build)",
|
|
46
|
-
"Bash(vitest *)",
|
|
47
|
-
"Bash(jest *)",
|
|
48
|
-
"PowerShell(npm test)",
|
|
49
|
-
"PowerShell(npm run lint)",
|
|
50
|
-
"PowerShell(npm run build)",
|
|
51
|
-
"Bash(black .)",
|
|
52
|
-
"Bash(pytest)",
|
|
53
|
-
"Bash(python -m unittest)",
|
|
54
|
-
"Bash(ruff check *)",
|
|
55
|
-
"Bash(bundle exec rspec *)",
|
|
56
|
-
"Bash(bundle exec rubocop *)",
|
|
57
|
-
"PowerShell(pytest)",
|
|
58
|
-
"PowerShell(python -m unittest)",
|
|
59
|
-
"PowerShell(ruff check *)",
|
|
60
|
-
"PowerShell(bundle exec rspec *)",
|
|
61
|
-
"PowerShell(bundle exec rubocop *)",
|
|
62
|
-
"Bash(node .ai-assistance/scripts/token-logger.js)",
|
|
63
|
-
"Bash(node .ai-assistance/scripts/token-session-start.js)",
|
|
64
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git status*)",
|
|
65
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git log*)",
|
|
66
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git diff*)",
|
|
67
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git show*)",
|
|
68
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git branch*)",
|
|
69
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git fetch*)",
|
|
70
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git checkout*)",
|
|
71
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git switch*)",
|
|
72
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git add*)",
|
|
73
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git commit*)",
|
|
74
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git rev-parse*)",
|
|
75
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git merge-base*)",
|
|
76
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git ls-remote*)",
|
|
77
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && git stash*)",
|
|
78
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rspec*)",
|
|
79
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rake test*)",
|
|
80
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rubocop*)",
|
|
81
|
-
"Bash(cd C:/ruby_scripts/git/graphlient && bundle install*)",
|
|
82
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git status*)",
|
|
83
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git log*)",
|
|
84
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git diff*)",
|
|
85
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git show*)",
|
|
86
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git branch*)",
|
|
87
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git fetch*)",
|
|
88
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git checkout*)",
|
|
89
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git switch*)",
|
|
90
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git add*)",
|
|
91
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git commit*)",
|
|
92
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git rev-parse*)",
|
|
93
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git merge-base*)",
|
|
94
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git ls-remote*)",
|
|
95
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && git stash*)",
|
|
96
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle exec rake test*)",
|
|
97
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle exec rubocop*)",
|
|
98
|
-
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle install*)"
|
|
99
|
-
],
|
|
100
|
-
"deny": [
|
|
101
|
-
"Read(*.env)",
|
|
102
|
-
"Read(./.env*)",
|
|
103
|
-
"Read(./secrets/**)",
|
|
104
|
-
"Bash(*cat *.env*)",
|
|
105
|
-
"Bash(*grep *.env*)",
|
|
106
|
-
"Bash(printenv*)",
|
|
107
|
-
"Bash(env)",
|
|
108
|
-
"Write(.git/*)",
|
|
109
|
-
"Edit(.git/*)",
|
|
110
|
-
"Bash(git push *)",
|
|
111
|
-
"Bash(rm -rf *)"
|
|
112
|
-
]
|
|
113
|
-
},
|
|
114
|
-
"hooks": {
|
|
115
|
-
"SessionStart": [
|
|
116
|
-
{
|
|
117
|
-
"matcher": "",
|
|
118
|
-
"hooks": [
|
|
119
|
-
{
|
|
120
|
-
"type": "command",
|
|
121
|
-
"command": "bash .ai-assistance/scripts/bridge-init.sh 2>/dev/null || true"
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
"type": "command",
|
|
125
|
-
"command": "node .ai-assistance/scripts/token-session-start.js 2>/dev/null || true"
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
{
|
|
139
|
-
"type": "command",
|
|
140
|
-
"command": "
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"defaultMode": "auto",
|
|
4
|
+
"allowedTools": [
|
|
5
|
+
"Read"
|
|
6
|
+
],
|
|
7
|
+
"permissionRules": [
|
|
8
|
+
{
|
|
9
|
+
"tool": "Write",
|
|
10
|
+
"pattern": "/**",
|
|
11
|
+
"action": "allow"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"tool": "StrReplace",
|
|
15
|
+
"pattern": "/**",
|
|
16
|
+
"action": "allow"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"allow": [
|
|
20
|
+
"WebFetch(domain:anthropic.com)",
|
|
21
|
+
"WebFetch(domain:npmjs.com)",
|
|
22
|
+
"Write(.glaudeignore)",
|
|
23
|
+
"Update(.glaudeignore)",
|
|
24
|
+
"Bash(rm .ai-assistance/bridge/LOCK)",
|
|
25
|
+
"Read(.git/**)",
|
|
26
|
+
"Read(**/rubygems/**)",
|
|
27
|
+
"Write(*.md)",
|
|
28
|
+
"Edit(.ai-assistance/**)",
|
|
29
|
+
"Update(.ai-assistance/**)",
|
|
30
|
+
"Write(.ai-assistance/**)",
|
|
31
|
+
"Write(lib/**)",
|
|
32
|
+
"Write(spec/**)",
|
|
33
|
+
"Bash(git status)",
|
|
34
|
+
"Bash(git diff *)",
|
|
35
|
+
"Bash(git log *)",
|
|
36
|
+
"Bash(git add *)",
|
|
37
|
+
"Bash(git commit *)",
|
|
38
|
+
"PowerShell(git status)",
|
|
39
|
+
"PowerShell(git diff *)",
|
|
40
|
+
"PowerShell(git log *)",
|
|
41
|
+
"PowerShell(git add *)",
|
|
42
|
+
"PowerShell(git commit *)",
|
|
43
|
+
"Bash(npm test)",
|
|
44
|
+
"Bash(npm run lint)",
|
|
45
|
+
"Bash(npm run build)",
|
|
46
|
+
"Bash(vitest *)",
|
|
47
|
+
"Bash(jest *)",
|
|
48
|
+
"PowerShell(npm test)",
|
|
49
|
+
"PowerShell(npm run lint)",
|
|
50
|
+
"PowerShell(npm run build)",
|
|
51
|
+
"Bash(black .)",
|
|
52
|
+
"Bash(pytest)",
|
|
53
|
+
"Bash(python -m unittest)",
|
|
54
|
+
"Bash(ruff check *)",
|
|
55
|
+
"Bash(bundle exec rspec *)",
|
|
56
|
+
"Bash(bundle exec rubocop *)",
|
|
57
|
+
"PowerShell(pytest)",
|
|
58
|
+
"PowerShell(python -m unittest)",
|
|
59
|
+
"PowerShell(ruff check *)",
|
|
60
|
+
"PowerShell(bundle exec rspec *)",
|
|
61
|
+
"PowerShell(bundle exec rubocop *)",
|
|
62
|
+
"Bash(node .ai-assistance/scripts/token-logger.js)",
|
|
63
|
+
"Bash(node .ai-assistance/scripts/token-session-start.js)",
|
|
64
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git status*)",
|
|
65
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git log*)",
|
|
66
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git diff*)",
|
|
67
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git show*)",
|
|
68
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git branch*)",
|
|
69
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git fetch*)",
|
|
70
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git checkout*)",
|
|
71
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git switch*)",
|
|
72
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git add*)",
|
|
73
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git commit*)",
|
|
74
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git rev-parse*)",
|
|
75
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git merge-base*)",
|
|
76
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git ls-remote*)",
|
|
77
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && git stash*)",
|
|
78
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rspec*)",
|
|
79
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rake test*)",
|
|
80
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && bundle exec rubocop*)",
|
|
81
|
+
"Bash(cd C:/ruby_scripts/git/graphlient && bundle install*)",
|
|
82
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git status*)",
|
|
83
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git log*)",
|
|
84
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git diff*)",
|
|
85
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git show*)",
|
|
86
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git branch*)",
|
|
87
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git fetch*)",
|
|
88
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git checkout*)",
|
|
89
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git switch*)",
|
|
90
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git add*)",
|
|
91
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git commit*)",
|
|
92
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git rev-parse*)",
|
|
93
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git merge-base*)",
|
|
94
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git ls-remote*)",
|
|
95
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && git stash*)",
|
|
96
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle exec rake test*)",
|
|
97
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle exec rubocop*)",
|
|
98
|
+
"Bash(cd C:/ruby_scripts/git/graphql-client && bundle install*)"
|
|
99
|
+
],
|
|
100
|
+
"deny": [
|
|
101
|
+
"Read(*.env)",
|
|
102
|
+
"Read(./.env*)",
|
|
103
|
+
"Read(./secrets/**)",
|
|
104
|
+
"Bash(*cat *.env*)",
|
|
105
|
+
"Bash(*grep *.env*)",
|
|
106
|
+
"Bash(printenv*)",
|
|
107
|
+
"Bash(env)",
|
|
108
|
+
"Write(.git/*)",
|
|
109
|
+
"Edit(.git/*)",
|
|
110
|
+
"Bash(git push *)",
|
|
111
|
+
"Bash(rm -rf *)"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"hooks": {
|
|
115
|
+
"SessionStart": [
|
|
116
|
+
{
|
|
117
|
+
"matcher": "",
|
|
118
|
+
"hooks": [
|
|
119
|
+
{
|
|
120
|
+
"type": "command",
|
|
121
|
+
"command": "bash .ai-assistance/scripts/bridge-init.sh 2>/dev/null || true"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"type": "command",
|
|
125
|
+
"command": "node .ai-assistance/scripts/token-session-start.js 2>/dev/null || true"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"type": "command",
|
|
129
|
+
"command": "bash .ai-assistance/scripts/bridge-inbox-check.sh 2>/dev/null || true"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"Stop": [
|
|
135
|
+
{
|
|
136
|
+
"matcher": "",
|
|
137
|
+
"hooks": [
|
|
138
|
+
{
|
|
139
|
+
"type": "command",
|
|
140
|
+
"command": "node .ai-assistance/scripts/token-logger.js 2>/dev/null || true"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"type": "command",
|
|
144
|
+
"command": "bash scripts/auto-worker-scheduler.sh 2>/dev/null || true"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
}
|
data/.gitlab-ci.yml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# CI pipeline for ecoportal-api-graphql
|
|
2
|
+
#
|
|
3
|
+
# First automated check on merge requests. Runs the RSpec suite NON-BLOCKING
|
|
4
|
+
# (allow_failure: true) — it reports pass/fail status without gating merges.
|
|
5
|
+
# Rationale (2026-07-10): add visibility now; tighten to a blocking gate later
|
|
6
|
+
# once the suite is reliably green on a clean runner.
|
|
7
|
+
#
|
|
8
|
+
# Live/AI specs (tagged :live) are excluded: they need ANTHROPIC_API_KEY + network.
|
|
9
|
+
# They already self-skip when the key is absent, but ~live keeps the runner off
|
|
10
|
+
# that path entirely.
|
|
11
|
+
#
|
|
12
|
+
# NOTE: graphlient resolves from a git fork (see Gemfile); ecoportal-api / -v2 come
|
|
13
|
+
# from rubygems. If a required floor (e.g. ecoportal-api-v2 >= 3.3.3) is not yet
|
|
14
|
+
# published, `bundle install` may fail on the runner — because this job is
|
|
15
|
+
# allow_failure, that surfaces as a warning rather than blocking the MR.
|
|
16
|
+
|
|
17
|
+
workflow:
|
|
18
|
+
rules:
|
|
19
|
+
# Merge-request pipelines.
|
|
20
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
21
|
+
# Avoid a duplicate branch pipeline when an MR is already open for the branch.
|
|
22
|
+
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
|
|
23
|
+
when: never
|
|
24
|
+
# Branch pipelines (incl. main/master pushes and feature branches without an MR).
|
|
25
|
+
- if: '$CI_COMMIT_BRANCH'
|
|
26
|
+
|
|
27
|
+
stages:
|
|
28
|
+
- test
|
|
29
|
+
|
|
30
|
+
rspec:
|
|
31
|
+
stage: test
|
|
32
|
+
image: ruby:3.2.2
|
|
33
|
+
allow_failure: true # non-blocking: surface failures, do not gate merges
|
|
34
|
+
variables:
|
|
35
|
+
BUNDLE_PATH: vendor/bundle # cache installed gems between pipelines
|
|
36
|
+
cache:
|
|
37
|
+
key: "ruby-322-bundle"
|
|
38
|
+
paths:
|
|
39
|
+
- vendor/bundle
|
|
40
|
+
before_script:
|
|
41
|
+
- ruby -v
|
|
42
|
+
- gem install bundler
|
|
43
|
+
- bundle install --jobs "$(nproc)" --retry 3
|
|
44
|
+
script:
|
|
45
|
+
- bundle exec rspec --tag ~live --format progress
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.13] - 2026-07-12
|
|
6
|
+
|
|
7
|
+
Reliability: the GraphQL `HttpClient` now inherits the **same request-resilience
|
|
8
|
+
contingencies as the REST clients** instead of a bespoke, divergent request path.
|
|
9
|
+
**Backwards-compatible** — `execute` returns the same parsed body and raises the same
|
|
10
|
+
error classes; only the transport path changed.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`Common::GraphQL::HttpClient#execute` no longer bypasses the inherited
|
|
15
|
+
`Common::Client` pipeline.** It previously issued the POST raw
|
|
16
|
+
(`base_request.post`) and handled the response itself, so GraphQL requests got
|
|
17
|
+
**none** of the resilience baked into `ecoportal-api`'s client over the years —
|
|
18
|
+
a single **HTTP 429** (Cloudflare edge rate-limit, error `1015`) aborted the whole
|
|
19
|
+
run. `execute` now routes through `instrument` → `with_retry { rate_throttling }`,
|
|
20
|
+
gaining for free:
|
|
21
|
+
- **rate-limit backoff** via `rate_throttle_client` (default
|
|
22
|
+
`ExponentialIncreaseProportionalDecrease`) — 429s are throttled + retried, not fatal.
|
|
23
|
+
- **retry on 5xx / connection errors** (`WithRetry`, 5 attempts) + empty-body guard.
|
|
24
|
+
- timeouts, and (deep-)logging / APM instrumentation.
|
|
25
|
+
- `handle_http_response` now consumes the wrapped `Common::Response` (single body
|
|
26
|
+
read — also removes a latent double-read hazard). The GraphQL-errors-in-a-200-body
|
|
27
|
+
path (`ResponseError`) is unchanged.
|
|
28
|
+
This is convergence on the shared base, so any future contingency added to
|
|
29
|
+
`Common::Client` now applies to GraphQL automatically.
|
|
30
|
+
|
|
5
31
|
## [1.3.12] - 2026-07-09
|
|
6
32
|
|
|
7
33
|
Compat-layer correctness for register **field filters** + the native `SearchConf` field-filter DSL.
|
data/CLAUDE.md
CHANGED
|
@@ -11,6 +11,7 @@ docs/worklog.md ← current state, blockers, open quest
|
|
|
11
11
|
.ai-assistance/projects/<slug>/TODO.md ← active project task list
|
|
12
12
|
.ai-assistance/local/paths.json ← local paths to sibling repos (gitignored — machine-specific)
|
|
13
13
|
.ai-assistance/bridge/CLAUDE.md ← bridge protocol: format, lifecycle, cross-repo requests
|
|
14
|
+
.ai-assistance/bridge/inbox/ <- unread cross-project bridge messages (PENDING = unread); surfaced at session start by .ai-assistance/scripts/bridge-inbox-check.sh
|
|
14
15
|
.ai-assistance/code/ecoPortal_architecture/ ← VERIFIED PLATFORM KNOWLEDGE — how the platform behaves
|
|
15
16
|
(data model, API layers, page/stage workflows, fields, search).
|
|
16
17
|
Read 00_overview_and_index first, then the area file for the
|
|
@@ -5,3 +5,8 @@
|
|
|
5
5
|
{"ts": "2026-07-06T11:14:43Z", "file": "docs/self-docs/STATUS.md", "change": "created", "from_hash": null, "to_hash": "08841d1d45eea2d6"}
|
|
6
6
|
{"ts": "2026-07-06T11:15:00Z", "file": "docs/self-docs/OVERVIEW.md", "change": "updated", "from_hash": "a43c976a85ebfad6", "to_hash": "391055c9a6a687b9"}
|
|
7
7
|
{"ts": "2026-07-06T11:15:00Z", "file": "docs/self-docs/ARCHITECTURE.md", "change": "updated", "from_hash": "b0989977a912aab1", "to_hash": "ad05f25b95b49c00"}
|
|
8
|
+
{"ts": "2026-07-09T07:08:00Z", "file": "docs/self-docs/OVERVIEW.md", "change": "updated", "from_hash": "391055c9a6a687b9", "to_hash": "c403012498ab9247"}
|
|
9
|
+
{"ts": "2026-07-09T07:08:00Z", "file": "docs/self-docs/INTEGRATIONS.md", "change": "updated", "from_hash": "bae9f91748e33af1", "to_hash": "d271ac76361e4638"}
|
|
10
|
+
{"ts": "2026-07-09T07:08:00Z", "file": "docs/self-docs/STATUS.md", "change": "updated", "from_hash": "08841d1d45eea2d6", "to_hash": "1acf51a3e7822dfb"}
|
|
11
|
+
{"ts": "2026-07-09T07:08:00Z", "file": "docs/self-docs/COMPLIANCE.md", "change": "created", "from_hash": null, "to_hash": "1e72c2356b4e3579"}
|
|
12
|
+
{"ts": "2026-07-09T07:08:00Z", "file": "docs/self-docs/OPERATIONS.md", "change": "created", "from_hash": null, "to_hash": "878b50d02339acb7"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: "1.1"
|
|
3
|
+
repo: "ecoportal-api-graphql"
|
|
4
|
+
doc: compliance
|
|
5
|
+
last_generated: "2026-07-09"
|
|
6
|
+
source_head: "3f7b877"
|
|
7
|
+
review_status: draft # audit answers MUST come from 'reviewed' docs only -- a human sets this
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Compliance -- ecoportal-api-graphql
|
|
11
|
+
|
|
12
|
+
**Purpose:** the audit / privacy / ISO-27001 surface for this project. It lets ROVO (over the EP Projects
|
|
13
|
+
Register) answer compliance questions across the fleet. **Trust rule:** everything here separates
|
|
14
|
+
EVIDENCE (a fact or link) from INTENT (planned); a reviewer must set `review_status: reviewed` before an
|
|
15
|
+
answer built on this doc is used for audit or re-certification -- a confident answer on unreviewed content
|
|
16
|
+
would mislead an auditor.
|
|
17
|
+
|
|
18
|
+
> This document is DRAFT and was composed from the repo's own context (CLAUDE.md, the
|
|
19
|
+
> `.ai-assistance/code/` specs, and the active project INTENT). Fields marked PLANNED or "human to
|
|
20
|
+
> confirm" MUST be verified by the repo owner before any audit use.
|
|
21
|
+
|
|
22
|
+
## ISO 27001
|
|
23
|
+
|
|
24
|
+
This is a Ruby client library (a gem), not a hosted service; it holds no infrastructure of its own and
|
|
25
|
+
introduces no independent ISO-27001 control surface. Its compliance posture is inherited from (a) the
|
|
26
|
+
ecoPortal platform it authenticates against and (b) the consuming project's runtime environment. The
|
|
27
|
+
control this repo DOES own is access-scoping of the automation that uses it.
|
|
28
|
+
|
|
29
|
+
| Control area | Status (evidence / planned) | Evidence link |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| Access control / least privilege (A.9) | EVIDENCE: the template-automation work is required to run under a per-org SERVICE ACCOUNT scoped to templates/org-config only, with page records structurally out of scope by credential grant (ep-ai-standards `security/ai-service-account-scope`). | `.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md`; `security/ai-service-account-scope` standard |
|
|
32
|
+
| Change control (A.12.1) | EVIDENCE: no silent breaking changes -- public-interface changes are recorded in the active project's DECISIONS log and confirmed with the developer; semver + CHANGELOG. | `CLAUDE.md`; `CHANGELOG.md` |
|
|
33
|
+
| Input validation (A.14.2) | EVIDENCE: `no_schema: true` disables build-time schema validation; the compensating control is a query validator now covering mutations. | `.ai-assistance/code/` (query validator); `ARCHITECTURE.md` |
|
|
34
|
+
| Auditability of automated changes | PLANNED / human to confirm: template BUILD/diff emits an ordered `WorkflowCommand` batch and a pairing ledger; whether that stream is retained as an audit trail for re-certification needs owner confirmation. | `.ai-assistance/code/diff_pairing_engine.md` |
|
|
35
|
+
|
|
36
|
+
## Data handled
|
|
37
|
+
|
|
38
|
+
The gem can read and write live ecoPortal domain objects through the API. Data classification is by
|
|
39
|
+
CAPABILITY (what the client can touch), then narrowed by the credential scope in use at runtime.
|
|
40
|
+
|
|
41
|
+
| Data class (none/team/customer/PII) | What / where | Treatment + retention | Exposed? (how) |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| Customer data + PII | Page records read/written via the GraphQL API (can contain personal data). | In-memory only during a client session; the gem persists nothing itself. Retention lives in the ecoPortal platform, not here. | Not exposed by the gem beyond the authenticated API call. Read/write capability is gated by the runtime credential; template-automation deliberately excludes page records by service-account scope. |
|
|
44
|
+
| Customer/org config (non-PII) | Templates, location structures, org configuration. | In-memory during a session; changes applied via `WorkflowCommand` batches. Retention in the platform. | Only via the authenticated API; this is the scope the template-automation service account is limited to. |
|
|
45
|
+
| Team-only | `.env` credentials for live tests (`ANTHROPIC_API_KEY`, ecoPortal creds via dotenv). | Local `.env`, gitignored; loaded only for `--tag live` specs. | Not committed; not exposed. |
|
|
46
|
+
|
|
47
|
+
## Third-party vendors in the data path
|
|
48
|
+
|
|
49
|
+
| Vendor | What data | Disclosed to end users? | Notes |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| Anthropic (Claude) | Only for `--tag live` AI tests, gated by `ANTHROPIC_API_KEY`. No customer page data is sent as part of normal gem operation. | N/A -- development-time only, not a production data path. | Live AI tests are opt-in; the gem's runtime API client does not call any LLM. Human to confirm no PII appears in live-test fixtures. |
|
|
52
|
+
|
|
53
|
+
No customer/PII data leaves the ecoPortal boundary through this gem in normal operation: it is a client
|
|
54
|
+
for ecoPortal's own API, not a bridge to an external SaaS.
|
|
55
|
+
|
|
56
|
+
## PII / data-leak controls
|
|
57
|
+
|
|
58
|
+
- **Credential scope (primary control):** the template-automation service account is scoped to
|
|
59
|
+
templates/org-config only, so page records (customer data + PII) are out of reach by GRANT, not by
|
|
60
|
+
instruction (ep-ai-standards `security/ai-service-account-scope`). This is the load-bearing leak
|
|
61
|
+
control.
|
|
62
|
+
- **`org_id` scoping:** every client session is bound to a single org context; cross-org reads require
|
|
63
|
+
distinct credentials.
|
|
64
|
+
- **No local persistence:** the gem holds data in memory for the session and writes nothing to disk;
|
|
65
|
+
there is no cache or log of customer records to leak.
|
|
66
|
+
- **`.env` gitignored:** credentials for live tests never enter version control.
|
|
67
|
+
- **Query validator:** compensates for `no_schema: true` by catching malformed queries/mutations before
|
|
68
|
+
they hit the live API.
|
|
69
|
+
|
|
70
|
+
## AI-generated content
|
|
71
|
+
|
|
72
|
+
- Externally-exposed AI content: **no.** The gem produces no customer-facing or publicly-exposed AI
|
|
73
|
+
content. AI assistance is confined to development (code generation, template-automation planning) and
|
|
74
|
+
`--tag live` AI tests; its output is reviewed code and internal artefacts, not exposed to end users.
|
|
75
|
+
- Marked as AI-generated: **N/A** for external content. Internally, AI-assisted commits follow the
|
|
76
|
+
developer-only authorship convention (no `Co-Authored-By` unless requested), and Gemini responses must
|
|
77
|
+
be verified against actual code before applying.
|
|
78
|
+
- Review process: standard MR review; public-interface changes additionally logged in the active
|
|
79
|
+
project's DECISIONS log and confirmed with the developer.
|
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
---
|
|
2
|
-
schema_version: "1.
|
|
2
|
+
schema_version: "1.1"
|
|
3
3
|
repo: "ecoportal-api-graphql"
|
|
4
4
|
doc: integrations
|
|
5
|
-
last_generated: "2026-07-
|
|
6
|
-
source_head: "
|
|
5
|
+
last_generated: "2026-07-09"
|
|
6
|
+
source_head: "3f7b877"
|
|
7
7
|
review_status: draft
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Integrations -- ecoportal-api-graphql
|
|
11
11
|
|
|
12
12
|
**Purpose:** the ties this project has to other systems and repos. This is the section the central
|
|
13
|
-
hub uses to trace inter-project dependencies and surface reuse (ADR-015 Section 5).
|
|
13
|
+
hub uses to trace inter-project dependencies and surface reuse (ADR-015 Section 5). It records, per
|
|
14
|
+
tie, the DATA that flows and the PERMISSIONS required -- feeding the compliance (vendor/PII) and the
|
|
15
|
+
cross-project-permissions questions. Detailed data-handling lives in `COMPLIANCE.md`.
|
|
14
16
|
|
|
15
17
|
## External services
|
|
16
18
|
|
|
17
|
-
| Service | Purpose |
|
|
18
|
-
|
|
19
|
-
| ecoPortal GraphQL API | The API this gem is a client for -- reads/writes pages, templates, location structures, contractor entities, actions, organizations. |
|
|
20
|
-
| ecoPortal REST API (v2) | Underlying REST infrastructure the GraphQL layer builds on and stays compatible with via the `Compat` layer. |
|
|
19
|
+
| Service | Purpose | Data sent (class + PII?) | Auth / permissions (scopes) |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| ecoPortal GraphQL API | The API this gem is a client for -- reads/writes pages, templates, location structures, contractor entities, actions, organizations. | Customer data + PII: page records can contain personal data. Also template/org-config data (non-PII). The gem is a full-access client by capability; the active template-automation work restricts itself to templates/org-config only by SERVICE-ACCOUNT grant. | OAuth via `Common::GraphQL::AuthService`, scoped by `org_id`; per-environment host (e.g. live.ecoportal.com). `no_schema: true` (no introspection). Credential scope is the load-bearing control -- see COMPLIANCE.md. |
|
|
22
|
+
| ecoPortal REST API (v2) | Underlying REST infrastructure the GraphQL layer builds on and stays compatible with via the `Compat` layer. | Same classes as above (indirect, via `ecoportal-api-v2`). | Same OAuth / org-scoped runtime credentials; provided through the upstream `ecoportal-api-v2` gem. |
|
|
21
23
|
|
|
22
24
|
## Upstream dependencies (repos we depend on)
|
|
23
25
|
|
|
24
|
-
| Repo / package | What we use it for |
|
|
25
|
-
|
|
26
|
-
| `ecoportal-api` | REST API base: auth, org context, base models, and the `Ecoportal::API::Common` namespace this gem extends. Team-managed. |
|
|
27
|
-
| `ecoportal-api-v2` | REST API v2 layer (Page, Register, etc.); required by the entry point. Team-managed. Being retired over time. |
|
|
28
|
-
| `graphlient` | Friendly GraphQL DSL/client wrapper; `Common::GraphQL::Client` inherits from `Graphlient::Client`. Active fork owned by the team (upstream: `ashkan18/graphlient`). |
|
|
29
|
-
| `graphql-client` | Low-level GraphQL HTTP + parsing, pulled in transitively via graphlient. Fork for upstream contribution only (upstream: `github-community-projects/graphql-client`); not team-maintained. |
|
|
30
|
-
| `graphql` (graphql-ruby) | Schema definition/execution engine (`rmosolgo/graphql-ruby`); external, read-only reference. Used server-side by ecoPortal; client-side usage here is indirect. |
|
|
26
|
+
| Repo / package | What we use it for | Permission/scope required (if any) |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `ecoportal-api` | REST API base: auth, org context, base models, and the `Ecoportal::API::Common` namespace this gem extends. Team-managed. | None beyond the runtime ecoPortal API credentials (email/pass/org_id/host) passed at instantiation. |
|
|
29
|
+
| `ecoportal-api-v2` | REST API v2 layer (Page, Register, etc.); required by the entry point. Team-managed. Being retired over time. | Same runtime ecoPortal API credentials. |
|
|
30
|
+
| `graphlient` | Friendly GraphQL DSL/client wrapper; `Common::GraphQL::Client` inherits from `Graphlient::Client`. Active fork owned by the team (upstream: `ashkan18/graphlient`). | None (library dependency). |
|
|
31
|
+
| `graphql-client` | Low-level GraphQL HTTP + parsing, pulled in transitively via graphlient. Fork for upstream contribution only (upstream: `github-community-projects/graphql-client`); not team-maintained. | None (library dependency). |
|
|
32
|
+
| `graphql` (graphql-ruby) | Schema definition/execution engine (`rmosolgo/graphql-ruby`); external, read-only reference. Used server-side by ecoPortal; client-side usage here is indirect. | None (library dependency). |
|
|
31
33
|
|
|
32
34
|
## Downstream consumers (who depends on us)
|
|
33
35
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: "1.1"
|
|
3
|
+
repo: "ecoportal-api-graphql"
|
|
4
|
+
doc: operations
|
|
5
|
+
last_generated: "2026-07-09"
|
|
6
|
+
source_head: "3f7b877"
|
|
7
|
+
review_status: draft
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Operations -- ecoportal-api-graphql
|
|
11
|
+
|
|
12
|
+
**Purpose:** the infrastructure / exposure / value surface for DevOps and Engineering. It lets ROVO answer
|
|
13
|
+
"what infrastructure is involved, is it behind Cloudflare, what governs its flows, and is it worth it?"
|
|
14
|
+
Same trust rule as COMPLIANCE.md: separate EVIDENCE from INTENT; audit answers use `reviewed` docs only.
|
|
15
|
+
|
|
16
|
+
> This document is DRAFT and composed from the repo's own context. It is a client LIBRARY (a gem): it has
|
|
17
|
+
> no infrastructure or public exposure of its own. Value/KPI figures below are unmeasured placeholders for
|
|
18
|
+
> the repo owner to fill; do not cite them as measured until reviewed.
|
|
19
|
+
|
|
20
|
+
## Infrastructure inventory
|
|
21
|
+
|
|
22
|
+
This project is a Ruby gem distributed as source/package -- it runs INSIDE whatever process requires it
|
|
23
|
+
(e.g. an `eco-helpers` integration script). It owns no compute, storage, or queue of its own.
|
|
24
|
+
|
|
25
|
+
| Component | Type (compute/store/queue/...) | Where hosted | Notes |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| The gem itself | library (no runtime infra) | Consumer's process / developer machine / CI | No servers, no data stores; loaded via Bundler into a host process. |
|
|
28
|
+
| ecoPortal GraphQL API | external service (dependency) | ecoPortal platform, per-environment host (e.g. live.ecoportal.com) | The gem is a CLIENT of this; the API's infrastructure is owned by the platform, not this repo. |
|
|
29
|
+
| RubyGems / Bundler | package distribution | RubyGems (or team gem source) | Distribution channel for the gem. |
|
|
30
|
+
|
|
31
|
+
## Public exposure
|
|
32
|
+
|
|
33
|
+
**Nothing in this repo is publicly exposed.** It is a client library with no listening endpoint, no
|
|
34
|
+
domain, and no inbound surface. It makes OUTBOUND authenticated calls to the ecoPortal GraphQL API; the
|
|
35
|
+
public-exposure and Cloudflare/WAF posture of that API belongs to the ecoPortal platform's own OPERATIONS
|
|
36
|
+
doc, not to this gem.
|
|
37
|
+
|
|
38
|
+
| Public domain / endpoint | Behind Cloudflare? | Security rules governing the flow |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| (none -- library, no inbound surface) | N/A | Outbound only: OAuth-authenticated, `org_id`-scoped calls to the ecoPortal GraphQL API over HTTPS. |
|
|
41
|
+
|
|
42
|
+
## DevOps audit runbook
|
|
43
|
+
|
|
44
|
+
How to check/verify this project autonomously:
|
|
45
|
+
|
|
46
|
+
- **Build / install:** `bundle install`; gem spec is `ecoportal-api-graphql.gemspec`; version constant
|
|
47
|
+
`Ecoportal::API::GRAPQL_VERSION`.
|
|
48
|
+
- **Tests:** `bundle exec rspec` for the unit suite; `bundle exec rspec --tag live` for live-API/AI tests
|
|
49
|
+
(requires `.env` with `ANTHROPIC_API_KEY` and ecoPortal credentials, loaded via dotenv).
|
|
50
|
+
- **Lint:** `bundle exec rubocop <file>` -- rubocop compliance is required for all generated Ruby
|
|
51
|
+
(config in `.rubocop.yml`).
|
|
52
|
+
- **CI:** no CI config file was detected at the repo root by the scanner (`ci_files: []`). Human to
|
|
53
|
+
confirm whether CI runs elsewhere (e.g. a GitLab CI defined outside the root) or is absent.
|
|
54
|
+
- **Version / release check:** `CHANGELOG.md` is authoritative; releases follow
|
|
55
|
+
`chore(release): vX.Y.Z`. Recent releases raised the `ecoportal-api-v2` floor to fix version-drift
|
|
56
|
+
crashes -- verify the dependency floors in the gemspec match the CHANGELOG.
|
|
57
|
+
- **Deeper docs:** `.ai-assistance/code/` (code-specs, dependency map, diff/build engine, schema
|
|
58
|
+
analysis) is the detailed runbook for engineers; `.ai-assistance/code/ecoPortal_architecture/` is the
|
|
59
|
+
verified platform knowledge base.
|
|
60
|
+
|
|
61
|
+
## Value & KPIs
|
|
62
|
+
|
|
63
|
+
No usage KPIs are instrumented in this repo today. The value narrative below is qualitative /
|
|
64
|
+
estimated; the repo owner should replace estimates with measured figures (or a dashboard link) before
|
|
65
|
+
these are treated as evidence.
|
|
66
|
+
|
|
67
|
+
| Metric | Value (measured/estimated) | Source / dashboard |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Templates targeted for programmatic build/maintenance | ~300+ (estimated, project scope) | `.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md` |
|
|
70
|
+
| Hours saved / delivery-speed gain | Not measured | -- (owner to instrument) |
|
|
71
|
+
| Active monitoring | None in-repo; staleness of these self-docs is detectable via `source_head` vs git head | `self-docs-index.json` |
|
|
72
|
+
| Cost-vs-return | Not measured | -- (owner to instrument) |
|
|
73
|
+
|
|
74
|
+
**Coverage-on-neglect:** these self-docs carry a `source_head` and a per-doc `content_hash` in
|
|
75
|
+
`self-docs-index.json`, so the hub and `project-review` can flag them stale rather than silently trusting
|
|
76
|
+
them.
|