Skip to content

Offer tests this project has no case for

POST
/v1/review-items/discovered
curl --request POST \
--url https://beta-api.plune.ai/v1/review-items/discovered \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "runId": "4f1a7f6e-0000-4000-8000-0000000000aa", "discovered": [ { "keys": [ { "kind": "playwright-id", "value": "pw-cart" } ], "title": "cart adds an item", "source": "playwright", "specRef": "e2e/checkout.spec.ts:12", "rawStatus": "passed" } ] }'

A runner reports the tests it ran that resolved to no case. Each becomes a queue entry of a third kind — one that testifies a case is missing rather than describing one — and a reviewer decides whether the project tracks it. Approving creates an automated case and attaches the keys, which is what makes the next run resolve instead of offering the same test again. Nothing is created here: the review queue remains the only way a case is born.

Media type application/json
object
discovered
required
Array<object>
>= 1 items <= 500 items

A test the caller runs that this project has no case for. It carries NO steps and no expected result, and that is the shape rather than a gap: a reporter sees a test’ RESULT, never its source, so it testifies that a case is missing instead of describing one. Approving the entry creates an automated case pointing at specRef and attaches every key, so the next run resolves instead of discovering the same test again.

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
runId

The run that turned these up. Checked against the caller’ own runs.

string
Examples
Example one

One test a Playwright suite ran and Plune has no case for

{
"runId": "4f1a7f6e-0000-4000-8000-0000000000aa",
"discovered": [
{
"keys": [
{
"kind": "playwright-id",
"value": "pw-cart"
}
],
"title": "cart adds an item",
"source": "playwright",
"specRef": "e2e/checkout.spec.ts:12",
"rawStatus": "passed"
}
]
}

The batch was read. Read the verdicts, not only the status — 200 does NOT mean every test was queued, and a caller that assumes it will re-offer refused tests for ever or go quiet about a real gap.

Media type application/json
object
results
required
Array<object>

What became of ONE offered test. Read it per test: most of a repeated batch is already known or already refused, and a status line cannot say which.

object
key
required

The key the server identified this test by — its highest-ranked kind.

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

queued — a new entry is waiting for a reviewer. duplicate — an entry about this test already exists. refused — a reviewer has already declined it, and the answer outlives the run that provoked it. known — a case already holds this key, so nothing should have been offered; resolve before discovering. created — the project trusts this source, so the case was made without asking; count these, because they are the ones a reporter would otherwise report as nothing happening.

string
Allowed values: queued duplicate refused known created
id

The queue entry, when there is one.

string format: uuid
testCaseId

The case a trusted source produced. Only on created.

string format: uuid
Example
{
"results": [
{
"key": {
"kind": "playwright-id"
},
"outcome": "queued"
}
]
}

Nothing was stored. Either the list is missing or exceeds the ceiling, or a test carries a field this kind of entry does not have — steps and an expected result are REFUSED by name rather than dropped, because a client that sent them believes they were stored.

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

No / invalid token or session

The runId is not one of the caller’ runs. Nothing is stored — answering 201 to a partly wrong request would leave rows missing the one field nobody would think to look for again.

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