Product content quality checks
Updated 2026-09-05
Separate structural validity from product meaning. In a local 40-row Japanese and German case, field checks passed while AI review still found Japanese wording to correct.
Define the quality contract before generation
Write acceptance rules for each field. Identity and revision fields should match their source. Editable text should use the requested locale, include required information and respect the destination format. Claims need supporting evidence. A single pass or fail label is too coarse to explain which condition blocked a product.
Keep machine-checkable defects separate from editorial judgments. Missing text and identifier drift can be localized deterministically. Whether a translation overstates a benefit requires context and qualified review. Route each issue to the person or system that can resolve it, and keep the result attached to the candidate revision.
| Check | Useful evidence | Follow-up review |
|---|---|---|
| Identity and source revision | Exact field comparison | Natural translation |
| Protected values | Typed scalar equality | Correct source specification |
| Markup and placeholders | Parser and token counts | Accurate product claims |
| Claim review | Assertion-to-source mapping | Store import success |
| Destination read-back | Approved-versus-stored comparison | Commercial performance |
Compare protected values after assembly
Generate only permitted text fields, then assemble the candidate record using protected values copied from the source. Run a second comparison on that assembled record. This catches mapper mistakes as well as accidental edits made during review.
The illustrative JavaScript example expects schema-validated objects with scalar protected values. It detects missing, extra or changed protected keys and a stale source revision, returning stable issue codes. Put schema and value validation before this helper, and route a structurally valid candidate to editorial review afterward.
function checkProtected(source, candidate) {
const issues = [];
if (candidate.sourceRevision !== source.sourceRevision) {
issues.push({ code: "STALE_SOURCE", field: "sourceRevision" });
}
const keys = new Set([
...Object.keys(source.protected),
...Object.keys(candidate.protected),
]);
for (const field of keys) {
const hasSource = Object.prototype.hasOwnProperty.call(source.protected, field);
const hasCandidate = Object.prototype.hasOwnProperty.call(candidate.protected, field);
if (!hasSource || !hasCandidate ||
!Object.is(source.protected[field], candidate.protected[field])) {
issues.push({ code: "PROTECTED_FIELD_CHANGED", field });
}
}
return issues;
}Keep number formatting separate from values
A localized number may look different while representing the same stored quantity. MDN documents Intl.NumberFormat for locale-aware presentation. Apply formatting after the authoritative value is selected; do not ask a language model to recreate a price from a rendered currency string.
Define units alongside numeric values, including which unit belongs to each dimension. If conversion is authorized, use a deterministic conversion rule and retain the original representation. Do not compare only the digits in a sentence: two identical numbers with different units can describe different products. Missing units should block approval until the source is resolved.
Validate placeholder multiplicity and markup
Use the application's template parser to collect placeholder tokens from source and candidate. Compare counts, not only a set of names; a duplicated token can break a sentence or an application even when every original token still appears. Keep format-specific escaping rules at the destination boundary.
The following small check accepts already extracted tokens. It does not attempt a universal placeholder regular expression. For HTML, parse the document fragment and compare permitted structure and links separately. WordPress's escaping guidance is relevant for custom rendering, but escaping alone cannot prove that the content preserved its intended meaning.
function samePlaceholderCounts(sourceTokens, candidateTokens) {
const counts = new Map();
for (const token of sourceTokens) {
counts.set(token, (counts.get(token) ?? 0) + 1);
}
for (const token of candidateTokens) {
if (!counts.has(token)) return false;
counts.set(token, counts.get(token) - 1);
}
return [...counts.values()].every((count) => count === 0);
}Case: valid fields, wording still needing correction
A translation agent explicitly configured for gpt-5.6-luna with xhigh reasoning produced 20 Japanese and 20 German patches from 20 synthetic products. Deterministic schema, identity and protected-field checks passed for all 40 assembled rows. Price, currency, material and dimensions were copied from the source; generated patches could change only title and description for the identified SKU and locale.
The untouched Japanese patches also pass the structural validator. AI review nevertheless identified the two wording issues below and revised their descriptions. This is why checking a protected material field cannot establish that prose describes the material accurately. Compare each consequential assertion with its source, even after every schema check is green.

| Synthetic product | Source meaning | Japanese AI-review correction |
|---|---|---|
| DEMO-003: sketch pad | Cardboard backing | Removed an unsupported implication of corrugated cardboard |
| DEMO-010: storage basket | Two side handles in total | Clarified the total handle count to remove ambiguity |
Test the review export as well as the import
OWASP describes spreadsheet formula injection and notes that safety transformations differ across consumers. Treat supplier and generated cells as untrusted. Use a reviewed serialization policy for the actual spreadsheet tool and inspect the saved artifact, not just an in-memory table.
Keep machine imports separate from review files. A prefix added for safe human viewing must not silently change an identifier or public description during import. Validate encoding, quote handling and expected row identities with a parser. Keep the untouched source so changes introduced by a spreadsheet editor can be identified and corrected.
Bind approval to the exact candidate
Store a candidate revision or hash with factual approval and language approval. Any later edit should invalidate the relevant approval until it is reviewed. The final publisher must compare the current source revision too, since an unchanged translation may be stale after a product specification changes.
In the case artifacts, the corrected Japanese patches and German patches assemble into rows marked review_status: unreviewed. Both reports retain translation_semantic_review: pending. AI-assisted correction is a revision step, not native-speaker or merchant sign-off. Preserve raw and revised candidates, then have the appropriate reviewer approve the exact text that would enter an import package.
Reproduce the checks and keep their scope clear
The local case's test exercises source-field preservation, duplicate SKU, missing SKU and a forbidden price override. Read-only reassembly of the saved Japanese and German patches reproduces both validated outputs. For a broader catalog, add checks for your own placeholder grammar, markup and revision policy; the illustrative helpers above are separate examples, not the validator used for these 40 rows.
This was a Luna-configured local translation case, with no Astra or gateway call and no real store import. The tool exposed no API usage, request IDs or billing; both outputs retain null usage and cost. Use the structural result to advance to semantic review, then test the authorized store adapter separately.
node --test examples/commerce-localization-case/case.test.mjsFAQ
Can a JSON-valid response still be unsafe to import?
Yes. Valid syntax does not establish correct identifiers, source freshness, supported fields, accurate claims or approval. Validate those contracts independently.
Why compare protected fields if the model cannot edit them?
The assembly, mapping and review stages can still introduce mistakes. A post-assembly comparison checks the actual record being prepared for delivery.
Can I validate claims with a list of allowed words?
A word list may flag some issues, but it cannot establish the meaning or strength of an assertion. Review the sentence against its product evidence.
Does matching placeholder names suffice?
Compare multiplicity too, using the real template parser. A repeated or missing token can be a defect even when the set of names looks familiar.
What did the 40-row case establish?
The saved patches assembled with no recorded structural failures and retained source-controlled product fields. Japanese wording still needed two AI-review corrections, and semantic approval remains pending for both languages.