Skip to content

Queue a result for human review

POST
/v1/review-items
curl --request POST \
--url https://beta-api.plune.ai/v1/review-items \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "resultId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "note": "example" }'

A person queues a disputed result here. The Cairn ingest also queues entries, but they are PROPOSED CASES rather than results (#10, ADR-CI-03) and arrive through /v1/ingest/cairn. One item per result.

Media type application/json
object
resultId
required

Must be a result in your project.

string format: uuid
note

Why this one is worth a look.

string
Example generated
{
"resultId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"note": "example"
}

Queued, pending

Media type application/json

One entry of the review queue. Always starts pending; a reviewer moves it on.

object
schemaVersion
required
integer
Allowed values: 1
id
required
string format: uuid
resultId

Present on an entry disputing a RESULT. Exactly one of resultId, proposedCase and discoveredTest is present: an entry with two asks two questions at once, and one with none asks nothing.

string format: uuid
proposedCase

Present on an entry proposing a new case. Mutually exclusive with the other two.

object
stableId
required

Content-derived identity; the dedup key.

string
title
required
string
<= 300 characters
execution
required
string
Allowed values: auto manual
steps
required
Array<string>
>= 1 items <= 20 items
expected
required
string
<= 2000 characters
origin
required
object
runId
required
string
mode
required
string
Allowed values: explore design api
target
required
string
technique
string
<= 32 characters
priority
string
source
object
kind
required
string
Allowed values: url openapi-operation requirement
value
required
string
>= 1 characters <= 100 characters
rationale
string
>= 1 characters <= 400 characters
runCost
object
tokens
required
integer
cases
required
integer
verdict

Absent means never executed — NOT “no result yet”.

string
Allowed values: passed failed
externalKeys

What a match resolves through. Absent is a normal proposal, not a degraded one: an agent that names no key gets an entry with no comparison, which is exactly what a genuinely new case gets.

Array<object>
<= 32 items

An identifier another tool already uses for this test, so a report can find its case without anyone typing a Plune id. The order of kind is load-bearing: it is the ranking that decides which key wins when several match different cases.

object
kind
required
string
Allowed values: playwright-id path-title allure-history cairn-stable eval-id qase testrail
value
required
string
<= 1024 characters
discoveredTest

Present on an entry reporting a test the caller RUNS and this project has no case for. Mutually exclusive with the other two.

object
keys
required

The identity. Order does not matter — the server ranks them and the highest-ranked kind is what deduplication reads, so two adapters sending the same keys in a different order do not produce two entries about one test.

Array<object>
>= 1 items <= 8 items

An identifier another tool already uses for this test, so a report can find its case without anyone typing a Plune id. The order of kind is load-bearing: it is the ranking that decides which key wins when several match different cases.

object
kind
required
string
Allowed values: playwright-id path-title allure-history cairn-stable eval-id qase testrail
value
required
string
<= 1024 characters
title
required
string
<= 300 characters
source
required

The reporter that found it, e.g. playwright.

string
<= 32 characters
specRef
required

Where the test lives, e.g. e2e/checkout.spec.ts:12. Required while everything descriptive is optional: an approved discovery becomes an automated case, and that shape needs a spec to point at.

string
<= 400 characters
rawStatus

What it did on this run, in the reporter’ own word.

string
<= 64 characters
platformRunId

The run that turned it up, once stored.

string
state
required
string
Allowed values: pending approved rejected
rejectionCategory

Present on every item rejected after R4, and absent forever on rejections stored before it — those are never migrated and must keep reading without error. An item that is pending or approved usually has none, but MAY still carry one: a rejection returned to review keeps the pair in the row as a draft, and the next move to rejected must supply it in the request anyway. Read it as “meaningful only while state is rejected”, not as “absent otherwise”.

string
Allowed values: duplicate incorrect out-of-scope low-value not-testable other
note
string
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
Example
{
"schemaVersion": 1,
"proposedCase": {
"execution": "auto",
"origin": {
"mode": "explore"
},
"source": {
"kind": "url"
},
"verdict": "passed",
"externalKeys": [
{
"kind": "playwright-id"
}
]
},
"discoveredTest": {
"keys": [
{
"kind": "playwright-id"
}
]
},
"state": "pending",
"rejectionCategory": "duplicate"
}

Missing resultId or an invalid body

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

Result not found or not yours

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Already queued — the body carries the existing item id

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Rate-limited: either the per-route throttle or a tenant quota. Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over