Skip to content

fix: move on-demand validation to /geo-experiments/:geoExperimentId/validate - #3045

Merged
jindaliiita merged 3 commits into
mainfrom
fix/geo-experiment-validate-endpoint
Aug 15, 2026
Merged

fix: move on-demand validation to /geo-experiments/:geoExperimentId/validate#3045
jindaliiita merged 3 commits into
mainfrom
fix/geo-experiment-validate-endpoint

Conversation

@jindaliiita

Copy link
Copy Markdown
Contributor

Summary

  • Moves the on-demand validation endpoint from POST /sites/:siteId/opportunities/:opportunityId/validate (with geoExperimentId in the body) to POST /sites/:siteId/geo-experiments/:geoExperimentId/validate — this validates the GeoExperiment's own suggestions, not its linked opportunity, so geoExperimentId belongs in the route, matching the sibling PATCH/DELETE/trigger-impact-measurement GeoExperiment routes.
  • The linked opportunity (used only to pick the import-worker message type) is now resolved internally via geoExperiment.getOpportunityId() instead of being passed in.
  • Moves the trigger logic from the standalone opportunity-validation-controller.js into suggestions.js as triggerGeoExperimentValidation, alongside its GeoExperiment siblings (triggerImpactMeasurement, etc.) instead of keeping it in its own file.
  • Updates route registration (src/routes/index.js), capability gating (INTERNAL_ROUTES in required-capabilities.js, llmo/can_configure + aso/can_edit in facs-capabilities.js), and OpenAPI docs (api.yaml, site-opportunities.yaml, schemas.yaml) to match.

Test plan

  • npx mocha on test/controllers/suggestions.test.js, test/routes/index.test.js, test/routes/required-capabilities.test.js, test/routes/facs-capabilities.test.js, test/index.test.js — 4012 passing, 0 failing
  • npm run lint on all changed files — clean
  • Full suite with coverage (npm test) — passes the repo's 90% threshold
  • npm run docs:lint — OpenAPI spec valid, no new warnings
  • npm run docs:builddocs/index.html regenerated

🤖 Generated with Claude Code

…alidate

The endpoint validates a GeoExperiment's own suggestions, not its linked
opportunity, so geoExperimentId belongs in the route (matching the sibling
PATCH/DELETE/trigger-impact-measurement GeoExperiment routes) instead of the
request body under /opportunities/:opportunityId/validate. The linked
opportunity is now resolved internally via geoExperiment.getOpportunityId()
to pick the import-worker message type. Moves the trigger logic into
suggestions.js alongside its GeoExperiment siblings instead of keeping a
separate controller file.
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@jindaliiita
jindaliiita deployed to dev-branches August 13, 2026 13:51 — with GitHub Actions Active
…lidate-endpoint

# Conflicts:
#	docs/index.html
@github-actions

Copy link
Copy Markdown

This PR will trigger a patch release when merged.

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jindaliiita,

Verdict: Request changes - two behavioral contract changes need explicit confirmation before merge.
Complexity: HIGH - large diff; API route relocation + shared contract change (OpenAPI).
Changes: Relocates the on-demand validation endpoint from the opportunity resource to the geo-experiment resource, adds access control, and resolves the linked opportunity internally (13 files).
Note: Recommend a human read before merge - this change modifies shared API contracts (OpenAPI spec). The bot review is a complement to, not a replacement for, a human read here.

Must fix before merge

  1. [Important] S2S access contract change: old route was in routeRequiredCapabilities with opportunity:write (S2S consumers could call it); new route is in INTERNAL_ROUTES only (S2S consumers are now denied) - src/routes/required-capabilities.js:64 (details inline)
  2. [Important] Behavioral tightening: GeoExperiments with no linked opportunity now get 400, whereas the old endpoint could accept them - src/controllers/suggestions.js:2801 (details inline)
Non-blocking (5): minor issues and suggestions
  • nit: error messages say "Site ID required" / "GeoExperiment ID required" when the actual issue is invalid UUID format; sibling code says "must be a valid UUID" - src/controllers/suggestions.js:2780
  • suggestion: define geoExperimentId path param via $ref: './parameters.yaml#/geoExperimentId' instead of inline, matching how sibling endpoints use shared parameter definitions - docs/openapi/site-opportunities.yaml:276
  • suggestion: GeoExperimentValidationResponse schema should mark its four always-present fields as required to strengthen the contract - docs/openapi/schemas.yaml:3242
  • nit: add a comment on the new INTERNAL_ROUTES entry explaining why validate is internal (mirrors sibling routes but the existing block has section comments for each group) - src/routes/required-capabilities.js:64
  • nit: Configuration.findLatest() and sqs.sendMessage() have no null/error guards, but this is a pre-existing pattern across all sibling methods, not a regression - src/controllers/suggestions.js:2819

Note: CI checks are passing.


Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 2m 50s | Cost: $6.14 | Commit: 84764b5a937b60ec1899c207ba2cd531e8b826ac
If this code review was useful, please react with 👍. Otherwise, react with 👎.

Comment thread src/routes/required-capabilities.js
Comment thread src/controllers/suggestions.js
@MysticatBot MysticatBot added ai-reviewed Reviewed by AI complexity:high AI-assessed PR complexity: HIGH needs-human-review AI reviewer recommends a human read before merge labels Aug 15, 2026
siteId, geoExperimentId, opportunityId, and status are unconditionally set
on every successful (202) response, so document that guarantee in the
OpenAPI schema per MysticatBot review feedback on #3045.

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jindaliiita,

Verdict: Approve - both prior blocking findings resolved through convincing author responses; new commit addresses the schema suggestion.
Complexity: HIGH - large diff; API route relocation + shared contract change (OpenAPI).
Changes: Relocates the on-demand validation endpoint from the opportunity resource to the geo-experiment resource, consolidates the controller into suggestions.js, updates access control and OpenAPI docs (13 files).
Note: Recommend a human read before merge - this change modifies shared API contracts (OpenAPI spec). The bot review is a complement to, not a replacement for, a human read here.
Note: CI checks are currently pending - confirm passing before merge.

Non-blocking (2): minor issues and suggestions
  • nit: error messages say "Site ID required" / "GeoExperiment ID required" when the actual validation failure is an invalid UUID format; sibling code uses "must be a valid UUID" - src/controllers/suggestions.js:2780
  • suggestion: define geoExperimentId path param via $ref: './parameters.yaml#/geoExperimentId' instead of inline, matching how sibling endpoints use shared parameter definitions - docs/openapi/site-opportunities.yaml:917

Previously flagged, now resolved

  • S2S access contract concern: author confirmed endpoint is UI-only, never consumed by S2S in its 4-day lifetime at the old path, consistent with all sibling geo-experiment routes in INTERNAL_ROUTES.
  • Behavioral tightening (null opportunity 400): author explained the old design was semantically broken (could validate against an unlinked opportunity); the new behavior is more correct, not just stricter.
  • GeoExperimentValidationResponse schema now marks all four fields as required (addressed by new commit 1f97a99).

Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 3m 47s | Cost: $1.44 | Commit: 1f97a998c397583ca14ebd2499ca577d9001c382
If this code review was useful, please react with 👍. Otherwise, react with 👎.

@jindaliiita
jindaliiita deployed to dev-branches August 15, 2026 14:00 — with GitHub Actions Active
@jindaliiita
jindaliiita merged commit 1dd3891 into main Aug 15, 2026
23 checks passed
@jindaliiita
jindaliiita deleted the fix/geo-experiment-validate-endpoint branch August 15, 2026 14:20
solaris007 pushed a commit that referenced this pull request Aug 15, 2026
## [1.749.1](v1.749.0...v1.749.1) (2026-08-15)

### Bug Fixes

* move on-demand validation to /geo-experiments/:geoExperimentId/validate ([#3045](#3045)) ([1dd3891](1dd3891))
@solaris007

Copy link
Copy Markdown
Member

🎉 This PR is included in version 1.749.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed Reviewed by AI complexity:high AI-assessed PR complexity: HIGH needs-human-review AI reviewer recommends a human read before merge released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants