Skip to content

Automatic translation — no human review gate — decision record

Deliverable for ADO PBI #1455 — "Make translation fully automatic; remove the human review gate." This is the durable record of the product pivot the implementation executed against.

Scope of this doc: the decision + the trade-offs behind it, and a precise account of what changed in the code and what was deliberately preserved. The code change shipped with this PBI; this record is its rationale and its boundary (what is out of scope / future).

Date: 2026-06-25.

It supersedes a prior product invariant. It retires the "apprenticeship, not a batch job" / per-batch human approval gate that spec.md and user-stories.md used to describe, and subsumes the auto-advance work. It also retires the premise of Feature #1365 that "the human-in-the-loop quality gate is the product's reason to exist."


0. TL;DR — the decisions

#QuestionDecisionConsequence
D1Is there a human review/approval gate?No. Kenly is a fully automatic translation service. Upload → upfront cost estimate → commit/pay → the whole book translates itself → read/export.The per-page approve / reject / edit and the source-language confirm/correct steps are gone. Processed pages are auto-approved by the system.
D2How does the batch ladder escalate?Automatically. Still calibrate on one page first, but each completed batch auto-confirms (increments ApprovalCount, widening the next batch) and the next batch is enqueued by IBatchAutoAdvancer (on the JobProcessor) with a Worker backstop.Calibrating → Processing → Complete with auto-confirm; no human action between batches. BatchPolicy (1 → 5 → 25 → 100 → rest) is unchanged.
D3What can stop an in-flight book?Only affordability. When the next batch would exceed the wallet balance, processing pauses cleanly (no error) and shows the "Add credit" CTA (#1396). A top-up resumes it. Failed pages are recovered by explicit retry.The pre-commit cost estimate (#1375) + the wallet are the sole gate. Retry is the one remaining explicit control.
D4What does the reading screen do?Read-only. Page through the translation (original scan beside the English), see per-page status, export. No decision buttons.The completion notification fires once when the whole book finishes ("Translation ready"), not per batch.

1. The decision

Remove the human review gate. Kenly is a fully automatic translation service with no human-in-the-loop review. A user uploads a book, sees an upfront cost estimate, commits/pays, and the entire book translates automatically with zero per-page interaction; they then read and export the finished translation. Like it or leave.

This is a product call by the product owner, not an engineering convenience:

  • The decision burden was too high. Asking a reader to approve/reject/correct every page — for a book that can run to hundreds or a thousand pages — is a worse experience than a finished translation delivered for a known upfront price. The gate that was framed as "the product's reason to exist" turned out to be the product's biggest friction.
  • The tech for meaningful per-page human intervention isn't the product. A reader correcting raw machine-translation output, block by block, is neither what most users want nor where the quality leverage is (that is in the OCR/translation models and an optional LLM polish pass — see spec.md §8, M3). Surfacing a correct/incorrect decision the user is poorly placed to make added burden without commensurate quality.
  • An automatic service is a cleaner promise. "Upload, pay a known price, get the whole book" is a product anyone can understand; "apprentice the machine page by page" is not.

2. D1 — No human review/approval gate

Recommendation. Removed. The page lifecycle is now Pending → Processing → Approved, where Approved is reached by the system auto-approving a cleanly-processed page — there is no human approve / reject / edit-before-approve, and no confirm/correct of the detected source language.

Options considered.

OptionVerdict
(a) Remove the gate entirely — fully automaticChosen. Matches the PO's product call; lowest friction; a clear upfront-price promise.
(b) Keep the gate but default it to auto-approve, opt-in to review❌ Carries the entire review UI + endpoints as dead weight for a path nobody is meant to take; invites drift and confusion about the "real" product.
(c) Keep per-page review, soften it (batch-approve)❌ Still asks the user to make per-book decisions; does not solve the decision-burden problem the PO raised.

Trade-offs. We give up the (theoretical) per-page human quality safety net. We accept this: the quality lever is the models + an optional polish pass, not a reader's block-by-block edits. The AwaitingReview / AwaitingApproval enum members were originally retained for back-compat with any project persisted under the old model — the automatic flow never entered them.

Update (2026-06-27). Those vestigial states were removed entirely (along with PageStatus.Rejected): ProjectStatus is now Created · Calibrating · Processing · Complete · Failed, PageStatus is Pending · Processing · Approved · Failed, and the AwaitingReview queue kind / lifecycle bucket / status filter are gone. The product owner directed the full removal once the DB held no pre-pivot records. Cancellation (Cancelling/Cancelled) and a possible explicit Paused state are tracked separately (see §7).

What changed in code. The approve / reject / edit-translation / confirm-source-language endpoints and their state-machine transitions were removed; ProcessNextBatchAsync now auto-confirms a completed batch instead of parking pages for review.


3. D2 — Automatic batch escalation (calibrate first, then auto-advance)

Recommendation. The batch ladder survives; only its trigger changed. The flow still starts narrow — a single calibration page — and widens 1 → 5 → 25 → 100 → rest. What changed: each completed batch auto-confirms (increments ApprovalCount, which BatchPolicy.NextBatchSize reads to widen the next batch) and the next batch is enqueued automatically by IBatchAutoAdvancer (BookTranslation.Core/Abstractions/IBatchAutoAdvancer.cs, implemented in BookTranslation.Infrastructure/Jobs/BatchAutoAdvancer.cs) driven from the JobProcessor, with the Worker as a backstop so an in-flight book reaches completion even if the API process churns.

The project state machine becomes:

Created ──Normalize──► Calibrating ──ProcessNextBatch (1 page, auto-confirm)──► Processing
   Processing ──auto-advanced ProcessNextBatch (5 → 25 → 100 → rest, each auto-confirms)──► Processing …
   Processing ──(no Pending pages left)──► Complete

Options considered.

OptionVerdict
(a) Keep the calibrate-narrow ladder, advance it automaticallyChosen. Keeps the proven "don't bulk-process before the first page looks sane" instinct and the resumable per-batch transitions, while removing the human pause.
(b) Drop the ladder, process the whole book in one batch❌ Loses the cheap early signal (a totally broken OCR config is caught after 1 page, not after 1000) and the granular resumability; no upside once the human gate is gone.

Trade-offs. The "calibration page" no longer gives a human a look before scale — it is now purely a system warm-up / early-failure signal. We keep it because it is nearly free and preserves the batch-granular resumable transitions; removing it bought nothing.


4. D3 — Affordability is the only gate (+ retry)

Recommendation. The only thing that pauses an in-flight book is money. The pre-commit cost estimate (#1375) plus the wallet are the sole brake. When the next batch would exceed the balance, the auto-advance pauses cleanly at Processingnot an error — and the UI shows the "Add credit" CTA (#1396); topping up resumes the chain exactly where it stopped. The one remaining explicit recovery control is retry of a Failed page (Failed → Processing), owning the affordance #1340 referenced and #1367 stories.

Options considered.

OptionVerdict
(a) Pause cleanly + "Add credit" + auto-resume on top-upChosen. Treats running out of credit as an expected state, not a failure; resumable by construction.
(b) Hard-fail the project when over balance❌ Punishes a normal, recoverable situation; loses work / confuses the user.
(c) Let it overdraw and bill later❌ Unacceptable for a prepaid wallet model; invites abuse and disputes.

Trade-offs. A long book can stop midway if the wallet runs dry — but that is the desired behaviour for a prepaid service, and the clean pause + one-click top-up makes it a non-event. The upfront estimate (#1375) is what keeps this rare: the user commits knowing the projected cost.


5. D4 — Read-only reading experience + single completion notification

Recommendation. The review screen is now a read-only reading view. The user pages through the translation (each page's original scan beside its English), sees per-page status, and exports — there are no approve / reject / edit decision buttons. The completion notification fires once, when the whole book finishes ("Translation ready"), replacing the old per-batch "a batch is ready for your review" notification (#1352, reframed).

Trade-offs. Fewer touch-points means the user gets one clear "it's done" signal instead of a stream of per-batch prompts — consistent with the hands-off product. Resume-where-you-left-off (#1353) stays, but now it resumes reading, not reviewing.


6. Explicitly preserved (NOT removed by this pivot)

The pivot is surgical — it removes the human gate, not the engine. These all survive unchanged in intent:

  • The resumable state machine. Every operation is still one discrete, guarded, persisted transition; project.json is still the authoritative resumable state; a fresh process still continues from disk. Auto-advance chains transitions; it does not make them implicit.
  • The calibrate-first batch ladder. 1 → 5 → 25 → 100 → rest, capped to remaining Pending pages. BatchPolicy is untouched.
  • The spend / affordability gate. The estimate-vs-balance cost gate and the credit wallet are now the primary (and only) gate, not a secondary one.
  • Failed-page retry. The one explicit recovery control (Failed → Processing).
  • The per-page pipeline. normalize → layout → OCR → language detect → block-by-block translate → assemble → export, all as in spec.md §4.

7. Out of scope / future

  • Per-page-range selection — "upload a PDF and translate only pages X–Y / specific pages" (#1386, #1376). The automatic flow currently translates the whole uploaded book; selecting a sub-range to pay for is a separate, future enhancement, not part of this pivot.
  • An additional cost-estimate requirement — any tightening of the upfront estimate (e.g. a hard confirm step, per-file actual-vs-estimate reconciliation beyond #1397–#1399) is tracked as a separate PBI, not folded in here.
  • Translation-quality controls — the optional LLM polish pass and per-book OCR-engine choice (Kraken vs Surya for historical type) remain M3 work in spec.md §8; they are the real quality lever now that per-page human correction is gone.

8. Impact on existing docs + tickets

  • spec.md — §1 goal, §2 principles, §3 state machine (project + page diagrams), §4 pipeline step 6, the batch-ladder note, §7 API table (approve/reject removed, retry surfaced), §8 M1 description, and §9 testing table were rewritten to the automatic model.
  • user-stories.md — product-intent header, the Reader/Translator persona, Feature #1365 (renamed Core Translation & Reading Experience; #1366 edit-before-approve and #1368 confirm-source-language retired; #1367 retry survives), the retro-documented flows in §6 (approve/reject removed; read-only reading + auto-advance documented), #1340/#1352 queue + notification wording, and the onboarding gap.
  • CLAUDE.md / README.md — the top-line one-liners that described a "human approval gate between every batch escalation" were corrected to the automatic-service model; the Worker description changed from "continues approved projects, never approves" to "auto-advances in-flight projects to completion."
  • Feature #1365 premise ("the human-in-the-loop quality gate is the product's reason to exist") is retired; this PBI subsumes the auto-advance work.