diff --git a/enterprise-style-package-provenance-guard/README.md b/enterprise-style-package-provenance-guard/README.md
new file mode 100644
index 00000000..a51cb97d
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/README.md
@@ -0,0 +1,18 @@
+# Enterprise Style Package Provenance Guard
+
+This module adds a focused Enterprise Tooling export-pipeline guard for journal and funder formatting plugins. It validates synthetic style packages before institution-scale JATS, DOCX, or LaTeX exports are released.
+
+The guard checks approved plugin versions, required export-format coverage, template checksum parity, citation-style parity, DOI/ORCID/version-history preservation, validation recency, reviewer signoff, generated output provenance digests, and private field leakage in style previews.
+
+## Commands
+
+```bash
+npm run check
+npm test
+npm run demo
+npm run verify-video
+```
+
+`npm run demo` writes reviewer artifacts to `reports/`, including JSON packets, a Markdown report, an SVG summary, and a short H.264 MP4 demo.
+
+Synthetic data only. No live repositories, journal systems, funder portals, credentials, private manuscripts, external APIs, payment systems, or payout-account settings are used.
diff --git a/enterprise-style-package-provenance-guard/demo.js b/enterprise-style-package-provenance-guard/demo.js
new file mode 100644
index 00000000..487a114e
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/demo.js
@@ -0,0 +1,50 @@
+const fs = require("node:fs");
+const path = require("node:path");
+const { evaluateStylePackage, renderMarkdownReport, renderSvgSummary } = require("./index");
+const { cleanPacket, riskyPacket } = require("./sample-data");
+
+const reportsDir = path.join(__dirname, "reports");
+fs.mkdirSync(reportsDir, { recursive: true });
+
+const cleanEvaluation = evaluateStylePackage(cleanPacket);
+const riskyEvaluation = evaluateStylePackage(riskyPacket);
+
+fs.writeFileSync(
+ path.join(reportsDir, "clean-style-package.json"),
+ `${JSON.stringify({ input: cleanPacket, evaluation: cleanEvaluation }, null, 2)}\n`
+);
+fs.writeFileSync(
+ path.join(reportsDir, "risky-style-package.json"),
+ `${JSON.stringify({ input: riskyPacket, evaluation: riskyEvaluation }, null, 2)}\n`
+);
+fs.writeFileSync(
+ path.join(reportsDir, "style-package-provenance-report.md"),
+ renderMarkdownReport(riskyPacket, riskyEvaluation)
+);
+fs.writeFileSync(
+ path.join(reportsDir, "summary.svg"),
+ renderSvgSummary(riskyEvaluation)
+);
+fs.writeFileSync(
+ path.join(reportsDir, "demo-script.txt"),
+ [
+ "Enterprise style package provenance guard demo",
+ "",
+ `Clean packet decision: ${cleanEvaluation.summary.decision}`,
+ `Clean audit digest: ${cleanEvaluation.summary.auditDigest}`,
+ "",
+ `Risky packet decision: ${riskyEvaluation.summary.decision}`,
+ `Risky finding count: ${riskyEvaluation.summary.findingCount}`,
+ `Risky audit digest: ${riskyEvaluation.summary.auditDigest}`,
+ "",
+ "The risky packet demonstrates a formatting plugin drift before JATS/DOCX/LaTeX export: unapproved plugin version, missing formats, checksum drift, citation mismatch, stale validation, missing signoff, metadata preservation gaps, and private preview-field leakage.",
+ ""
+ ].join("\n")
+);
+
+console.log(JSON.stringify({
+ cleanDecision: cleanEvaluation.summary.decision,
+ riskyDecision: riskyEvaluation.summary.decision,
+ riskyFindings: riskyEvaluation.summary.findingCount,
+ report: "reports/style-package-provenance-report.md"
+}, null, 2));
diff --git a/enterprise-style-package-provenance-guard/index.js b/enterprise-style-package-provenance-guard/index.js
new file mode 100644
index 00000000..13905813
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/index.js
@@ -0,0 +1,356 @@
+const crypto = require("node:crypto");
+
+function asArray(value) {
+ return Array.isArray(value) ? value : [];
+}
+
+function stableJson(value) {
+ if (Array.isArray(value)) {
+ return `[${value.map(stableJson).join(",")}]`;
+ }
+ if (value && typeof value === "object") {
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
+ }
+ return JSON.stringify(value);
+}
+
+function sha256(value) {
+ return crypto.createHash("sha256").update(stableJson(value)).digest("hex");
+}
+
+function toDate(value) {
+ const parsed = new Date(value || "");
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
+}
+
+function daysBetween(laterValue, earlierValue) {
+ const later = toDate(laterValue);
+ const earlier = toDate(earlierValue);
+ if (!later || !earlier) {
+ return null;
+ }
+ return Math.floor((later.getTime() - earlier.getTime()) / (24 * 60 * 60 * 1000));
+}
+
+function severityRank(severity) {
+ return { critical: 4, high: 3, medium: 2, low: 1 }[severity] || 0;
+}
+
+function addFinding(findings, severity, code, message, refs, action) {
+ findings.push({
+ severity,
+ code,
+ message,
+ refs: asArray(refs),
+ action
+ });
+}
+
+function isSemver(value) {
+ return /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/.test(String(value || ""));
+}
+
+function normalizedSet(values) {
+ return new Set(asArray(values).map((value) => String(value).trim().toLowerCase()).filter(Boolean));
+}
+
+function setDifference(required, actual) {
+ const actualSet = normalizedSet(actual);
+ return asArray(required).filter((value) => !actualSet.has(String(value).trim().toLowerCase()));
+}
+
+function evaluateStylePackage(packet) {
+ const findings = [];
+ const reviewDate = packet.reviewDate || new Date().toISOString().slice(0, 10);
+ const stylePackages = asArray(packet.stylePackages);
+ const approvedPlugins = new Map(asArray(packet.approvedPlugins).map((plugin) => [plugin.id, plugin]));
+ const requiredFormats = asArray(packet.requiredExportFormats);
+ const packageSummaries = [];
+
+ if (stylePackages.length === 0) {
+ addFinding(
+ findings,
+ "critical",
+ "STYLE_PACKAGE_EMPTY",
+ "No enterprise formatting style packages were supplied for export review.",
+ [packet.institutionId || "institution"],
+ "attach_style_packages_before_export_release"
+ );
+ }
+
+ for (const stylePackage of stylePackages) {
+ const refs = [stylePackage.id || "style-package"];
+ const plugin = approvedPlugins.get(stylePackage.pluginId);
+ const pluginVersion = String(stylePackage.pluginVersion || "");
+ const target = stylePackage.target || {};
+
+ if (!plugin) {
+ addFinding(
+ findings,
+ "critical",
+ "PLUGIN_NOT_APPROVED",
+ `${stylePackage.id || "style package"} uses plugin ${stylePackage.pluginId || "unknown"} without enterprise approval.`,
+ refs,
+ "route_plugin_for_enterprise_approval"
+ );
+ }
+
+ if (!isSemver(pluginVersion)) {
+ addFinding(
+ findings,
+ "high",
+ "PLUGIN_VERSION_NOT_PINNED",
+ `${stylePackage.id || "style package"} is missing a pinned semantic plugin version.`,
+ refs,
+ "pin_plugin_version_before_export"
+ );
+ } else if (plugin && !asArray(plugin.allowedVersions).includes(pluginVersion)) {
+ addFinding(
+ findings,
+ "high",
+ "PLUGIN_VERSION_NOT_APPROVED",
+ `${stylePackage.id || "style package"} uses ${pluginVersion}, which is not in the approved plugin version list.`,
+ refs,
+ "promote_or_replace_approved_plugin_version"
+ );
+ }
+
+ const missingFormats = setDifference(requiredFormats, stylePackage.formats);
+ if (missingFormats.length > 0) {
+ addFinding(
+ findings,
+ "high",
+ "EXPORT_FORMAT_COVERAGE_GAP",
+ `${stylePackage.id || "style package"} is missing required export formats: ${missingFormats.join(", ")}.`,
+ refs,
+ "add_required_export_format_templates"
+ );
+ }
+
+ const templateChecks = asArray(stylePackage.templates);
+ if (templateChecks.length === 0) {
+ addFinding(
+ findings,
+ "high",
+ "TEMPLATE_MANIFEST_MISSING",
+ `${stylePackage.id || "style package"} has no template checksum manifest.`,
+ refs,
+ "attach_template_checksum_manifest"
+ );
+ }
+
+ for (const template of templateChecks) {
+ if (!template.expectedChecksum || !template.actualChecksum) {
+ addFinding(
+ findings,
+ "medium",
+ "TEMPLATE_CHECKSUM_INCOMPLETE",
+ `${template.path || stylePackage.id || "template"} lacks both expected and actual checksums.`,
+ refs,
+ "record_expected_and_actual_template_checksums"
+ );
+ } else if (template.expectedChecksum !== template.actualChecksum) {
+ addFinding(
+ findings,
+ "critical",
+ "TEMPLATE_CHECKSUM_DRIFT",
+ `${template.path || stylePackage.id || "template"} checksum differs from the approved style package manifest.`,
+ refs,
+ "block_export_until_template_is_rebuilt_from_approved_source"
+ );
+ }
+ }
+
+ if (String(stylePackage.citationStyle || "").toLowerCase() !== String(target.citationStyle || "").toLowerCase()) {
+ addFinding(
+ findings,
+ "high",
+ "CITATION_STYLE_MISMATCH",
+ `${stylePackage.id || "style package"} uses ${stylePackage.citationStyle || "unknown"} citations for ${target.name || "target"} which requires ${target.citationStyle || "unknown"}.`,
+ refs,
+ "select_target_approved_citation_style"
+ );
+ }
+
+ const metadata = stylePackage.metadataPreservation || {};
+ const missingMetadata = [
+ ["DOI", metadata.doi],
+ ["ORCID", metadata.orcid],
+ ["version history", metadata.versionHistory],
+ ["license", metadata.license],
+ ["funder award", metadata.funderAward]
+ ].filter(([, present]) => present !== true).map(([label]) => label);
+ if (missingMetadata.length > 0) {
+ addFinding(
+ findings,
+ "high",
+ "EXPORT_METADATA_PRESERVATION_GAP",
+ `${stylePackage.id || "style package"} does not preserve ${missingMetadata.join(", ")} metadata across export formats.`,
+ refs,
+ "preserve_required_publication_metadata"
+ );
+ }
+
+ const validationAge = daysBetween(reviewDate, stylePackage.lastValidatedAt);
+ if (validationAge === null || validationAge > Number(packet.maxValidationAgeDays || 90)) {
+ addFinding(
+ findings,
+ "medium",
+ "STYLE_VALIDATION_STALE",
+ `${stylePackage.id || "style package"} style validation is ${validationAge === null ? "missing" : `${validationAge} days old`}.`,
+ refs,
+ "rerun_style_export_validation"
+ );
+ }
+
+ const signoff = stylePackage.reviewerSignoff || {};
+ if (!signoff.reviewer || signoff.status !== "approved") {
+ addFinding(
+ findings,
+ "high",
+ "STYLE_SIGNOFF_MISSING",
+ `${stylePackage.id || "style package"} lacks approved enterprise reviewer signoff.`,
+ refs,
+ "obtain_enterprise_style_reviewer_signoff"
+ );
+ }
+
+ const generatedOutputs = asArray(stylePackage.generatedOutputs);
+ const missingOutputDigest = generatedOutputs.filter((output) => !output.provenanceDigest || !output.builtFromTemplateChecksum);
+ if (missingOutputDigest.length > 0) {
+ addFinding(
+ findings,
+ "medium",
+ "OUTPUT_PROVENANCE_DIGEST_MISSING",
+ `${stylePackage.id || "style package"} has ${missingOutputDigest.length} generated outputs without build provenance digests.`,
+ refs,
+ "record_output_build_provenance_digests"
+ );
+ }
+
+ if (asArray(stylePackage.previewFields).some((field) => field.private === true && field.exported === true)) {
+ addFinding(
+ findings,
+ "critical",
+ "PRIVATE_FIELD_EXPORTED_IN_STYLE_PREVIEW",
+ `${stylePackage.id || "style package"} exports private internal style-preview fields.`,
+ refs,
+ "remove_private_preview_fields_from_export"
+ );
+ }
+
+ packageSummaries.push({
+ id: stylePackage.id,
+ pluginId: stylePackage.pluginId,
+ pluginVersion,
+ target: target.name,
+ formatCount: asArray(stylePackage.formats).length,
+ templateCount: templateChecks.length,
+ validationAgeDays: validationAge,
+ outputCount: generatedOutputs.length
+ });
+ }
+
+ findings.sort((a, b) => severityRank(b.severity) - severityRank(a.severity) || a.code.localeCompare(b.code));
+ const decision = findings.some((finding) => severityRank(finding.severity) >= 4)
+ ? "hold_enterprise_style_exports"
+ : findings.some((finding) => severityRank(finding.severity) >= 3)
+ ? "revise_style_package_before_export"
+ : findings.some((finding) => finding.severity === "medium")
+ ? "release_after_style_validation_refresh"
+ : "release_enterprise_style_exports";
+
+ const summary = {
+ institutionId: packet.institutionId,
+ reviewDate,
+ decision,
+ stylePackagesReviewed: stylePackages.length,
+ findingCount: findings.length,
+ highOrCriticalFindings: findings.filter((finding) => severityRank(finding.severity) >= 3).length
+ };
+ const auditDigest = `sha256:${sha256({ summary, findings, packageSummaries }).slice(0, 16)}`;
+
+ return {
+ summary: {
+ ...summary,
+ auditDigest
+ },
+ findings,
+ packageSummaries,
+ requiredExportFormats: requiredFormats
+ };
+}
+
+function renderMarkdownReport(packet, evaluation) {
+ const lines = [
+ `# Enterprise Style Package Provenance Report`,
+ "",
+ `Institution: ${packet.institutionId}`,
+ `Review date: ${evaluation.summary.reviewDate}`,
+ `Decision: ${evaluation.summary.decision}`,
+ `Audit digest: ${evaluation.summary.auditDigest}`,
+ "",
+ "## Style Packages",
+ "",
+ "| Package | Target | Plugin | Formats | Templates | Validation age |",
+ "| --- | --- | --- | ---: | ---: | ---: |"
+ ];
+
+ for (const item of evaluation.packageSummaries) {
+ lines.push(`| ${item.id} | ${item.target || "unknown"} | ${item.pluginId}@${item.pluginVersion || "unknown"} | ${item.formatCount} | ${item.templateCount} | ${item.validationAgeDays === null ? "missing" : `${item.validationAgeDays}d`} |`);
+ }
+
+ lines.push("", "## Findings", "");
+ if (evaluation.findings.length === 0) {
+ lines.push("No findings.");
+ } else {
+ for (const finding of evaluation.findings) {
+ lines.push(`- **${finding.severity.toUpperCase()} ${finding.code}**: ${finding.message} Action: \`${finding.action}\`.`);
+ }
+ }
+
+ lines.push("", "## Required Export Formats", "");
+ for (const format of evaluation.requiredExportFormats) {
+ lines.push(`- ${format}`);
+ }
+ lines.push("");
+ return lines.join("\n");
+}
+
+function renderSvgSummary(evaluation) {
+ const width = 920;
+ const height = 420;
+ const critical = evaluation.findings.filter((finding) => finding.severity === "critical").length;
+ const high = evaluation.findings.filter((finding) => finding.severity === "high").length;
+ const medium = evaluation.findings.filter((finding) => finding.severity === "medium").length;
+ const bars = [
+ ["critical", critical, "#b91c1c"],
+ ["high", high, "#dc2626"],
+ ["medium", medium, "#d97706"]
+ ];
+ const barSvg = bars.map(([label, count, color], index) => {
+ const y = 150 + index * 72;
+ const barWidth = Math.max(16, Math.min(520, count * 54));
+ return `${label}${count}`;
+ }).join("");
+
+ return [
+ ``,
+ ""
+ ].join("\n");
+}
+
+module.exports = {
+ evaluateStylePackage,
+ renderMarkdownReport,
+ renderSvgSummary,
+ stableJson,
+ sha256
+};
diff --git a/enterprise-style-package-provenance-guard/make-demo-video.js b/enterprise-style-package-provenance-guard/make-demo-video.js
new file mode 100644
index 00000000..167891f6
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/make-demo-video.js
@@ -0,0 +1,91 @@
+const fs = require("node:fs");
+const path = require("node:path");
+const { spawnSync } = require("node:child_process");
+const { evaluateStylePackage } = require("./index");
+const { cleanPacket, riskyPacket } = require("./sample-data");
+
+const reportsDir = path.join(__dirname, "reports");
+const framesDir = path.join(reportsDir, "frames");
+fs.mkdirSync(framesDir, { recursive: true });
+
+const clean = evaluateStylePackage(cleanPacket);
+const risky = evaluateStylePackage(riskyPacket);
+const width = 960;
+const height = 540;
+const frames = 72;
+const fps = 18;
+
+function setPixel(buffer, x, y, r, g, b) {
+ if (x < 0 || y < 0 || x >= width || y >= height) {
+ return;
+ }
+ const offset = (y * width + x) * 3;
+ buffer[offset] = r;
+ buffer[offset + 1] = g;
+ buffer[offset + 2] = b;
+}
+
+function fillRect(buffer, x, y, w, h, r, g, b) {
+ for (let row = y; row < y + h; row += 1) {
+ for (let col = x; col < x + w; col += 1) {
+ setPixel(buffer, col, row, r, g, b);
+ }
+ }
+}
+
+function writeFrame(index, progress) {
+ const buffer = Buffer.alloc(width * height * 3, 250);
+ fillRect(buffer, 0, 0, width, height, 248, 250, 252);
+ fillRect(buffer, 56, 48, 848, 444, 255, 255, 255);
+ fillRect(buffer, 56, 48, 848, 8, 17, 24, 39);
+
+ const cleanWidth = Math.floor(328 * Math.min(1, progress * 1.7));
+ const riskyWidth = Math.floor(328 * Math.max(0, (progress - 0.18) * 1.45));
+ fillRect(buffer, 104, 116, 328, 64, 226, 232, 240);
+ fillRect(buffer, 104, 116, cleanWidth, 64, 22, 163, 74);
+ fillRect(buffer, 528, 116, 328, 64, 226, 232, 240);
+ fillRect(buffer, 528, 116, riskyWidth, 64, 220, 38, 38);
+
+ for (let i = 0; i < clean.summary.stylePackagesReviewed; i += 1) {
+ fillRect(buffer, 128 + i * 84, 246, 56, 94, 16, 185, 129);
+ fillRect(buffer, 136 + i * 84, 256, 40, 18, 255, 255, 255);
+ fillRect(buffer, 136 + i * 84, 286, 40, 10, 255, 255, 255);
+ }
+
+ for (let i = 0; i < Math.min(12, risky.summary.findingCount); i += 1) {
+ const barHeight = 30 + (i % 6) * 18;
+ fillRect(buffer, 548 + i * 24, 386 - barHeight, 18, barHeight, 185, 28, 28);
+ }
+
+ fillRect(buffer, 104, 424, Math.floor(744 * progress), 18, 37, 99, 235);
+ fillRect(buffer, 104, 454, Math.floor(560 * progress), 18, 217, 119, 6);
+
+ const header = Buffer.from(`P6\n${width} ${height}\n255\n`, "ascii");
+ fs.writeFileSync(path.join(framesDir, `frame-${String(index).padStart(3, "0")}.ppm`), Buffer.concat([header, buffer]));
+}
+
+for (let index = 0; index < frames; index += 1) {
+ writeFrame(index, index / (frames - 1));
+}
+
+const output = path.join(reportsDir, "demo.mp4");
+const result = spawnSync(process.env.FFMPEG_PATH || "ffmpeg", [
+ "-y",
+ "-framerate",
+ String(fps),
+ "-i",
+ path.join(framesDir, "frame-%03d.ppm"),
+ "-pix_fmt",
+ "yuv420p",
+ "-movflags",
+ "+faststart",
+ output
+], { stdio: "inherit" });
+
+fs.rmSync(framesDir, { recursive: true, force: true });
+
+if (result.status !== 0) {
+ process.exit(result.status || 1);
+}
+
+console.log(`Wrote ${output}`);
diff --git a/enterprise-style-package-provenance-guard/package.json b/enterprise-style-package-provenance-guard/package.json
new file mode 100644
index 00000000..03267324
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "enterprise-style-package-provenance-guard",
+ "version": "1.0.0",
+ "private": true,
+ "description": "Synthetic enterprise export formatting-plugin provenance guard for SCIBASE enterprise tooling.",
+ "main": "index.js",
+ "scripts": {
+ "check": "node --check index.js && node --check sample-data.js && node --check test.js && node --check demo.js && node --check make-demo-video.js",
+ "test": "node test.js",
+ "demo": "node demo.js && node make-demo-video.js",
+ "verify-video": "ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,width,height,duration,avg_frame_rate -show_entries format=duration,size -of default=noprint_wrappers=1 reports/demo.mp4"
+ },
+ "keywords": [
+ "scibase",
+ "enterprise-tooling",
+ "export-pipeline",
+ "formatting-plugin",
+ "provenance"
+ ],
+ "license": "MIT"
+}
diff --git a/enterprise-style-package-provenance-guard/reports/clean-style-package.json b/enterprise-style-package-provenance-guard/reports/clean-style-package.json
new file mode 100644
index 00000000..82f860d8
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/reports/clean-style-package.json
@@ -0,0 +1,111 @@
+{
+ "input": {
+ "institutionId": "northstar-research-office",
+ "reviewDate": "2026-06-01",
+ "maxValidationAgeDays": 90,
+ "requiredExportFormats": [
+ "JATS",
+ "DOCX",
+ "LaTeX"
+ ],
+ "approvedPlugins": [
+ {
+ "id": "journal-style-pack",
+ "allowedVersions": [
+ "3.4.2",
+ "3.4.3"
+ ],
+ "owner": "enterprise-publication-ops"
+ }
+ ],
+ "stylePackages": [
+ {
+ "id": "cell-reports-2026-style",
+ "pluginId": "journal-style-pack",
+ "pluginVersion": "3.4.3",
+ "target": {
+ "name": "Cell Reports",
+ "citationStyle": "vancouver"
+ },
+ "formats": [
+ "JATS",
+ "DOCX",
+ "LaTeX"
+ ],
+ "citationStyle": "vancouver",
+ "lastValidatedAt": "2026-05-20",
+ "reviewerSignoff": {
+ "reviewer": "pubops-style-reviewer",
+ "status": "approved"
+ },
+ "templates": [
+ {
+ "path": "templates/cell-reports/article.jats.xml",
+ "expectedChecksum": "sha256:6bd2f4c0c2a6",
+ "actualChecksum": "sha256:6bd2f4c0c2a6"
+ },
+ {
+ "path": "templates/cell-reports/manuscript.docx",
+ "expectedChecksum": "sha256:a9f28f1de342",
+ "actualChecksum": "sha256:a9f28f1de342"
+ }
+ ],
+ "metadataPreservation": {
+ "doi": true,
+ "orcid": true,
+ "versionHistory": true,
+ "license": true,
+ "funderAward": true
+ },
+ "generatedOutputs": [
+ {
+ "path": "exports/cell-reports/article.xml",
+ "builtFromTemplateChecksum": "sha256:6bd2f4c0c2a6",
+ "provenanceDigest": "sha256:output-9122"
+ },
+ {
+ "path": "exports/cell-reports/manuscript.docx",
+ "builtFromTemplateChecksum": "sha256:a9f28f1de342",
+ "provenanceDigest": "sha256:output-8227"
+ }
+ ],
+ "previewFields": [
+ {
+ "name": "publicTitle",
+ "exported": true,
+ "private": false
+ }
+ ]
+ }
+ ]
+ },
+ "evaluation": {
+ "summary": {
+ "institutionId": "northstar-research-office",
+ "reviewDate": "2026-06-01",
+ "decision": "release_enterprise_style_exports",
+ "stylePackagesReviewed": 1,
+ "findingCount": 0,
+ "highOrCriticalFindings": 0,
+ "auditDigest": "sha256:3a3a13df45782064"
+ },
+ "findings": [],
+ "packageSummaries": [
+ {
+ "id": "cell-reports-2026-style",
+ "pluginId": "journal-style-pack",
+ "pluginVersion": "3.4.3",
+ "target": "Cell Reports",
+ "formatCount": 3,
+ "templateCount": 2,
+ "validationAgeDays": 12,
+ "outputCount": 2
+ }
+ ],
+ "requiredExportFormats": [
+ "JATS",
+ "DOCX",
+ "LaTeX"
+ ]
+ }
+}
diff --git a/enterprise-style-package-provenance-guard/reports/demo-script.txt b/enterprise-style-package-provenance-guard/reports/demo-script.txt
new file mode 100644
index 00000000..d29b2711
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/reports/demo-script.txt
@@ -0,0 +1,10 @@
+Enterprise style package provenance guard demo
+
+Clean packet decision: release_enterprise_style_exports
+Clean audit digest: sha256:3a3a13df45782064
+
+Risky packet decision: hold_enterprise_style_exports
+Risky finding count: 17
+Risky audit digest: sha256:e519c9e6fe7731dd
+
+The risky packet demonstrates a formatting plugin drift before JATS/DOCX/LaTeX export: unapproved plugin version, missing formats, checksum drift, citation mismatch, stale validation, missing signoff, metadata preservation gaps, and private preview-field leakage.
diff --git a/enterprise-style-package-provenance-guard/reports/demo.mp4 b/enterprise-style-package-provenance-guard/reports/demo.mp4
new file mode 100644
index 00000000..c3717323
Binary files /dev/null and b/enterprise-style-package-provenance-guard/reports/demo.mp4 differ
diff --git a/enterprise-style-package-provenance-guard/reports/risky-style-package.json b/enterprise-style-package-provenance-guard/reports/risky-style-package.json
new file mode 100644
index 00000000..61ee06fc
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/reports/risky-style-package.json
@@ -0,0 +1,292 @@
+{
+ "input": {
+ "institutionId": "northstar-research-office",
+ "reviewDate": "2026-06-01",
+ "maxValidationAgeDays": 90,
+ "requiredExportFormats": [
+ "JATS",
+ "DOCX",
+ "LaTeX"
+ ],
+ "approvedPlugins": [
+ {
+ "id": "journal-style-pack",
+ "allowedVersions": [
+ "3.4.2"
+ ],
+ "owner": "enterprise-publication-ops"
+ }
+ ],
+ "stylePackages": [
+ {
+ "id": "horizon-eu-repository-style",
+ "pluginId": "journal-style-pack",
+ "pluginVersion": "3.5.0",
+ "target": {
+ "name": "Horizon EU grant portal",
+ "citationStyle": "apa"
+ },
+ "formats": [
+ "DOCX"
+ ],
+ "citationStyle": "vancouver",
+ "lastValidatedAt": "2025-12-10",
+ "reviewerSignoff": {
+ "reviewer": "",
+ "status": "draft"
+ },
+ "templates": [
+ {
+ "path": "templates/horizon/report.docx",
+ "expectedChecksum": "sha256:approved-4411",
+ "actualChecksum": "sha256:local-drift-7719"
+ },
+ {
+ "path": "templates/horizon/article.jats.xml",
+ "expectedChecksum": "",
+ "actualChecksum": "sha256:missing-expected"
+ }
+ ],
+ "metadataPreservation": {
+ "doi": true,
+ "orcid": false,
+ "versionHistory": false,
+ "license": true,
+ "funderAward": false
+ },
+ "generatedOutputs": [
+ {
+ "path": "exports/horizon/report.docx",
+ "builtFromTemplateChecksum": "",
+ "provenanceDigest": ""
+ }
+ ],
+ "previewFields": [
+ {
+ "name": "internalReviewerNotes",
+ "exported": true,
+ "private": true
+ }
+ ]
+ },
+ {
+ "id": "unapproved-preprint-style",
+ "pluginId": "community-style-snapshot",
+ "pluginVersion": "latest",
+ "target": {
+ "name": "bioRxiv",
+ "citationStyle": "vancouver"
+ },
+ "formats": [
+ "JATS",
+ "DOCX"
+ ],
+ "citationStyle": "vancouver",
+ "lastValidatedAt": null,
+ "reviewerSignoff": null,
+ "templates": [],
+ "metadataPreservation": {
+ "doi": false,
+ "orcid": false,
+ "versionHistory": false,
+ "license": false,
+ "funderAward": false
+ },
+ "generatedOutputs": []
+ }
+ ]
+ },
+ "evaluation": {
+ "summary": {
+ "institutionId": "northstar-research-office",
+ "reviewDate": "2026-06-01",
+ "decision": "hold_enterprise_style_exports",
+ "stylePackagesReviewed": 2,
+ "findingCount": 17,
+ "highOrCriticalFindings": 13,
+ "auditDigest": "sha256:e519c9e6fe7731dd"
+ },
+ "findings": [
+ {
+ "severity": "critical",
+ "code": "PLUGIN_NOT_APPROVED",
+ "message": "unapproved-preprint-style uses plugin community-style-snapshot without enterprise approval.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "route_plugin_for_enterprise_approval"
+ },
+ {
+ "severity": "critical",
+ "code": "PRIVATE_FIELD_EXPORTED_IN_STYLE_PREVIEW",
+ "message": "horizon-eu-repository-style exports private internal style-preview fields.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "remove_private_preview_fields_from_export"
+ },
+ {
+ "severity": "critical",
+ "code": "TEMPLATE_CHECKSUM_DRIFT",
+ "message": "templates/horizon/report.docx checksum differs from the approved style package manifest.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "block_export_until_template_is_rebuilt_from_approved_source"
+ },
+ {
+ "severity": "high",
+ "code": "CITATION_STYLE_MISMATCH",
+ "message": "horizon-eu-repository-style uses vancouver citations for Horizon EU grant portal which requires apa.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "select_target_approved_citation_style"
+ },
+ {
+ "severity": "high",
+ "code": "EXPORT_FORMAT_COVERAGE_GAP",
+ "message": "horizon-eu-repository-style is missing required export formats: JATS, LaTeX.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "add_required_export_format_templates"
+ },
+ {
+ "severity": "high",
+ "code": "EXPORT_FORMAT_COVERAGE_GAP",
+ "message": "unapproved-preprint-style is missing required export formats: LaTeX.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "add_required_export_format_templates"
+ },
+ {
+ "severity": "high",
+ "code": "EXPORT_METADATA_PRESERVATION_GAP",
+ "message": "horizon-eu-repository-style does not preserve ORCID, version history, funder award metadata across export formats.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "preserve_required_publication_metadata"
+ },
+ {
+ "severity": "high",
+ "code": "EXPORT_METADATA_PRESERVATION_GAP",
+ "message": "unapproved-preprint-style does not preserve DOI, ORCID, version history, license, funder award metadata across export formats.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "preserve_required_publication_metadata"
+ },
+ {
+ "severity": "high",
+ "code": "PLUGIN_VERSION_NOT_APPROVED",
+ "message": "horizon-eu-repository-style uses 3.5.0, which is not in the approved plugin version list.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "promote_or_replace_approved_plugin_version"
+ },
+ {
+ "severity": "high",
+ "code": "PLUGIN_VERSION_NOT_PINNED",
+ "message": "unapproved-preprint-style is missing a pinned semantic plugin version.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "pin_plugin_version_before_export"
+ },
+ {
+ "severity": "high",
+ "code": "STYLE_SIGNOFF_MISSING",
+ "message": "horizon-eu-repository-style lacks approved enterprise reviewer signoff.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "obtain_enterprise_style_reviewer_signoff"
+ },
+ {
+ "severity": "high",
+ "code": "STYLE_SIGNOFF_MISSING",
+ "message": "unapproved-preprint-style lacks approved enterprise reviewer signoff.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "obtain_enterprise_style_reviewer_signoff"
+ },
+ {
+ "severity": "high",
+ "code": "TEMPLATE_MANIFEST_MISSING",
+ "message": "unapproved-preprint-style has no template checksum manifest.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "attach_template_checksum_manifest"
+ },
+ {
+ "severity": "medium",
+ "code": "OUTPUT_PROVENANCE_DIGEST_MISSING",
+ "message": "horizon-eu-repository-style has 1 generated outputs without build provenance digests.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "record_output_build_provenance_digests"
+ },
+ {
+ "severity": "medium",
+ "code": "STYLE_VALIDATION_STALE",
+ "message": "horizon-eu-repository-style style validation is 173 days old.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "rerun_style_export_validation"
+ },
+ {
+ "severity": "medium",
+ "code": "STYLE_VALIDATION_STALE",
+ "message": "unapproved-preprint-style style validation is missing.",
+ "refs": [
+ "unapproved-preprint-style"
+ ],
+ "action": "rerun_style_export_validation"
+ },
+ {
+ "severity": "medium",
+ "code": "TEMPLATE_CHECKSUM_INCOMPLETE",
+ "message": "templates/horizon/article.jats.xml lacks both expected and actual checksums.",
+ "refs": [
+ "horizon-eu-repository-style"
+ ],
+ "action": "record_expected_and_actual_template_checksums"
+ }
+ ],
+ "packageSummaries": [
+ {
+ "id": "horizon-eu-repository-style",
+ "pluginId": "journal-style-pack",
+ "pluginVersion": "3.5.0",
+ "target": "Horizon EU grant portal",
+ "formatCount": 1,
+ "templateCount": 2,
+ "validationAgeDays": 173,
+ "outputCount": 1
+ },
+ {
+ "id": "unapproved-preprint-style",
+ "pluginId": "community-style-snapshot",
+ "pluginVersion": "latest",
+ "target": "bioRxiv",
+ "formatCount": 2,
+ "templateCount": 0,
+ "validationAgeDays": null,
+ "outputCount": 0
+ }
+ ],
+ "requiredExportFormats": [
+ "JATS",
+ "DOCX",
+ "LaTeX"
+ ]
+ }
+}
diff --git a/enterprise-style-package-provenance-guard/reports/style-package-provenance-report.md b/enterprise-style-package-provenance-guard/reports/style-package-provenance-report.md
new file mode 100644
index 00000000..6868aad1
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/reports/style-package-provenance-report.md
@@ -0,0 +1,39 @@
+# Enterprise Style Package Provenance Report
+
+Institution: northstar-research-office
+Review date: 2026-06-01
+Decision: hold_enterprise_style_exports
+Audit digest: sha256:e519c9e6fe7731dd
+
+## Style Packages
+
+| Package | Target | Plugin | Formats | Templates | Validation age |
+| --- | --- | --- | ---: | ---: | ---: |
+| horizon-eu-repository-style | Horizon EU grant portal | journal-style-pack@3.5.0 | 1 | 2 | 173d |
+| unapproved-preprint-style | bioRxiv | community-style-snapshot@latest | 2 | 0 | missing |
+
+## Findings
+
+- **CRITICAL PLUGIN_NOT_APPROVED**: unapproved-preprint-style uses plugin community-style-snapshot without enterprise approval. Action: `route_plugin_for_enterprise_approval`.
+- **CRITICAL PRIVATE_FIELD_EXPORTED_IN_STYLE_PREVIEW**: horizon-eu-repository-style exports private internal style-preview fields. Action: `remove_private_preview_fields_from_export`.
+- **CRITICAL TEMPLATE_CHECKSUM_DRIFT**: templates/horizon/report.docx checksum differs from the approved style package manifest. Action: `block_export_until_template_is_rebuilt_from_approved_source`.
+- **HIGH CITATION_STYLE_MISMATCH**: horizon-eu-repository-style uses vancouver citations for Horizon EU grant portal which requires apa. Action: `select_target_approved_citation_style`.
+- **HIGH EXPORT_FORMAT_COVERAGE_GAP**: horizon-eu-repository-style is missing required export formats: JATS, LaTeX. Action: `add_required_export_format_templates`.
+- **HIGH EXPORT_FORMAT_COVERAGE_GAP**: unapproved-preprint-style is missing required export formats: LaTeX. Action: `add_required_export_format_templates`.
+- **HIGH EXPORT_METADATA_PRESERVATION_GAP**: horizon-eu-repository-style does not preserve ORCID, version history, funder award metadata across export formats. Action: `preserve_required_publication_metadata`.
+- **HIGH EXPORT_METADATA_PRESERVATION_GAP**: unapproved-preprint-style does not preserve DOI, ORCID, version history, license, funder award metadata across export formats. Action: `preserve_required_publication_metadata`.
+- **HIGH PLUGIN_VERSION_NOT_APPROVED**: horizon-eu-repository-style uses 3.5.0, which is not in the approved plugin version list. Action: `promote_or_replace_approved_plugin_version`.
+- **HIGH PLUGIN_VERSION_NOT_PINNED**: unapproved-preprint-style is missing a pinned semantic plugin version. Action: `pin_plugin_version_before_export`.
+- **HIGH STYLE_SIGNOFF_MISSING**: horizon-eu-repository-style lacks approved enterprise reviewer signoff. Action: `obtain_enterprise_style_reviewer_signoff`.
+- **HIGH STYLE_SIGNOFF_MISSING**: unapproved-preprint-style lacks approved enterprise reviewer signoff. Action: `obtain_enterprise_style_reviewer_signoff`.
+- **HIGH TEMPLATE_MANIFEST_MISSING**: unapproved-preprint-style has no template checksum manifest. Action: `attach_template_checksum_manifest`.
+- **MEDIUM OUTPUT_PROVENANCE_DIGEST_MISSING**: horizon-eu-repository-style has 1 generated outputs without build provenance digests. Action: `record_output_build_provenance_digests`.
+- **MEDIUM STYLE_VALIDATION_STALE**: horizon-eu-repository-style style validation is 173 days old. Action: `rerun_style_export_validation`.
+- **MEDIUM STYLE_VALIDATION_STALE**: unapproved-preprint-style style validation is missing. Action: `rerun_style_export_validation`.
+- **MEDIUM TEMPLATE_CHECKSUM_INCOMPLETE**: templates/horizon/article.jats.xml lacks both expected and actual checksums. Action: `record_expected_and_actual_template_checksums`.
+
+## Required Export Formats
+
+- JATS
+- DOCX
+- LaTeX
diff --git a/enterprise-style-package-provenance-guard/reports/summary.svg b/enterprise-style-package-provenance-guard/reports/summary.svg
new file mode 100644
index 00000000..eab0c277
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/reports/summary.svg
@@ -0,0 +1,8 @@
+
diff --git a/enterprise-style-package-provenance-guard/sample-data.js b/enterprise-style-package-provenance-guard/sample-data.js
new file mode 100644
index 00000000..8cf3a188
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/sample-data.js
@@ -0,0 +1,161 @@
+const cleanPacket = {
+ institutionId: "northstar-research-office",
+ reviewDate: "2026-06-01",
+ maxValidationAgeDays: 90,
+ requiredExportFormats: ["JATS", "DOCX", "LaTeX"],
+ approvedPlugins: [
+ {
+ id: "journal-style-pack",
+ allowedVersions: ["3.4.2", "3.4.3"],
+ owner: "enterprise-publication-ops"
+ }
+ ],
+ stylePackages: [
+ {
+ id: "cell-reports-2026-style",
+ pluginId: "journal-style-pack",
+ pluginVersion: "3.4.3",
+ target: {
+ name: "Cell Reports",
+ citationStyle: "vancouver"
+ },
+ formats: ["JATS", "DOCX", "LaTeX"],
+ citationStyle: "vancouver",
+ lastValidatedAt: "2026-05-20",
+ reviewerSignoff: {
+ reviewer: "pubops-style-reviewer",
+ status: "approved"
+ },
+ templates: [
+ {
+ path: "templates/cell-reports/article.jats.xml",
+ expectedChecksum: "sha256:6bd2f4c0c2a6",
+ actualChecksum: "sha256:6bd2f4c0c2a6"
+ },
+ {
+ path: "templates/cell-reports/manuscript.docx",
+ expectedChecksum: "sha256:a9f28f1de342",
+ actualChecksum: "sha256:a9f28f1de342"
+ }
+ ],
+ metadataPreservation: {
+ doi: true,
+ orcid: true,
+ versionHistory: true,
+ license: true,
+ funderAward: true
+ },
+ generatedOutputs: [
+ {
+ path: "exports/cell-reports/article.xml",
+ builtFromTemplateChecksum: "sha256:6bd2f4c0c2a6",
+ provenanceDigest: "sha256:output-9122"
+ },
+ {
+ path: "exports/cell-reports/manuscript.docx",
+ builtFromTemplateChecksum: "sha256:a9f28f1de342",
+ provenanceDigest: "sha256:output-8227"
+ }
+ ],
+ previewFields: [
+ {
+ name: "publicTitle",
+ exported: true,
+ private: false
+ }
+ ]
+ }
+ ]
+};
+
+const riskyPacket = {
+ institutionId: "northstar-research-office",
+ reviewDate: "2026-06-01",
+ maxValidationAgeDays: 90,
+ requiredExportFormats: ["JATS", "DOCX", "LaTeX"],
+ approvedPlugins: [
+ {
+ id: "journal-style-pack",
+ allowedVersions: ["3.4.2"],
+ owner: "enterprise-publication-ops"
+ }
+ ],
+ stylePackages: [
+ {
+ id: "horizon-eu-repository-style",
+ pluginId: "journal-style-pack",
+ pluginVersion: "3.5.0",
+ target: {
+ name: "Horizon EU grant portal",
+ citationStyle: "apa"
+ },
+ formats: ["DOCX"],
+ citationStyle: "vancouver",
+ lastValidatedAt: "2025-12-10",
+ reviewerSignoff: {
+ reviewer: "",
+ status: "draft"
+ },
+ templates: [
+ {
+ path: "templates/horizon/report.docx",
+ expectedChecksum: "sha256:approved-4411",
+ actualChecksum: "sha256:local-drift-7719"
+ },
+ {
+ path: "templates/horizon/article.jats.xml",
+ expectedChecksum: "",
+ actualChecksum: "sha256:missing-expected"
+ }
+ ],
+ metadataPreservation: {
+ doi: true,
+ orcid: false,
+ versionHistory: false,
+ license: true,
+ funderAward: false
+ },
+ generatedOutputs: [
+ {
+ path: "exports/horizon/report.docx",
+ builtFromTemplateChecksum: "",
+ provenanceDigest: ""
+ }
+ ],
+ previewFields: [
+ {
+ name: "internalReviewerNotes",
+ exported: true,
+ private: true
+ }
+ ]
+ },
+ {
+ id: "unapproved-preprint-style",
+ pluginId: "community-style-snapshot",
+ pluginVersion: "latest",
+ target: {
+ name: "bioRxiv",
+ citationStyle: "vancouver"
+ },
+ formats: ["JATS", "DOCX"],
+ citationStyle: "vancouver",
+ lastValidatedAt: null,
+ reviewerSignoff: null,
+ templates: [],
+ metadataPreservation: {
+ doi: false,
+ orcid: false,
+ versionHistory: false,
+ license: false,
+ funderAward: false
+ },
+ generatedOutputs: []
+ }
+ ]
+};
+
+module.exports = {
+ cleanPacket,
+ riskyPacket
+};
diff --git a/enterprise-style-package-provenance-guard/test.js b/enterprise-style-package-provenance-guard/test.js
new file mode 100644
index 00000000..2ede4c32
--- /dev/null
+++ b/enterprise-style-package-provenance-guard/test.js
@@ -0,0 +1,31 @@
+const assert = require("node:assert/strict");
+const { evaluateStylePackage, sha256 } = require("./index");
+const { cleanPacket, riskyPacket } = require("./sample-data");
+
+const clean = evaluateStylePackage(cleanPacket);
+assert.equal(clean.summary.decision, "release_enterprise_style_exports");
+assert.equal(clean.summary.findingCount, 0);
+assert.equal(clean.summary.stylePackagesReviewed, 1);
+assert.ok(clean.summary.auditDigest.startsWith("sha256:"));
+
+const risky = evaluateStylePackage(riskyPacket);
+assert.equal(risky.summary.decision, "hold_enterprise_style_exports");
+assert.equal(risky.summary.stylePackagesReviewed, 2);
+assert.ok(risky.summary.findingCount >= 10);
+assert.ok(risky.summary.highOrCriticalFindings >= 7);
+
+const findingCodes = new Set(risky.findings.map((finding) => finding.code));
+assert.ok(findingCodes.has("TEMPLATE_CHECKSUM_DRIFT"));
+assert.ok(findingCodes.has("PRIVATE_FIELD_EXPORTED_IN_STYLE_PREVIEW"));
+assert.ok(findingCodes.has("PLUGIN_NOT_APPROVED"));
+assert.ok(findingCodes.has("PLUGIN_VERSION_NOT_PINNED"));
+assert.ok(findingCodes.has("EXPORT_METADATA_PRESERVATION_GAP"));
+assert.ok(findingCodes.has("CITATION_STYLE_MISMATCH"));
+assert.ok(findingCodes.has("EXPORT_FORMAT_COVERAGE_GAP"));
+
+const firstDigest = evaluateStylePackage(riskyPacket).summary.auditDigest;
+const secondDigest = evaluateStylePackage(riskyPacket).summary.auditDigest;
+assert.equal(firstDigest, secondDigest);
+assert.equal(sha256({ b: 2, a: 1 }), sha256({ a: 1, b: 2 }));
+
+console.log("enterprise style package provenance guard tests passed");