# Validation

## Query validation result summaries

> Retrieve lightweight validation summaries for a repository. Returns only counts and status — no markdown content or raw deployment data.\
> \
> \*\*Use cases:\*\*\
> \- Table view: list recent validations with status badges and package counts\
> \- Filter by base branch or PR number\
> \
> Results are ordered by most recent first.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}}},"paths":{"/sfp/api/validation/results":{"get":{"operationId":"ValidationController_getResults","summary":"Query validation result summaries","description":"Retrieve lightweight validation summaries for a repository. Returns only counts and status — no markdown content or raw deployment data.\n\n**Use cases:**\n- Table view: list recent validations with status badges and package counts\n- Filter by base branch or PR number\n\nResults are ordered by most recent first.","parameters":[{"name":"repositoryIdentifier","required":true,"in":"query","description":"Repository identifier (e.g., flxbl-io/sf-core)","schema":{"type":"string"}},{"name":"pullRequestNumber","required":false,"in":"query","description":"Filter by PR number","schema":{"type":"string"}},{"name":"baseBranch","required":false,"in":"query","description":"Filter by target/base branch","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum results (default: 20, max: 100)","schema":{"type":"number"}}],"responses":{"200":{"description":"Lightweight validation summaries"},"400":{"description":"Missing repositoryIdentifier"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: member, owner, application"}},"tags":["Validation"]}}}}
```

## Publish validation results

> Store validation results from \`sfp validate\`. Called by the CLI when \`--publish-results\` is used.\
> \
> \*\*Dual write:\*\* Stores full results (with markdown and deployment/test data) in the results table and a lightweight summary in the summary table.\
> \
> \*\*Duplicate handling:\*\* If results already exist for the same PR + commit + domain, they are overwritten.\
> \
> \*\*Retention:\*\* Keeps last 500 results per repository.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"PublishValidationDto":{"type":"object","properties":{"repositoryIdentifier":{"type":"string","description":"Repository identifier (e.g., flxbl-io/sf-core)"},"pullRequestNumber":{"type":"string","description":"Pull request number (if PR context)"},"commitSha":{"type":"string","description":"Git commit SHA that was validated"},"domain":{"type":"string","description":"Domain / release config name (e.g., \"frameworks\", \"core\"). Used as part of the storage key so each domain is stored separately."},"branchName":{"type":"string","description":"Source branch name"},"baseBranch":{"type":"string","description":"Target branch name (for PRs)"},"status":{"type":"string","description":"Validation status","enum":["succeeded","failed","no_changes"]},"validationMode":{"type":"string","description":"Validation mode","enum":["individual","thorough"]},"targetOrg":{"type":"string","description":"Target org used for validation"},"pool":{"type":"string","description":"Pool tag(s) used"},"deploymentResult":{"description":"Deployment result details","allOf":[{"$ref":"#/components/schemas/DeploymentResultDto"}]},"testResults":{"description":"Test results per package","type":"array","items":{"$ref":"#/components/schemas/TestResultDto"}},"errorMessage":{"type":"string","description":"Overall error message if validation failed"},"validationMarkdown":{"type":"string","description":"Pre-rendered validation markdown"},"testResultsMarkdown":{"type":"string","description":"Pre-rendered test results markdown"},"executionTimeMs":{"type":"number","description":"Total execution time in milliseconds"},"prUrl":{"type":"string","description":"Direct URL to the pull request"},"commitUrl":{"type":"string","description":"Direct URL to the commit"}},"required":["repositoryIdentifier","commitSha","status","validationMode","deploymentResult"]},"DeploymentResultDto":{"type":"object","properties":{"deployed":{"description":"Successfully deployed packages","type":"array","items":{"$ref":"#/components/schemas/DeployedPackageDto"}},"failed":{"description":"Failed packages","type":"array","items":{"$ref":"#/components/schemas/FailedPackageDto"}},"scheduled":{"type":"number","description":"Number of scheduled packages"},"error":{"type":"string","description":"Overall deployment error message"}},"required":["deployed","failed"]},"DeployedPackageDto":{"type":"object","properties":{"packageName":{"type":"string","description":"Package name"},"packageType":{"type":"string","description":"Package type (source, unlocked, data, etc.)"},"versionNumber":{"type":"string","description":"Package version number"}},"required":["packageName","packageType"]},"FailedPackageDto":{"type":"object","properties":{"packageName":{"type":"string","description":"Package name"},"error":{"type":"string","description":"Error message describing why the package failed"}},"required":["packageName"]},"TestResultDto":{"type":"object","properties":{"packageName":{"type":"string","description":"Package name the tests belong to"},"passed":{"type":"boolean","description":"Whether tests passed"},"totalTests":{"type":"number","description":"Total number of tests"},"passingTests":{"type":"number","description":"Number of passing tests"},"failingTests":{"type":"number","description":"Number of failing tests"},"coverage":{"type":"number","description":"Code coverage percentage"}},"required":["packageName","passed"]}}},"paths":{"/sfp/api/validation/results":{"post":{"operationId":"ValidationController_publishResults","summary":"Publish validation results","description":"Store validation results from `sfp validate`. Called by the CLI when `--publish-results` is used.\n\n**Dual write:** Stores full results (with markdown and deployment/test data) in the results table and a lightweight summary in the summary table.\n\n**Duplicate handling:** If results already exist for the same PR + commit + domain, they are overwritten.\n\n**Retention:** Keeps last 500 results per repository.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishValidationDto"}}}},"responses":{"201":{"description":"Results stored successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: application"}},"tags":["Validation"]}}}}
```

## Get full validation results for a pull request

> Retrieve all validation runs for a specific PR with full data including markdown and deployment/test details.\
> \
> \*\*Use cases:\*\*\
> \- PR detail view: show deployment breakdown, test results, and markdown reports\
> \- Compare validation results between commits on the same PR\
> \
> Each entry represents a separate validation run (one per commit + domain combination).

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.3.0"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}}},"paths":{"/sfp/api/validation/pr/{prNumber}":{"get":{"operationId":"ValidationController_getPRValidation","summary":"Get full validation results for a pull request","description":"Retrieve all validation runs for a specific PR with full data including markdown and deployment/test details.\n\n**Use cases:**\n- PR detail view: show deployment breakdown, test results, and markdown reports\n- Compare validation results between commits on the same PR\n\nEach entry represents a separate validation run (one per commit + domain combination).","parameters":[{"name":"prNumber","required":true,"in":"path","description":"Pull request number","schema":{"type":"string"}},{"name":"repositoryIdentifier","required":true,"in":"query","description":"Repository identifier (e.g., flxbl-io/sf-core)","schema":{"type":"string"}}],"responses":{"200":{"description":"PR validation runs with full data"},"400":{"description":"Missing repositoryIdentifier"},"403":{"description":"Forbidden - Requires role: member, owner, application"}},"tags":["Validation"]}}}}
```
