ecoportal-api-graphql 1.3.13 → 1.3.16
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/CHANGELOG.md +87 -0
- data/lib/ecoportal/api/common/graphql/client.rb +0 -2
- data/lib/ecoportal/api/common/graphql/http_client.rb +6 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -17
- data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
- data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
- data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
- data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
- data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page.rb +17 -16
- data/lib/ecoportal/api/graphql/base/template.rb +35 -0
- data/lib/ecoportal/api/graphql/base.rb +37 -35
- data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -35
- data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection.rb +17 -17
- data/lib/ecoportal/api/graphql/file_upload/client.rb +21 -10
- data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
- data/lib/ecoportal/api/graphql/fragment/force.rb +14 -10
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
- data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
- data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
- data/lib/ecoportal/api/graphql/fragment.rb +3 -0
- data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -16
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -21
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -28
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -23
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -24
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -251
- data/lib/ecoportal/api/graphql/input.rb +24 -24
- data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
- data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
- data/lib/ecoportal/api/graphql/model/page.rb +16 -15
- data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
- data/lib/ecoportal/api/graphql/model/template.rb +15 -0
- data/lib/ecoportal/api/graphql/model.rb +32 -30
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -45
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +7 -7
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +8 -7
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -35
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -35
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -36
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -13
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -46
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation.rb +20 -20
- data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -21
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +20 -19
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/register.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/payload.rb +23 -23
- data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
- data/lib/ecoportal/api/graphql/query/page.rb +45 -45
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +9 -3
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +9 -3
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -78
- data/lib/ecoportal/api/graphql/query.rb +27 -27
- data/lib/ecoportal/api/graphql.rb +9 -5
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- metadata +9 -180
- data/.ai-assistance/bridge/CLAUDE.md +0 -338
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +0 -29
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +0 -18
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +0 -42
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +0 -115
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +0 -48
- data/.ai-assistance/bridge/context/gemini-review-response.md +0 -104
- data/.ai-assistance/bridge/context/project.md +0 -42
- data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +0 -48
- data/.ai-assistance/bridge/queue/.gitkeep +0 -1
- data/.ai-assistance/capabilities/CLAUDE.md +0 -27
- data/.ai-assistance/capabilities/assumptions-log.md +0 -80
- data/.ai-assistance/capabilities/code.md +0 -47
- data/.ai-assistance/capabilities/connectors.md +0 -37
- data/.ai-assistance/capabilities/cowork.md +0 -55
- data/.ai-assistance/code/OVERVIEW.md +0 -155
- data/.ai-assistance/code/data_fields.md +0 -242
- data/.ai-assistance/code/dependencies.md +0 -151
- data/.ai-assistance/code/diff_as_input.md +0 -234
- data/.ai-assistance/code/diff_pairing_engine.md +0 -243
- data/.ai-assistance/code/diff_service_deep_dive.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +0 -55
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +0 -181
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +0 -147
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +0 -277
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +0 -200
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +0 -228
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +0 -197
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +0 -243
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +0 -196
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +0 -132
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +0 -187
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +0 -236
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +0 -183
- data/.ai-assistance/code/ecoportal_schema_reference.md +0 -240
- data/.ai-assistance/code/filter_contract_matrix.md +0 -177
- data/.ai-assistance/code/graphql_domain_knowledge.md +0 -240
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +0 -71
- data/.ai-assistance/code/refactoring/opportunities.md +0 -251
- data/.ai-assistance/code/schema_analysis.md +0 -321
- data/.ai-assistance/code/search_filters.md +0 -868
- data/.ai-assistance/code/spec_coverage.md +0 -73
- data/.ai-assistance/code/template_diff_pairing_domain.md +0 -175
- data/.ai-assistance/code/workflow-command-guide.md +0 -466
- data/.ai-assistance/code/workflow-space.md +0 -353
- data/.ai-assistance/conventions/CLAUDE.md +0 -30
- data/.ai-assistance/conventions/code-working-tree-protocol.md +0 -199
- data/.ai-assistance/conventions/gitignore-rules.md +0 -42
- data/.ai-assistance/conventions/permission-guidance.md +0 -120
- data/.ai-assistance/integrations/README.md +0 -70
- data/.ai-assistance/integrations/gitkraken-mcp.md +0 -107
- data/.ai-assistance/integrations/gitlab-mcp.md +0 -123
- data/.ai-assistance/integrations/local-git.md +0 -60
- data/.ai-assistance/local_paths.example.md +0 -17
- data/.ai-assistance/projects/TODO.md +0 -118
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +0 -168
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +0 -60
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +0 -267
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +0 -53
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +0 -102
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +0 -139
- data/.ai-assistance/projects/compat-layer-audit/COMPAT_AUDIT.md +0 -244
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +0 -93
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +0 -244
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +0 -266
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +0 -86
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +0 -101
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +0 -177
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +0 -161
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +0 -125
- data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +0 -136
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +0 -126
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +0 -261
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +0 -122
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +0 -148
- data/.ai-assistance/projects/page-model/DECISIONS.md +0 -245
- data/.ai-assistance/projects/page-model/TODO.md +0 -190
- data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +0 -93
- data/.ai-assistance/projects/qa-services-delivery/INTENT.md +0 -76
- data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +0 -115
- data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +0 -99
- data/.ai-assistance/projects/qa-services-delivery/TODO.md +0 -81
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +0 -107
- data/.ai-assistance/projects/search-filter-builder/TODO.md +0 -131
- data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +0 -87
- data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +0 -108
- data/.ai-assistance/projects/template-diff-deploy/INTENT.md +0 -12
- data/.ai-assistance/projects/template-diff-deploy/TODO.md +0 -9
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +0 -134
- data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +0 -93
- data/.ai-assistance/projects/template-maintenance/README.md +0 -14
- data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +0 -236
- data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +0 -243
- data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +0 -154
- data/.ai-assistance/projects/workflow-space/TODO.md +0 -213
- data/.ai-assistance/reinstall-claude-desktop-windows.md +0 -136
- data/.ai-assistance/scripts/CLAUDE.md +0 -150
- data/.ai-assistance/scripts/bridge-inbox-check.sh +0 -75
- data/.ai-assistance/scripts/bridge-init.sh +0 -86
- data/.ai-assistance/scripts/bridge-status.sh +0 -44
- data/.ai-assistance/scripts/capabilities-check.ts +0 -104
- data/.ai-assistance/scripts/check-outbox.sh +0 -43
- data/.ai-assistance/scripts/dep_graph.rb +0 -91
- data/.ai-assistance/scripts/lock-acquire.sh +0 -103
- data/.ai-assistance/scripts/lock-multi.sh +0 -124
- data/.ai-assistance/scripts/lock-queue.sh +0 -94
- data/.ai-assistance/scripts/setup-mcps.test.ts +0 -188
- data/.ai-assistance/scripts/setup-mcps.ts +0 -234
- data/.ai-assistance/scripts/task-complete.ts +0 -74
- data/.ai-assistance/scripts/task-create.ts +0 -75
- data/.ai-assistance/scripts/task-read.ts +0 -125
- data/.ai-assistance/scripts/token-logger.js +0 -220
- data/.ai-assistance/scripts/token-report.ts +0 -158
- data/.ai-assistance/scripts/token-session-start.js +0 -66
- data/.ai-assistance/skills/ai-instructions/SKILL.md +0 -48
- data/.ai-assistance/skills/code-specs/SKILL.md +0 -69
- data/.ai-assistance/skills/corporate-policies/SKILL.md +0 -201
- data/.ai-assistance/skills/dep-graph/SKILL.md +0 -139
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +0 -417
- data/.ai-assistance/skills/gemini-assist/SKILL.md +0 -63
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +0 -205
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +0 -1
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +0 -240
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +0 -25
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +0 -261
- data/.ai-assistance/skills/procedural-memory/SKILL.md +0 -319
- data/.ai-assistance/skills/project-cycle/SKILL.md +0 -177
- data/.ai-assistance/skills/project-self-docs/SKILL.md +0 -181
- data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +0 -378
- data/.ai-assistance/skills/refactor/SKILL.md +0 -62
- data/.ai-assistance/skills/rubocop/SKILL.md +0 -93
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +0 -215
- data/.ai-assistance/skills/spec-generation/SKILL.md +0 -72
- data/.ai-assistance/standards-version.json +0 -22
- data/.ai-assistance/token-budget.json +0 -32
- data/.ai-assistance/version.json +0 -39
- data/.claude/settings.json +0 -150
- data/.env.example +0 -18
- data/.gitattributes +0 -15
- data/.gitignore +0 -37
- data/.gitlab-ci.yml +0 -45
- data/.markdownlint.json +0 -4
- data/.rspec +0 -3
- data/.rubocop.yml +0 -121
- data/.ruby-version +0 -1
- data/.yardopts +0 -10
- data/CLAUDE.md +0 -243
- data/Gemfile +0 -30
- data/Rakefile +0 -90
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/setup.ps1 +0 -6
- data/docs/self-docs/ARCHITECTURE.md +0 -88
- data/docs/self-docs/CHANGES.jsonl +0 -12
- data/docs/self-docs/COMPLIANCE.md +0 -79
- data/docs/self-docs/CONVENTIONS.md +0 -74
- data/docs/self-docs/INTEGRATIONS.md +0 -65
- data/docs/self-docs/OPERATIONS.md +0 -76
- data/docs/self-docs/OVERVIEW.md +0 -64
- data/docs/self-docs/STATUS.md +0 -73
- data/docs/self-docs/self-docs-index.json +0 -51
- data/docs/worklog.md +0 -977
- data/ecoportal-api-graphql.gemspec +0 -40
- data/scripts/auto-worker-scheduler.sh +0 -386
- data/tests/actions_get.rb +0 -7
- data/tests/contractor_entities_get.rb +0 -20
- data/tests/contractor_entity_create.rb +0 -19
- data/tests/contractor_entity_udpate.rb +0 -20
- data/tests/dump_page_model.rb +0 -74
- data/tests/dump_template_model.rb +0 -90
- data/tests/loc_structure_get.rb +0 -10
- data/tests/loc_structure_update.rb +0 -51
- data/tests/loc_structures_get.rb +0 -15
- data/tests/local_libs.rb +0 -20
- data/tests/validate_queries.rb +0 -127
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Decisions — QA-as-CI/CD (ecoportal-qa)
|
|
2
|
-
|
|
3
|
-
Append per decision; never delete — history matters.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## [2026-07-02] Standalone repo, governed by ep-ai-standards (not built inside it)
|
|
8
|
-
|
|
9
|
-
**Context:** Oscar was unsure whether ep-ai-standards tooling should live in its own repo or inside
|
|
10
|
-
ep-ai-standards, noting it "shouldn't matter as long as results don't clash and ep-ai-standards can
|
|
11
|
-
pick it up and ensure continuity."
|
|
12
|
-
|
|
13
|
-
**Decision:** **Standards & governance live in ep-ai-standards; implementations live where their
|
|
14
|
-
dependencies live.** `ecoportal-qa` depends on the GraphQL gem → its own repo. It carries a
|
|
15
|
-
`.ai-assistance/` **conformance declaration** (`conformance.json` + `CLAUDE.md`) so ep-ai-standards
|
|
16
|
-
can discover, index, and govern it without owning the code.
|
|
17
|
-
|
|
18
|
-
**Reason:** Makes "location doesn't matter" true *by construction*: continuity via the declaration,
|
|
19
|
-
no clash via shared conventions. Keeps the governance repo lean and each tool independently testable.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## [2026-07-02] A QA "pseudo-language" (declarative DSL) → compiler → jobs
|
|
24
|
-
|
|
25
|
-
**Decision:** QA authors declarative **check-sets** in a small YAML DSL (front-end). A Ruby
|
|
26
|
-
**compiler** turns them into runnable Check objects (IR), and later into CI-job / auto-approve
|
|
27
|
-
backends.
|
|
28
|
-
|
|
29
|
-
**Reason:** Delegation surface for QA (no Ruby needed); front-end/back-end split insulates QA
|
|
30
|
-
templates from the volatile WorkflowCommand/GraphQL API. Proven pattern (Great Expectations,
|
|
31
|
-
Gherkin, policy-as-code, CI-as-code).
|
|
32
|
-
|
|
33
|
-
**Consequences:** The DSL schema is a public contract to keep stable; compiler backends can churn.
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## [2026-07-02] Read-only, canonical-JSON result, honest skips
|
|
38
|
-
|
|
39
|
-
**Decision:** The runner is **read-only** end to end. Every run emits one **canonical Result JSON**
|
|
40
|
-
(ticket · target · verdict · per-check outcome) that all reporting derives from and that is the audit
|
|
41
|
-
record. Checks that can't be evaluated (e.g. a `required` flag not captured in a snapshot) return
|
|
42
|
-
**`:skip`**, never a false pass; verdict distinguishes `passed` / `passed_with_gaps` / `changes_requested`.
|
|
43
|
-
|
|
44
|
-
**Reason:** Safety/privacy (no writes), governance (auditability), and trustworthy results (a skip is
|
|
45
|
-
not a pass) are the stated decision drivers.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## [2026-07-02] Jira phased; human-in-the-loop; auto-approve last & opt-in
|
|
50
|
-
|
|
51
|
-
**Decision:** Phase Jira integration: **read + post results + human-gated transition first**; the
|
|
52
|
-
**auto-approve hook is built last, opt-in, and QA-owned** (off by default). Jira is the
|
|
53
|
-
ticket-management workflow layer, not the check engine.
|
|
54
|
-
|
|
55
|
-
**Reason:** Services & Delivery is a human team; agents assist, not replace. Governance/human gate are
|
|
56
|
-
non-negotiable. Lowest-risk capability (read-only + report) delivers value before any transition logic.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## [2026-07-02] Ruby core, no runtime deps in the core
|
|
61
|
-
|
|
62
|
-
**Decision:** Core (DSL/compiler/runner/reporters) has **no runtime gem dependencies** — it operates
|
|
63
|
-
on a page/template doc Hash. `Source::GraphqlSource` lazily requires `ecoportal-api-graphql` only when
|
|
64
|
-
run against a live org.
|
|
65
|
-
|
|
66
|
-
**Reason:** Ruby for team resourcing redundancy; a dependency-free core stays offline-runnable and
|
|
67
|
-
trivially testable (specs run against a captured snapshot), and keeps CI fast.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## [2026-07-03] PROPOSED — Jira adapter: interface + REST first, MCP later (pending Oscar)
|
|
72
|
-
|
|
73
|
-
**Context:** Phase 3 posts results to Jira. Two ways in: the Atlassian MCP (no secrets, but may be
|
|
74
|
-
absent in headless/CI runs) vs Jira REST (needs a managed service-account token, but works everywhere).
|
|
75
|
-
|
|
76
|
-
**Proposed decision:** define a `Jira::Client` interface and implement **`RestClient` first**; add
|
|
77
|
-
`McpClient` later as an interactive convenience. The endgame is Phase 4 CI ("ticket as pipeline"),
|
|
78
|
-
where MCP likely isn't available — REST is the durable path and won't need redoing. The interface
|
|
79
|
-
makes it a drop-in choice, not a fork. **Not yet ratified** — awaiting Oscar's answers on the target
|
|
80
|
-
Jira project, workflow statuses, and whether a service-account token is available (see PHASE3-SCOPE.md).
|
|
81
|
-
|
|
82
|
-
**Reason:** avoid building a channel that can't run where the destination (CI) lives.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## [2026-07-03] Phase 3 does NOT auto-transition (reaffirms human-in-the-loop)
|
|
87
|
-
|
|
88
|
-
**Decision:** the Jira adapter's default is **report-only** (post a redacted, idempotent result
|
|
89
|
-
comment); a status transition happens **only** when a human explicitly names one (`--transition`).
|
|
90
|
-
Auto-approve stays out of scope until Phase 5 (opt-in + governed + audited).
|
|
91
|
-
|
|
92
|
-
**Reason:** the human gate is non-negotiable; posting a result is useful on its own and carries no
|
|
93
|
-
risk, so it ships first while transition automation waits for the governed Phase 5 design.
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Project: QA-as-CI/CD for Services Delivery (ecoportal-qa)
|
|
2
|
-
|
|
3
|
-
**Created:** 2026-07-02
|
|
4
|
-
**Status:** active — Phase 1 prototype built
|
|
5
|
-
**Primary repo:** `ecoportal-qa` (`C:\ruby_scripts\git\ecoportal-qa`) — NEW standalone Ruby tool
|
|
6
|
-
**Reads via:** `ecoportal-api-graphql` (the GraphQL client gem)
|
|
7
|
-
**Governed by:** `ep-ai-standards` (conformance declared in `ecoportal-qa/.ai-assistance/`)
|
|
8
|
-
|
|
9
|
-
> **Why the plan lives here:** `ecoportal-qa` is the implementation repo; the team's project-cycle
|
|
10
|
-
> docs live in `ecoportal-api-graphql/.ai-assistance/projects/` (same pattern as the ooze migration).
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Problem
|
|
15
|
-
|
|
16
|
-
The QA team in **Services Delivery** reviews **org configuration & template changes** against Jira
|
|
17
|
-
tickets before sign-off. Today this is manual and slow. They want to (a) quickly see *what has been
|
|
18
|
-
done*, (b) author repeatable **automated checks** that save review time, and (c) eventually gate
|
|
19
|
-
Jira ticket transitions on those checks — with **humans always in the loop** (this is a Services &
|
|
20
|
-
Delivery team; agents/AI assist, they don't replace people).
|
|
21
|
-
|
|
22
|
-
## Vision — "QA-as-CI/CD"
|
|
23
|
-
|
|
24
|
-
QA authors checks once, in a friendly declarative language; a Ruby compiler turns them into runnable
|
|
25
|
-
jobs; results flow to reporting + Jira; humans gate the transitions.
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
QA template (YAML DSL) → Compiler (Ruby) → runnable Checks → Runner (read-only) → Result (JSON)
|
|
29
|
-
▲ what QA writes ▲ front-end→IR ▲ vs live/captured template ▲ reporting · Jira · monitoring
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Classic compiler split: QA owns a **stable front-end language**; the compiler emits **volatile
|
|
33
|
-
back-end job code**. That insulation matters — the underlying WorkflowCommand/GraphQL API is volatile,
|
|
34
|
-
and QA templates must not break when it shifts.
|
|
35
|
-
|
|
36
|
-
## Decision drivers (Oscar)
|
|
37
|
-
|
|
38
|
-
safety · privacy · simplicity · **delegation to the QA team** · monitoring · reporting · governance ·
|
|
39
|
-
Ruby (resourcing redundancy) · human-in-the-loop. Jira is *where the ticket-management workflow is
|
|
40
|
-
handled*, not where the engine runs.
|
|
41
|
-
|
|
42
|
-
## Scope
|
|
43
|
-
|
|
44
|
-
### In scope
|
|
45
|
-
- The **QA DSL** (declarative check-set: `meta.ticket/target` + `expect.stages→sections→fields`).
|
|
46
|
-
- A **compiler** (DSL → ordered, stateless Check objects / IR).
|
|
47
|
-
- A **runner** that verifies checks **read-only** against a live or captured template.
|
|
48
|
-
- A **canonical Result** (JSON) — the single source of truth for all reporting + the audit record.
|
|
49
|
-
- Sources: `FixtureSource` (offline JSON snapshot) + `GraphqlSource` (live, read-only, via the gem).
|
|
50
|
-
- Reporters: JSON (canonical) + Text now; CSV/HTML next.
|
|
51
|
-
- **ep-ai-standards conformance** stub so the tool is discoverable/governed without being owned.
|
|
52
|
-
|
|
53
|
-
### Out of scope (non-goals / later)
|
|
54
|
-
- **Writing** to orgs from the check path (read-only by design — safety/privacy).
|
|
55
|
-
- **Auto-approval** without a human — only ever an opt-in, QA-owned hook, built last.
|
|
56
|
-
- Building QA templates for every customer (that's QA's ongoing authoring, enabled by this tool).
|
|
57
|
-
- Replacing human QA judgement.
|
|
58
|
-
|
|
59
|
-
## Subject of review (confirmed)
|
|
60
|
-
**Org config & template changes** — templates/registers/workflows/fields/forces — sourced from the
|
|
61
|
-
GraphQL API. (A template IS a page, so structure reads via the page model.)
|
|
62
|
-
|
|
63
|
-
## Precedents (this pattern is proven)
|
|
64
|
-
- **Great Expectations** — declarative "expectations" → validation engine → results + data docs
|
|
65
|
-
(closest 1:1 analogy; "config/template expectations").
|
|
66
|
-
- **Gherkin/Cucumber** — a QA-writable language compiled to executable steps.
|
|
67
|
-
- **OPA / policy-as-code** — declarative rules → decisions + audit (governance model).
|
|
68
|
-
- **GitLab/GitHub CI-as-code** — YAML pipelines → jobs (the "ticket as pipeline" backend target).
|
|
69
|
-
|
|
70
|
-
## Success criteria
|
|
71
|
-
1. QA can author a check-set in YAML and get a green/red result against a real template with **zero
|
|
72
|
-
Ruby**. *(Phase 1 — DONE against the toocs snapshot.)*
|
|
73
|
-
2. Results are canonical JSON, auditable (ticket · target · verdict · per-check), and human-readable.
|
|
74
|
-
3. Read-only end to end; no PII leaks in results/logs.
|
|
75
|
-
4. Jira transitions are human-gated; auto-approve is opt-in and off by default.
|
|
76
|
-
5. The tool is discoverable/governed by ep-ai-standards via its conformance declaration.
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# Phase 3 — Jira adapter (human-gated) — SCOPE
|
|
2
|
-
|
|
3
|
-
**Status:** SCOPED (not built) — 2026-07-03. Building is blocked on two Oscar decisions (below).
|
|
4
|
-
**Repo:** `ecoportal-qa`. **Depends on:** Phase 1–2 (Runner + canonical Result + Reporters + Redactor).
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Goal
|
|
9
|
-
|
|
10
|
-
Connect the QA runner to **Jira** so a QA run is: (1) **traceable** to a ticket, (2) its result is
|
|
11
|
-
**posted back** to that ticket, and (3) a **human gates** any status change. Phase 3 does **not**
|
|
12
|
-
auto-transition — that is Phase 5, opt-in and governed. Jira is the *ticket-management workflow layer*;
|
|
13
|
-
the check engine stays exactly as built.
|
|
14
|
-
|
|
15
|
-
Non-goal (Phase 3): automatic transitions, running on a Jira webhook (that's Phase 4 CI), editing
|
|
16
|
-
ticket content beyond a result comment + an optional verdict field.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## The one idea that keeps this simple
|
|
21
|
-
|
|
22
|
-
Everything already funnels into **one canonical `Result`** (ticket · target · verdict · per-check).
|
|
23
|
-
The Jira adapter is **just another consumer of that Result** — exactly like the CSV/HTML reporters.
|
|
24
|
-
It never reaches into the runner or the checks. So Phase 3 adds a *channel*, not a *rewrite*.
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
Runner ─► Result ─┬─► Reporters (text/json/csv/html) [Phase 1–2]
|
|
28
|
-
└─► Jira::Publisher ─► Jira::Client ─► a ticket [Phase 3] ← new channel only
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Design
|
|
34
|
-
|
|
35
|
-
### Traceability (ticket ↔ check-set)
|
|
36
|
-
- The link is the check-set's `meta.ticket` (e.g. `SD-1234`). **Push model:** you run a check-set,
|
|
37
|
-
the adapter posts to the ticket named in its `meta`.
|
|
38
|
-
- A reverse index (ticket → check-set file) is derivable by scanning `qa/checks/` — deferred until we
|
|
39
|
-
know where check-sets live long-term (Open Q #4).
|
|
40
|
-
|
|
41
|
-
### Components (all new, in `ecoportal-qa`)
|
|
42
|
-
- **`Jira::Client`** — a thin interface: `find_issue(key)`, `add_comment(key, body)`,
|
|
43
|
-
`set_field(key, field, value)`, `available_transitions(key)`, `transition(key, name)`.
|
|
44
|
-
- **`Jira::RestClient`** — real implementation over Jira Cloud REST v3 (base URL + service-account
|
|
45
|
-
API token from ENV/secret store). *Recommended first implementation* (see decision below).
|
|
46
|
-
- **`Jira::McpClient`** — optional implementation over the Atlassian MCP (no secrets in our code).
|
|
47
|
-
- **`Jira::DryRunClient`** — records intended calls, performs none. The offline test double + the safe
|
|
48
|
-
default for `--dry-run`. (Same pattern as `Source::FixtureSource`.)
|
|
49
|
-
- **`Jira::Publisher`** — orchestrates: render the result (TextReporter for the comment, JSON/HTML as
|
|
50
|
-
attachment), **redact first** (Redactor), post the comment, optionally set a verdict field, and —
|
|
51
|
-
only when a human explicitly asks — offer/perform a transition.
|
|
52
|
-
|
|
53
|
-
### Human-in-the-loop transition model (the safety crux)
|
|
54
|
-
Phase 3 supports three modes, defaulting to the safest:
|
|
55
|
-
1. **`--dry-run`** (default in CI-less/interactive) — print what *would* be posted; touch nothing.
|
|
56
|
-
2. **report-only** — post the result comment (+ optional verdict field); **leave the transition to
|
|
57
|
-
the human in the Jira UI.** This is the recommended day-one mode.
|
|
58
|
-
3. **`--transition "<name>"`** — a person runs this explicitly after reading the result; the tool
|
|
59
|
-
performs that one named transition. The tool NEVER picks/performs a transition on its own.
|
|
60
|
-
|
|
61
|
-
### Governance / safety
|
|
62
|
-
- **Redact before posting** (comments can be widely visible) — reuse the Phase-2 Redactor.
|
|
63
|
-
- **Secrets**: REST token from ENV/secret store, scoped to comment + transition on the target project
|
|
64
|
-
only; never committed. MCP path carries no secrets in our code.
|
|
65
|
-
- **Idempotency**: tag the comment with a hidden marker (`<!-- ecoportal-qa:run SD-1234 -->`) so a
|
|
66
|
-
re-run *updates* its previous comment instead of spamming the ticket.
|
|
67
|
-
- **Audit**: every Jira call appended to a run log (issue · action · verdict · timestamp · actor).
|
|
68
|
-
- **Least action**: the default does not transition; transitions are explicit, named, human-invoked.
|
|
69
|
-
|
|
70
|
-
### CLI surface (extends Phase 2)
|
|
71
|
-
```
|
|
72
|
-
ecoportal-qa report CHECKSET.qa.yml --source fixture:PATH|graphql:ID \
|
|
73
|
-
--jira [--jira-client rest|mcp|dry-run] [--transition "QA Approved"] [--redact] [--attach json,html]
|
|
74
|
-
```
|
|
75
|
-
- No `--jira` → behaves exactly like Phase 2 `run` (prints a report).
|
|
76
|
-
- `--jira` without `--transition` → report-only (comment + optional field).
|
|
77
|
-
- Exit code still encodes the verdict (CI-friendly).
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## Decision needed: Atlassian MCP vs Jira REST
|
|
82
|
-
|
|
83
|
-
| | Atlassian MCP | Jira REST API |
|
|
84
|
-
|---|---|---|
|
|
85
|
-
| Secrets in our code | none (session auth) | service-account token (managed) |
|
|
86
|
-
| Works in CI / headless | **uncertain** — interactive-auth MCP servers may be absent in headless/cron | **yes** |
|
|
87
|
-
| Setup speed (interactive) | fast | moderate |
|
|
88
|
-
| Control / stability | good, but tied to MCP availability | full, documented |
|
|
89
|
-
|
|
90
|
-
**Recommendation:** build the **`Jira::Client` interface + `RestClient` first**. Reason: the endgame
|
|
91
|
-
is Phase 4 CI ("ticket as pipeline"), where MCP likely isn't available; REST works everywhere, so it's
|
|
92
|
-
the durable path and doesn't have to be redone. Add `McpClient` later as an interactive convenience.
|
|
93
|
-
The interface makes this a drop-in choice, not a fork.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## Sub-phases (build order once unblocked)
|
|
98
|
-
- **3a** — `Jira::Client` interface + `Jira::DryRunClient` + `Jira::Publisher` (format/redact/idempotency).
|
|
99
|
-
**Fully offline-specable** (DryRunClient records calls) — same as Phase 1–2, no live Jira needed.
|
|
100
|
-
- **3b** — `Jira::RestClient` (config: base URL, token, project) + integration behind an env-gated spec.
|
|
101
|
-
- **3c** — CLI `report --jira …` wiring + audit log.
|
|
102
|
-
- **3d** — (optional) `Jira::McpClient`.
|
|
103
|
-
|
|
104
|
-
**Gate 3:** a QA run posts a redacted, idempotent result comment to a real ticket; transitions only
|
|
105
|
-
happen when a human names one. No auto-transition anywhere.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## Open questions (Oscar) — these block the build
|
|
110
|
-
1. **Which Jira project + workflow statuses?** Need the exact transition names QA uses
|
|
111
|
-
(e.g. `In QA → QA Approved` / `Changes Requested`).
|
|
112
|
-
2. **REST service-account + API token**, or start **MCP-only interactive**? (Drives 3b vs 3d order.)
|
|
113
|
-
3. **Verdict field**: a dedicated custom field, or comment-only for now?
|
|
114
|
-
4. **Where do check-sets live** long-term (repo `qa/checks/`, per-customer, shared config repo)? —
|
|
115
|
-
affects the reverse ticket→check-set index (deferred until answered).
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# ROADMAP — where ecoportal-qa is going, and how the pieces get us there
|
|
2
|
-
|
|
3
|
-
A narrative companion to INTENT/DECISIONS/TODO. Read this when you want the *why* and the *shape of
|
|
4
|
-
the journey*, not the task list.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## The destination (the "north star")
|
|
9
|
-
|
|
10
|
-
> QA in Services Delivery verifies org config & template changes **faster, consistently, and
|
|
11
|
-
> auditably** — and over time those checks run **as a human-gated pipeline on the Jira ticket**, so
|
|
12
|
-
> QA spends their attention on *judgement* (does this design meet the customer's intent?) instead of
|
|
13
|
-
> *mechanical checking* (is field X present, of type Y, in section Z?).
|
|
14
|
-
|
|
15
|
-
Two things stay true at every step: **the tool is read-only against orgs**, and **humans make the
|
|
16
|
-
decisions**. Agents/automation assist; they never approve on their own.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Why this shape — one Result, many channels
|
|
21
|
-
|
|
22
|
-
The whole design rests on a single idea: **every run produces one canonical `Result`** (ticket ·
|
|
23
|
-
target · verdict · per-check outcome). Everything else is a *consumer* of that Result.
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
what QA means turns intent verifies, the single
|
|
27
|
-
(declarative) into checks read-only source of truth
|
|
28
|
-
┌───────────────────┐ ┌──────────────┐ ┌───────────────┐ ┌────────────────────┐
|
|
29
|
-
│ QA template DSL │ ► │ Compiler │ ► │ Runner │ ► │ RESULT │
|
|
30
|
-
│ (.qa.yml) │ │ (front→IR) │ │ (live/fixture)│ │ (canonical JSON) │
|
|
31
|
-
└───────────────────┘ └──────────────┘ └───────────────┘ └─────────┬──────────┘
|
|
32
|
-
│
|
|
33
|
-
┌────────────────────────┬───────────────────┬──────────┴───────────┐
|
|
34
|
-
▼ ▼ ▼ ▼
|
|
35
|
-
Reporters Jira CI Monitoring
|
|
36
|
-
(text/json/csv/html) (comment + gate) (ticket-as-pipeline) (dashboards)
|
|
37
|
-
[P1–P2 ✅] [P3 ▶] [P4] [P4]
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Why this matters for "how we keep going":** adding Jira (P3), CI (P4), or auto-approve (P5) never
|
|
41
|
-
touches the DSL, compiler, or runner. Each new capability is *another consumer of the Result*. That's
|
|
42
|
-
what lets us extend without rework — and why the QA-facing language (the `.qa.yml`) can stay stable
|
|
43
|
-
even as the WorkflowCommand/GraphQL API underneath churns.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## The capability ladder — each rung is independently useful
|
|
48
|
-
|
|
49
|
-
Each phase delivers value **on its own**, even if we stopped there. That's deliberate: we're never
|
|
50
|
-
"halfway to something that works" — we're "fully at rung N, climbing to N+1."
|
|
51
|
-
|
|
52
|
-
| Rung | Capability | Value delivered on its own | Status |
|
|
53
|
-
|---|---|---|---|
|
|
54
|
-
| **P1** | **Author & run checks** | QA writes YAML, gets green/red on a real template — repeatable, no Ruby | ✅ done |
|
|
55
|
-
| **P2** | **Report & operate** | CSV/HTML/JSON reports, a CLI, PII redaction, rich checks, CI-ready exit codes | ✅ done |
|
|
56
|
-
| **P3** | **Connect to Jira** | Results land on the ticket QA already works in; human gates transitions | ▶ scoped |
|
|
57
|
-
| **P4** | **Automate the pipeline** | "Ticket as CI pipeline" — checks run on ticket state, results archived, monitored | planned |
|
|
58
|
-
| **P5** | **Delegate the routine** | Opt-in, governed auto-approve when checks pass — humans touch only exceptions | planned |
|
|
59
|
-
|
|
60
|
-
**Where we are:** top of **P2**. Right now, today, a QA person can author a `.qa.yml`, run
|
|
61
|
-
`ecoportal-qa`, and read a green/red report of a real template. That is already the core value; P3+
|
|
62
|
-
is about *meeting QA where they work* and *removing manual steps*, not about making it "finally work".
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## How each rung changes the human's day
|
|
67
|
-
|
|
68
|
-
- **P1–P2 (now):** QA runs a command, reads a report. Faster than eyeballing a template by hand, and
|
|
69
|
-
the same checks run identically every time.
|
|
70
|
-
- **P3 (next):** QA doesn't leave Jira. The result appears on the ticket; they read it and click the
|
|
71
|
-
transition themselves. Traceability (which checks, which verdict) is on the ticket forever.
|
|
72
|
-
- **P4:** The run happens *for* them when the ticket moves — no manual step. Same result, same human
|
|
73
|
-
gate, just no "remember to run it".
|
|
74
|
-
- **P5:** For the routine, all-green cases a team opts into, the ticket can advance automatically —
|
|
75
|
-
freeing the human to spend time only where a check failed or judgement is genuinely needed.
|
|
76
|
-
|
|
77
|
-
The trajectory is **less toil, same authority**: at every rung the human still decides; we just remove
|
|
78
|
-
the mechanical work leading up to the decision.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Guardrails that never move (so "going faster" never means "going riskier")
|
|
83
|
-
|
|
84
|
-
1. **Read-only against orgs** — the check path never writes to a customer org.
|
|
85
|
-
2. **Humans decide** — no auto-transition until P5, and even then opt-in + governed + audited.
|
|
86
|
-
3. **Auditable** — the canonical Result is the record; Jira comments are idempotent and redacted.
|
|
87
|
-
4. **Governed by ep-ai-standards** — the tool declares conformance; standards live there, code lives here.
|
|
88
|
-
5. **QA owns the language** — the `.qa.yml` DSL is the delegation surface; the team writes their own checks.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## What could change the plan (honest unknowns)
|
|
93
|
-
- **Sandbox access** — P2's live capture of a real template (`6a3fa5b8…622b`) and P3's live Jira posting
|
|
94
|
-
both need credentials we don't have yet. Until then we build against fixtures + dry-run clients.
|
|
95
|
-
- **Jira specifics** — project, workflow statuses, MCP-vs-REST (see PHASE3-SCOPE.md). These shape P3/P4
|
|
96
|
-
but not the core.
|
|
97
|
-
- **Where check-sets live** — repo vs per-customer vs shared config; affects the ticket→check-set index.
|
|
98
|
-
|
|
99
|
-
None of these block the *core* — they only decide *which channel we wire next and how*.
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# TODOs — QA-as-CI/CD (ecoportal-qa)
|
|
2
|
-
|
|
3
|
-
Legend: `[ ]` todo · `[~]` in progress · `[x]` done · `[!]` blocked
|
|
4
|
-
|
|
5
|
-
Code lives in `ecoportal-qa`; this file tracks the plan.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Phase 1 — DSL + compiler + runner + canonical result ✅ DONE 2026-07-02
|
|
10
|
-
|
|
11
|
-
- [x] `DSL::CheckSet` — parse + validate a declarative `.qa.yml` (meta.ticket/target + expect tree).
|
|
12
|
-
- [x] `Compiler` — DSL → stateless `Check` objects (stage/section/field exists, field type/options/required).
|
|
13
|
-
- [x] `TemplateModel` — normalised read-only view over a page/template doc (stages→sections→fields).
|
|
14
|
-
- [x] `Source::FixtureSource` (offline JSON) + `Source::GraphqlSource` (lazy live read, read-only).
|
|
15
|
-
- [x] `Runner` + canonical `Result` (verdict passed / passed_with_gaps / changes_requested) with honest `:skip`.
|
|
16
|
-
- [x] `Reporters::{Json,Text}`.
|
|
17
|
-
- [x] Proven end-to-end against the real `toocs_coding_page.json` snapshot (7 pass / 2 fail / 3 skip).
|
|
18
|
-
- [x] 11 specs green; rubocop clean (team `.rubocop.yml`); ep-ai-standards conformance stub.
|
|
19
|
-
|
|
20
|
-
**Gate 1:** QA can author YAML → get a green/red result on a real template with zero Ruby. ✅
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Phase 2 — Reporters + more check primitives + CLI ✅ MOSTLY DONE 2026-07-03 (branch `feature/phase-2`, commit `22cc865`)
|
|
25
|
-
|
|
26
|
-
- [x] `Reporters::Csv` + `Reporters::Html` (derive from the canonical Result). JSON/Text refactored
|
|
27
|
-
to render from the canonical hash so redaction applies uniformly.
|
|
28
|
-
- [x] More checks: field ordering + section ordering, force/binding presence, select-option weights,
|
|
29
|
-
field-count bounds (exact or `{min,max}`), "must NOT exist" (stage/section/field absent),
|
|
30
|
-
regex on labels (`label_pattern`, optional `type`). Force/option/required checks `skip` honestly
|
|
31
|
-
when the snapshot didn't capture them.
|
|
32
|
-
- [!] Capture the reference template `6a3fa5b8…622b` via the gem's `dump_template_model.rb`; pin as
|
|
33
|
-
a fixture + author a real check-set. **BLOCKED on a sandbox org + creds** (Open Q #2). Substituted
|
|
34
|
-
a synthetic `sample_template_page.json` (real doc shape) to exercise the new checks offline.
|
|
35
|
-
- [x] PII-redaction pass on results (`Redactor` — emails + custom patterns; preserves verdict/counts).
|
|
36
|
-
- [x] `exe/ecoportal-qa run <check-set> --source fixture:PATH|graphql:ID [--format ...] [--redact]`
|
|
37
|
-
CLI; exit code encodes verdict for CI (0/1/2/3).
|
|
38
|
-
|
|
39
|
-
31 specs green, rubocop clean. Only the live-capture item remains (creds-blocked).
|
|
40
|
-
|
|
41
|
-
## Phase 2b (carried) — monitoring hookup
|
|
42
|
-
- [ ] Feed the canonical Result JSON into a dashboard/monitoring sink (design alongside Phase 4 CI).
|
|
43
|
-
|
|
44
|
-
## Phase 3 — Jira adapter (human-gated) — SCOPED 2026-07-03 (see `PHASE3-SCOPE.md`)
|
|
45
|
-
|
|
46
|
-
**Blocked on build** until Oscar answers the 4 open questions in PHASE3-SCOPE.md (Jira project +
|
|
47
|
-
workflow statuses; REST token vs MCP-only; verdict field vs comment-only; where check-sets live).
|
|
48
|
-
|
|
49
|
-
- [~] Design complete — `Jira::{Client,RestClient,McpClient,DryRunClient,Publisher}`; result funnels
|
|
50
|
-
in as just another consumer of the canonical Result (no runner/DSL changes).
|
|
51
|
-
- [x] **3a** — `Jira::Client` interface + `DryRunClient` + `Publisher` (render→redact→idempotent
|
|
52
|
-
comment). Offline-specable (DryRunClient records calls). *DONE 2026-07-03, branch
|
|
53
|
-
`feature/qa-jira-3a-dryrun-publisher` (ecoportal-qa, UNMERGED). 21 new specs (52 total), rubocop
|
|
54
|
-
clean. Report-only default (no transition), redact-before-post, per-ticket idempotency marker,
|
|
55
|
-
audit trail. 3b/3c still blocked on the 4 open Qs (Jira project/statuses, REST token vs MCP,
|
|
56
|
-
verdict field, where check-sets live).*
|
|
57
|
-
- [ ] **3b** — `Jira::RestClient` (base URL + service-account token; env-gated integration spec).
|
|
58
|
-
- [ ] **3c** — CLI `report --jira [--jira-client rest|mcp|dry-run] [--transition NAME] [--attach ...]`
|
|
59
|
-
+ audit log. Default = report-only (no transition); `--transition` is explicit + human-invoked.
|
|
60
|
-
- [ ] **3d** — (optional) `Jira::McpClient`.
|
|
61
|
-
- [x] Decision recorded: interface + REST-first, MCP later; Phase 3 never auto-transitions (DECISIONS).
|
|
62
|
-
|
|
63
|
-
## Phase 4 — CI-as-code backend ("ticket as pipeline")
|
|
64
|
-
|
|
65
|
-
- [ ] Compiler backend: emit a CI job (GitLab CI / GH Actions) from a check-set.
|
|
66
|
-
- [ ] Pipeline-per-ticket: on ticket state, run the check-set, archive the Result artifact.
|
|
67
|
-
- [ ] Monitoring/dashboards fed by the canonical Result JSON.
|
|
68
|
-
|
|
69
|
-
## Phase 5 — Opt-in auto-approve hooks (governed)
|
|
70
|
-
|
|
71
|
-
- [ ] QA-owned rule: `verdict == passed` + explicit opt-in → offer/perform an auto-transition.
|
|
72
|
-
- [ ] Off by default; audit every auto-approval; RBAC on who can enable it.
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## Open questions (Oscar)
|
|
77
|
-
1. Which Jira project(s)/workflow are we targeting, and MCP vs REST for the adapter?
|
|
78
|
-
2. Sandbox org + creds to run `GraphqlSource` / capture `6a3fa5b8…622b` live.
|
|
79
|
-
3. Do QA prefer authoring in YAML or JSON (both parse the same) — and where do check-sets live
|
|
80
|
-
(in `ecoportal-qa/qa/checks/`, per-customer repos, or a shared config repo)?
|
|
81
|
-
4. Publish `ecoportal-qa` to the internal gem registry, or keep it path/git-sourced for now?
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Project: Search Filter Builder
|
|
2
|
-
|
|
3
|
-
**Created:** 2026-06-07
|
|
4
|
-
**Status:** Planning
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Problem
|
|
9
|
-
|
|
10
|
-
The EcoPortal GraphQL `searchConf` argument is a Hash type — not a typed GraphQL input
|
|
11
|
-
model. This means:
|
|
12
|
-
- No schema validation or autocomplete for filter structures
|
|
13
|
-
- Scripts must hand-craft raw hashes, which are error-prone and hard to read
|
|
14
|
-
- No reuse: changing a search target (e.g. a different `externalId`) requires cloning
|
|
15
|
-
and mutating the whole hash manually
|
|
16
|
-
- No discoverability: customers have no way to learn available filter fields from the
|
|
17
|
-
schema — they must consult separate documentation
|
|
18
|
-
|
|
19
|
-
Engineering has backend classes for the search model, but these are not exposed as
|
|
20
|
-
GraphQL input types. The Confluence API Docs space has a partial filters reference, but
|
|
21
|
-
it is incomplete and not tied to any code.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Goal
|
|
26
|
-
|
|
27
|
-
Provide a first-class Ruby filter builder in `ecoportal-api-graphql` that:
|
|
28
|
-
|
|
29
|
-
1. **Mirrors backend structure** — classes that correspond to the backend search model,
|
|
30
|
-
even though they have no GraphQL type equivalent (they serialise to the expected Hash).
|
|
31
|
-
2. **Supports AND/OR composition** — clean DSL to express nested filter logic without
|
|
32
|
-
manually constructing the `or:` / `filters:` nesting.
|
|
33
|
-
3. **Supports parametrization** — re-use a filter template by substituting specific
|
|
34
|
-
values (e.g. swap `externalId`, `locationId`, field value) without re-building
|
|
35
|
-
from scratch each call.
|
|
36
|
-
4. **Works for both search modalities:**
|
|
37
|
-
- Org search: `currentOrganization { pages(searchConf: ...) }`
|
|
38
|
-
- Register search: `currentOrganization { register(id:) { pages(searchConf: ...) } }`
|
|
39
|
-
5. **AI assistance hook (future):** The front-end already has AI-generated filter
|
|
40
|
-
construction for end users. This builder should be designed so that a future AI layer
|
|
41
|
-
can generate filter objects from natural-language descriptions. The structured classes
|
|
42
|
-
make this tractable — the AI outputs typed objects rather than raw hashes.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Context
|
|
47
|
-
|
|
48
|
-
### searchConf structure (verified from Insomnia production queries)
|
|
49
|
-
|
|
50
|
-
```json
|
|
51
|
-
{
|
|
52
|
-
"filters": [ <filter_object>, ... ],
|
|
53
|
-
"sorters": { "key": "created_at", "direction": "asc" },
|
|
54
|
-
"query": "optional full-text string"
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
`filters` can be an array (standard) or a single object (older queries).
|
|
59
|
-
`sorters` can be a single object or an array. Key field is `key` (not `fieldName`).
|
|
60
|
-
|
|
61
|
-
### Filter operations (snake_case strings — confirmed)
|
|
62
|
-
|
|
63
|
-
| Operation | Structure | Notes |
|
|
64
|
-
|---|---|---|
|
|
65
|
-
| `exact_filter` | `{ key: "field", value: "val" }` | Equality match |
|
|
66
|
-
| `date_filter` | `{ key: "field", gte: "ISO8601", time_zone: "UTC" }` | Also: `lte` |
|
|
67
|
-
| `register_filter` | `{ ids: ["id1", "id2"] }` | Org search only — scope to registers |
|
|
68
|
-
| `and_filter` | `{ filters: [...] }` | Explicit AND group (implicit at top level) |
|
|
69
|
-
| `or_filter` | `{ filters: [...] }` | OR group |
|
|
70
|
-
|
|
71
|
-
Additional (from Confluence docs, not yet confirmed via Insomnia):
|
|
72
|
-
`in_filter`, `range_filter`, `exists_filter`, `ne_filter`
|
|
73
|
-
|
|
74
|
-
### Known filter key fields (confirmed from Insomnia)
|
|
75
|
-
|
|
76
|
-
| key | Type | Operations confirmed |
|
|
77
|
-
|---|---|---|
|
|
78
|
-
| `external_id` | string | `exact_filter` |
|
|
79
|
-
| `updated_at` | datetime | `date_filter` |
|
|
80
|
-
| `created_at` | datetime | (in sorters; likely filterable too) |
|
|
81
|
-
|
|
82
|
-
Additional (from Confluence docs): `state`, `location_ids`, `creator_id`, `template_id`
|
|
83
|
-
|
|
84
|
-
Full reference with production examples: `.ai-assistance/code/search_filters.md`
|
|
85
|
-
|
|
86
|
-
### Source references
|
|
87
|
-
|
|
88
|
-
- Insomnia v5 export: pending import into `.ai-assistance/tmp/insomnia_searches.json`
|
|
89
|
-
- Backend filter classes: accessible via the ecoPortal Rails codebase
|
|
90
|
-
- Front-end queries: `.graphql` files distributed across the React codebase hierarchy
|
|
91
|
-
- Confluence APIDOCS: partial filter reference (most common filters section)
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Design principles
|
|
96
|
-
|
|
97
|
-
- **No GraphQL type required:** Builder classes serialise to Hash — they are plain Ruby
|
|
98
|
-
value objects, not GraphQL input classes. No `Logic::Input` inheritance needed.
|
|
99
|
-
- **Composable:** `AndFilter`, `OrFilter`, `Filter`, `Sorter`, `SearchConf` as
|
|
100
|
-
distinct classes. Compose like: `SearchConf.new.where(externalId: 'X').or(state: :active, state: :draft)`.
|
|
101
|
-
- **Parametrizable:** A built `SearchConf` can be cloned with substitutions —
|
|
102
|
-
`search.with(externalId: 'Y')` returns a new instance with one value swapped.
|
|
103
|
-
- **Serializes to Hash:** `search.to_h` returns the raw hash ready to pass as
|
|
104
|
-
`searchConf:` argument to any query.
|
|
105
|
-
- **AI-compatible (future):** Class structure is simple enough for an AI model to
|
|
106
|
-
instantiate from a natural-language description. The AI assistance integration
|
|
107
|
-
is a follow-on — design should not be blocked by it.
|