Skip to main content

Review

Review is the promote step of catching content up. A run drafts and checks, and parks what a machine cannot decide; a person promotes it here. Every decision is recorded against the workspace, feeds the context graph, and decides what a locale can ship as.

Outdated wording

The narration uses terminology that has since been retired. The interface and the behaviour shown are unchanged.

The review session

A project has one review surface: the review session. It is a dedicated page rather than a mode of the editor, and every entry point that says "review", whether a run's hand-off, a dashboard card, or a file's own review link, opens it.

The session walks every pending block across the project's items and locales in one keyboard-first flow. Each step shows the source beside the draft, the checks that fired on it, the voice findings, and the terms in force at the block's point. A collection can be carried into the session from the project overview, so a reviewer who owns the help centre reviews only the help centre; item and locale filters narrow the queue further.

For each block:

  • Approve marks the target reviewed for that locale. It needs the review permission for that language, which the built-in Reviewer template carries; a translator can edit and reject, but not approve.
  • Sign off marks it signed off, the rung above reviewed, for a ship gate that asks for more than a review. It needs the same review permission, and it can be given straight from a translated target or after an approval.
  • Reject sends it back to draft for another pass.
  • Edit fixes the draft in place. A fix is a correction made at a point, and corrections are what the context learns from (see Voice and corrections).

Review status is tracked per locale. A block's status is a property of each target, so approving the French target never changes the German one, and a reviewer scoped to French can approve only French.

Correct the context from the session

Some of what a reviewer notices is about the rules rather than the draft. Three actions in the session act on the context instead of the block:

  • Mark a source term. Records that a word in the source is a term, with the status it should carry. Setting a governed status such as forbidden or preferred opens a change-set rather than applying directly, so someone other than the author approves it.
  • Propose a source change. A fix that belongs in the source, not in one target, is routed to the source owner as a proposal. It invalidates every locale of that block once accepted, and the proposal shows that reach before anyone accepts it.
  • Suggest a voice rule. A recurring fix becomes a candidate rule for the voice profile in force at the point, reviewed on the Context hub's Voice section.

Bulk approval

A workspace with one reviewer and many drafts does not need to click through every block. Approve everything passing approves every pending block whose checks report no error-severity finding and whose voice score meets the profile's compliance bar. Blocks that fail a check or fall below the bar are left pending for a person. The same predicate decides a locale's ship state below, so what bulk approval accepts is exactly what was already shippable on machine review. The response names each bar that left a target pending, including the targets the caller wrote themselves in a workspace that blocks self-approval.

Machine authorship

A draft a run produced carries no human author, because a run writes it with nobody acting. Separation of duties (see Members and roles) stops a person from approving a translation they wrote by hand, and leaves the one person in a small workspace free to approve what the machine wrote. It applies to every way of promoting a target: block by block, over a selection, through Approve everything passing, to a sign-off, which is judged on the author of the wording exactly as an approval is, and to decisions pushed from a working copy.

A decision that arrives by kapi push is held to the same review permission and the same separation-of-duties policy as one made here, and the push reports the approvals and sign-offs the workspace did not accept. The content lands either way, as a translation awaiting review.

Taking a sign-off back is review-level work here, and it is by push as well. A push that lowers a signed-off target without changing its translation lands only from someone who holds review permission for that language; otherwise the sign-off stands and the push reports the demotion it did not apply. An edited translation drops to awaiting review on either route, because a sign-off judged the wording it was given.

A rejection that arrives by push applies only to the translation it names. When that translation has since been replaced here, the unit keeps its rung and its record, and the push reports the rejection it did not apply.

What an approval leaves behind

Two records, written for every approval whichever route made it:

  • A decision, in the project's ledger, naming who decided, when, and the hash of the exact wording they blessed. That record travels to a working copy on kapi pull, and it is what promotes the wording into the workspace content memory.
  • An audit entry, in the workspace audit log, naming the actor, the block, the locale, and the rungs the target moved between. A rejection, a sign-off and a withdrawn approval are recorded the same way, each under its own name. Approve everything passing records the pass and its counts per language, because the pass is what the person decided; which blocks it took is in the ledger.

The reviewer is summoned

When a run parks work, the reviewer is told: a review task opens, an email goes out, and the app shows a banner and a badge sized to what is actually pending. The summons names the count and the locales, not the whole project.

Approval continues the loop

Approving the last pending block of a locale closes its review task. When that empties the project's whole review queue, a completing run starts on its own and delivers the approved content, so review never ends in a dead end that needs another click.

run parkschecks green is not enoughsummonssessionapprove · reject · edit · correct the contextapprovereview completelast pending block approvedcontinuescompleting rundelivers approved content

A run parks what it cannot decide; the session promotes it; the last approval starts the run that delivers.

Source review: the first worklist

Target review is the second gate. The loop settles the source before it translates (the loop is source-first), so a run has an upstream worklist: source review. When a run finds source that has not cleared the project's source_gate, it holds the fan-out for that content and routes it to a person instead of paying to translate an unsettled source into every language.

When a run holds on source:

  • The run parks with the reason source_not_ready and records how many blocks are blocked on source. In the Runs view this reads as parked, N blocks need source review; the run still exits without error.
  • The loop opens a source review task for a member with source-edit permission. It is the same task queue as translate, review and the fix-up tasks, and appears on the task board and in My Tasks.

A source reviewer works the same content on the source side: terms, do-not- translate marks, placeholders, and context, before the fan-out. Clearing the task lifts the affected source to the gate; the next run translates the now-approved content, memory first. A project that wants raw fan-out sets source_gate: none.

The review inbox

The workspace-level Review inbox rolls up every project awaiting review, most-pending first, each linking into its own session. It reads the same project-scoped standing the dashboard shows, so pooled review and review assigned to a person are both visible, not only what is assigned to you.

Ship states

Review decides what a locale can ship as. Bowrain derives one ship state per locale, per project and per collection, from what the work left behind:

StateMeaning
governedEvery block translated, no failing check, nothing stale, a terminology result for every block, every target carrying a review decision, and terms governing the locale.
approvedThe same, in a locale no terms govern: a person approved every target, and only the checks stand behind the approval.
ai_shippableEvery block translated, no failing check, and a terminology result wherever terms govern, but review is incomplete: shippable on machine review only.
pendingAnything less: partial coverage, a failing check, a stale decision, a turned-down translation, a block terms govern with no terminology result, or nothing to ship yet.

The rule is the same everywhere it is read. A locale is pending when any block is untranslated, has an error-severity finding, carries a decision made against content that has since changed, or holds a translation a reviewer turned down. A block in a locale terms govern with no terminology result, such as a target made only of inline codes, also holds the locale at pending. A block whose target uses a forbidden term counts as a failing check.

Otherwise the locale is ai_shippable while some targets await approval. With every target approved, it is governed where terms govern the locale and approved where none do. A voice score does not change the state: a block under the voice profile's bar is held out of bulk approval instead.

The state appears on the project dashboard, per collection, in the Runs view's per-locale summary, and in the workspace loop rollup. It is also published at the delivery edge: GET /api/v1/projects/:id/ship.json serves a per-locale manifest a site's language picker can read to hide locales that are not shippable and to badge those shipped on machine review. The entry for a locale no terms govern adds "not_governed": ["terms"]. An approved locale reads as shippable and verified, and that field is how a build tells it apart from a governed one. The same manifest is what kapi status --ship --emit ship.json writes at build time, so a site built from a checkout and a site reading the server agree.

Set the bar where the content sits. A legal notice waits for a person (governed); a help article may ship on checks (ai_shippable). The project's ship_gate and per-scope ship_gates in the recipe carry that decision (see Project model).

Review in place

Strings read differently in a component than in a table. A collection can declare where its strings can be read in place:

collections:
- name: web-ui
channel: app
preview:
kind: storybook
url: https://storybook.example.com
content:
- path: "i18n/en/*.json"
format: json

preview names a host and how to find a view in it. A storybook host publishes an index that maps components to stories, so an item resolves to the stories of the components its blocks name. The offer to review in place appears on the page a reviewer opens a file from; the reviewer's own translations are pushed into the running page as they review. A collection with no preview block offers no in-place reading. The block is declared per collection because a repository publishes one host per surface it ships.

Checks in review

Checks run in the loop, and their findings travel with the block into the session: each finding carries a severity, a type, and a message, and a block with an error-severity finding cannot be approved in bulk. A reviewer can re-run the checks over a file from the session after editing.

Voice review

Block review and voice review are different decisions. Promoting or rejecting a candidate rule, or a rule change bundled into a change-set, happens on the Context hub's Voice section, by someone other than the rule's author.