---
title: "Review"
description: "Edit, verify and reject translation records from code, with the same rules everywhere."
canonical_url: "https://diglot.sh/core/review"
---
# Review

> Edit, verify and reject translation records from code, with the same rules everywhere.

When you build a review tool, whether a web editor, a bot or a script, you need the same rules that diglot applies everywhere else: an edit has to be a valid translation, a rejected record can only be replaced by an edit, and a reviewer must not overwrite a change they never saw. `editRecord`, `verifyRecord` and `rejectRecord` implement those rules, so your tool only has to load a record, call one of them and write the result back.

Each function takes the current record, or `undefined` when there is none, and returns either the next record or a refusal:

```ts
import { verifyRecord } from '@diglot/core'
import { writeRecord } from '@diglot/store'

const result = verifyRecord(record, { segment, by: 'danielroe', expected: textTheReviewerSaw })
if (!result.ok)
  throw new Error(result.message)

await writeRecord(root, 'fr', result.record)
```

A successful result is `{ ok: true, record, warnings }`, where `record` is normalised and ready to write and `warnings` are the validation warnings of its text. A refusal is `{ ok: false, code, message, errors }`, and `errors` lists the validation errors when the code is `invalid`.

## Options every function takes

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        by
      </code>
    </td>
    
    <td>
      The GitHub login of the reviewer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        at
      </code>
    </td>
    
    <td>
      An ISO 8601 timestamp. Defaults to now
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        expected
      </code>
    </td>
    
    <td>
      The text the reviewer saw. If the record's current text differs, the transition is refused as <code>
        stale
      </code>
      
      . <code>
        null
      </code>
      
       means the reviewer expected no record. Without it, the current text isn't checked
    </td>
  </tr>
</tbody>
</table>

Pass `expected` whenever a person acts on something they read earlier. If the Action or another reviewer changed the record in the meantime, the refusal tells your tool to reload instead of silently overwriting their work.

## Edit

`editRecord(record, { segment, text, by, style, maxLength })` writes a human edit: `origin` becomes `human` and `review` becomes `edited`. The record keeps its `mt`, `prev` and `derived`, so you can still see how much of the machine draft changed, and its `verifiedBy` and `rejectedBy` are dropped. That is why an edit is the way to replace a rejection.

The function refuses:

- `mismatch`, when the record's `hash` isn't the segment's.
- `invalid`, when the text fails [validation](https://diglot.sh/core/validation) against the segment or is longer than `maxLength`. `maxLength` defaults to `maxTranslationLength` of the source skeleton, and `false` turns the limit off.
- `unchanged`, when the text is the same as before, unless the record is rejected.

Without a record, it creates one. Pass the locale's `style` to get `length` warnings for texts outside its length band.

## Verify

`verifyRecord(record, { segment, by, style })` sets `review` to `verified` and adds `verifiedBy`. When you pass a `segment`, the record's text is validated against it first. The function refuses:

- `no-record`, when there is no record.
- `rejected`, when the record is rejected. Edit it instead.
- `invalid`, when the text fails validation against the segment.
- `unchanged`, when the record is already verified, so the first reviewer stays on record.

## Reject

`rejectRecord(record, { by })` sets `review` to `rejected`, adds `rejectedBy` and drops `verifiedBy`. The text stays in the record for reviewers and metrics, while readers see the source text. The function refuses a missing record (`no-record`) and one that is already rejected (`unchanged`).

## Refusal codes

<table>
<thead>
  <tr>
    <th>
      Code
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        no-record
      </code>
    </td>
    
    <td>
      There is no record to verify or reject
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stale
      </code>
    </td>
    
    <td>
      The record's text isn't the <code>
        expected
      </code>
      
       text
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        invalid
      </code>
    </td>
    
    <td>
      The text fails validation against the segment
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        unchanged
      </code>
    </td>
    
    <td>
      The transition wouldn't change the record
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rejected
      </code>
    </td>
    
    <td>
      The record is rejected, and only an edit replaces a rejection
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mismatch
      </code>
    </td>
    
    <td>
      The record belongs to another segment
    </td>
  </tr>
</tbody>
</table>

The [x18n plugin](https://diglot.sh/review-ui/reviews) verifies approved records through `verifyRecord`, so a review in x18n follows these rules too.


## Sitemap

See the full [sitemap](https://diglot.sh/sitemap.md) for all pages.
