An image handoff becomes difficult when the accepted file and the review note describe different revisions. A useful manifest keeps those identities together. It should answer which source was edited, which export was inspected, and which review decision applies to that export. A filename alone can be ambiguous after a file has been replaced.
Define a small review contract
Give the asset and each revision separate identifiers. The asset identifier names the product view; the revision identifier names one particular exported result. Record the exported filename and a short acceptance note. Use explicit states such as pending, accepted, and changes_requested. An accepted result should have a meaningful note that explains what was checked.
Do not treat a timestamp as a unique identifier. Two exports can occur within the same clock resolution, and different machines may disagree about time. An application-generated revision identifier can be independent of the human-readable export time. Keep the original source available so that a later reviewer can compare shape, color, and fine details.
Validate the handoff before using it
The following JavaScript example validates an application-owned review manifest. Its string lengths are example limits for this small document, rather than rules for image formats. Save it as review-manifest.mjs and run it with Node.js. It does not open or decode an image and cannot certify visual quality.
import assert from 'node:assert/strict';
export function acceptedExports(manifest) {
if (manifest?.version !== 1 || !Array.isArray(manifest.assets)) {
throw new Error('Unsupported review manifest.');
}
const seen = new Set();
return manifest.assets.map((asset) => {
const fields = ['assetId', 'revisionId', 'filename', 'note'];
if (fields.some((name) => typeof asset?.[name] !== 'string' ||
!asset[name].trim() || asset[name].length > 500)) {
throw new Error('A complete review record is required.');
}
const key = JSON.stringify([asset.assetId, asset.revisionId]);
if (seen.has(key)) throw new Error('Duplicate asset revision.');
seen.add(key);
if (asset.state !== 'accepted') throw new Error('Review is incomplete.');
return { assetId: asset.assetId, revisionId: asset.revisionId,
filename: asset.filename, note: asset.note };
});
}
const record = { assetId: 'mug-front', revisionId: 'rev-b7',
filename: 'mug-front_rev-b7.png', state: 'accepted',
note: 'Handle opening and rim checked on light and dark surfaces.' };
assert.equal(acceptedExports({ version: 1, assets: [record] }).length, 1);
assert.throws(() => acceptedExports({ version: 1,
assets: [record, record] }), /Duplicate/);
assert.throws(() => acceptedExports({ version: 1,
assets: [{ ...record, state: 'pending' }] }), /incomplete/);Inspect the exact exported file
A review manifest is useful only if the filename still refers to the inspected bytes. In a production workflow, store an immutable export or add a checksum and verify it when the file is transferred. Do not replace the file silently after acceptance. A changed export needs a new revision and a fresh decision.
For a background-removal step performed with RemovePhotoBG, inspect the downloaded result before marking the revision accepted. Check openings, thin handles, reflections, and any shadow that should remain. The review note should describe observations rather than simply say that an editing tool was used.
Keep failures visible
A missing review, duplicate revision, or incomplete note should stop the handoff. Do not change those states automatically to accepted merely to finish a batch. Return the affected asset to review while retaining already accepted results. For a larger system, add a bounded manifest size and a persistent history of who made each decision; this short example supplies neither authorization nor an audit service.
Read the Node.js assertion documentation for the checks used by the example. Run the fixture after changing the manifest contract, and add a case for each failure your own workflow needs to distinguish.