{"record":{"id":"79f1628c59d52482","repo":"paperclipai/paperclip","slug":"public-viewer-page-differs-from-the-trusted-shell","errorCode":null,"errorMessage":"Public viewer page differs from the trusted shell","messagePattern":"Public viewer page differs from the trusted shell","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/public-eval-viewer.mjs","lineNumber":230,"sourceCode":"      if (item.evidenceRef) fields(item.evidenceRef, \"section recordId\");\n      if (\n        item.kind === \"tool_activity\" &&\n        (JSON.stringify(item.input) !==\n          JSON.stringify({\n            detail: \"Arguments withheld from public replay.\",\n          }) ||\n          Object.keys(item.result).sort().join(\",\") !== \"detail,outcome\" ||\n          item.result.detail !== \"Tool payload withheld from public replay.\")\n      )\n        throw new Error(\"Public replay contains a raw tool payload\");\n    }\n  }\n}\n\nexport function validatePublicViewerPage(content, trustedIndex) {\n  const match = content.match(PUBLIC_VIEWER_DATA);\n  if (!match || publicViewerShell(trustedIndex, match[1]) !== content)\n    throw new Error(\"Public viewer page differs from the trusted shell\");\n  const payload = JSON.parse(match[1]);\n  validatePublicChatPayload(payload);\n  return payload;\n}\n","sourceCodeStart":212,"sourceCodeEnd":235,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/public-eval-viewer.mjs#L212-L235","documentation":"Thrown by validatePublicViewerPage when the served public viewer HTML does not byte-match the trusted shell regenerated via publicViewerShell(trustedIndex, embeddedData). The page must be exactly the trusted index shell with only the embedded PUBLIC_VIEWER_DATA JSON substituted; any other modification is rejected to prevent tampering with the public page.","triggerScenarios":"Validating HTML content where the PUBLIC_VIEWER_DATA regex does not match, or where re-rendering the shell around the extracted JSON differs from the actual content (extra scripts, changed markup, different JSON escaping).","commonSituations":"Deploy pipeline injects extra tags (analytics, CSP meta) into the page; index.html was rebuilt from a different trusted version; a minifier reformatted the HTML or the embedded JSON.","solutions":["Regenerate the viewer page using publicViewerShell with the current trusted index so it byte-matches.","Remove any post-processing steps (injected scripts, minification) that alter the public page after generation.","Ensure the embedded JSON serialization (key order, escaping) matches what publicViewerShell expects."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const m = content.match(PUBLIC_VIEWER_DATA);\nif (!m || publicViewerShell(trustedIndex, m[1]) !== content) throw new Error('viewer page drifted from trusted shell');","typeGuard":null,"tryCatchPattern":"try { validatePublicViewerPage(html, trustedIndex); } catch (e) { if (e.message.includes('trusted shell')) { console.error('public page was modified after generation; regenerate it'); process.exit(1); } throw e; }","preventionTips":["Generate the page exclusively via publicViewerShell; forbid post-generation HTML edits.","Disable deploy-time HTML injections (analytics/CDN transforms) for this artifact.","Pin the trusted index version used for regeneration in CI."],"tags":["validation","html","integrity"],"backgroundTag":"checksum-mismatch","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}