Correct a case proposal before approving it
const url = 'https://beta-api.plune.ai/v1/review-items/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/edit';const options = { method: 'PUT', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"expectedRevision":1,"title":"Pay by card","steps":["Open the cart","Pay with 3-D Secure","Confirm in the bank app"],"expected":"The order is placed"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://beta-api.plune.ai/v1/review-items/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/edit \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "expectedRevision": 1, "title": "Pay by card", "steps": [ "Open the cart", "Pay with 3-D Secure", "Confirm in the bank app" ], "expected": "The order is placed" }'A reviewer fixes the title, the steps and the expected result of a case proposal that waits (#1878). The correction is kept as editedCase beside the agent’s proposedCase, which is never changed; approving the item then makes the case from the correction. The save raises revision and clears the approvals given so far, so the people who approved the old text approve again; lint and verdict describe the agent’s proposal and are not recomputed. expectedRevision is the revision you were shown (revision, 1 when absent): any other answers 409 with the revision that stands, so two reviewers never overwrite each other. A correction equal to the version that stands changes nothing and answers 200 with the revision unchanged. The change is logged (entity review_item, action update) with each field’s before and after.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Request Body required
Section titled “Request Body required ”object
The revision the reviewer was shown.
Examples
Add a step
{ "expectedRevision": 1, "title": "Pay by card", "steps": [ "Open the cart", "Pay with 3-D Secure", "Confirm in the bank app" ], "expected": "The order is placed"}Responses
Section titled “ Responses ”The item with its editedCase
One entry of the review queue. Always starts pending; a reviewer moves it on.
object
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.
Present on an entry proposing a new case. Mutually exclusive with the other two.
object
Content-derived identity; the dedup key.
object
What the pre-review checks found, written before the proposal was queued (#1289). It marks the proposal. Only placeholder stops anything: a proposal whose title, steps or expected result still holds {{...}}, [TODO]/[TBD]/[FIXME]/[XXX] (or the same in <...>) or a run of three or more underscores cannot be approved (409 naming the places), and that check is read off the reviewer’s edited version when there is one. Absent means nothing was found.
object
Where the rule is explained.
object
Absent means never executed — NOT “no result yet”. blocked: no answer from the target.
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.
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
The reviewer’s corrected version of the proposal (#1878), beside proposedCase, which stays what the agent said. Present only after an edit; approving the item makes the case from it. Left off the page of the listing (editedBy and editedAt stay).
object
The user id of whoever saved the version in editedCase.
When editedCase was saved.
Present on an entry reporting a test the caller RUNS and this project has no case for. Mutually exclusive with the other two.
object
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.
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
The reporter that found it, e.g. playwright.
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.
What it did on this run, in the reporter’ own word.
The run that turned it up, once stored.
changes_requested (#1276): a reviewer asked the author for changes (changeRequest says what). It is the item’s own state, not a mark on a reviewer: it cannot be approved until the author re-submits, which puts the item back to pending.
Raised by every re-submission; absent is 1. An approval counts only for the revision it was given on.
The user ids asked to review the item - the project’s default reviewer, when they could be asked.
The default reviewer who was NOT asked because they no longer have the right to review - the list says who was passed over.
Who approved which revision; the policy’s approvalsRequired counts those of the current revision.
object
The open request for changes (present with state: changes_requested); the author’s re-submission clears it.
object
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”.
Example
{ "schemaVersion": 1, "proposedCase": { "execution": "auto", "origin": { "mode": "explore" }, "source": { "kind": "url" }, "lint": [ { "rule": "title-vague" } ], "verdict": "passed", "externalKeys": [ { "kind": "playwright-id" } ] }, "discoveredTest": { "keys": [ { "kind": "playwright-id" } ] }, "state": "pending", "rejectionCategory": "duplicate"}A malformed body; the message names the field
object
Example generated
{ "error": "example"}No / invalid token or session
A read-only member
Not found or not yours
object
Example generated
{ "error": "example"}A revision that is no longer the one that stands (the body carries revision), an item already decided, or one that is not a case proposal
object
Example generated
{ "error": "example"}Rate-limited: the per-route throttle, or the per-minute request limit of the plan an API token counts by (#1442; the body names the plan, #2092). Retry-After carries the seconds until the window rolls over.
object
Example generated
{ "error": "example"}Headers
Section titled “Headers ”Seconds until the window rolls over