@nebulacomponents/citable 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +16 -3
  3. package/dist/universal/.agents/skills/citable/SKILL.md +66 -1
  4. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  5. package/dist/universal/.agents/skills/citable/manifest.json +9 -6
  6. package/dist/universal/.agents/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  7. package/dist/universal/.agents/skills/citable/schemas/finding.schema.json +69 -0
  8. package/dist/universal/.agents/skills/citable/schemas/remediation-verification.schema.json +98 -0
  9. package/dist/universal/.agents/skills/citable/schemas/sow.schema.json +92 -0
  10. package/dist/universal/.claude/agents/citable/manifest.json +2 -2
  11. package/dist/universal/.claude/skills/citable/SKILL.md +66 -1
  12. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  13. package/dist/universal/.claude/skills/citable/manifest.json +9 -6
  14. package/dist/universal/.claude/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  15. package/dist/universal/.claude/skills/citable/schemas/finding.schema.json +69 -0
  16. package/dist/universal/.claude/skills/citable/schemas/remediation-verification.schema.json +98 -0
  17. package/dist/universal/.claude/skills/citable/schemas/sow.schema.json +92 -0
  18. package/dist/universal/.cursor/skills/citable/SKILL.md +66 -1
  19. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  20. package/dist/universal/.cursor/skills/citable/manifest.json +9 -6
  21. package/dist/universal/.cursor/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  22. package/dist/universal/.cursor/skills/citable/schemas/finding.schema.json +69 -0
  23. package/dist/universal/.cursor/skills/citable/schemas/remediation-verification.schema.json +98 -0
  24. package/dist/universal/.cursor/skills/citable/schemas/sow.schema.json +92 -0
  25. package/dist/universal/.gemini/skills/citable/SKILL.md +66 -1
  26. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  27. package/dist/universal/.gemini/skills/citable/manifest.json +9 -6
  28. package/dist/universal/.gemini/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  29. package/dist/universal/.gemini/skills/citable/schemas/finding.schema.json +69 -0
  30. package/dist/universal/.gemini/skills/citable/schemas/remediation-verification.schema.json +98 -0
  31. package/dist/universal/.gemini/skills/citable/schemas/sow.schema.json +92 -0
  32. package/dist/universal/.github/skills/citable/SKILL.md +66 -1
  33. package/dist/universal/.github/skills/citable/VERSION +1 -1
  34. package/dist/universal/.github/skills/citable/manifest.json +9 -6
  35. package/dist/universal/.github/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  36. package/dist/universal/.github/skills/citable/schemas/finding.schema.json +69 -0
  37. package/dist/universal/.github/skills/citable/schemas/remediation-verification.schema.json +98 -0
  38. package/dist/universal/.github/skills/citable/schemas/sow.schema.json +92 -0
  39. package/dist/universal/.kiro/skills/citable/SKILL.md +66 -1
  40. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  41. package/dist/universal/.kiro/skills/citable/manifest.json +9 -6
  42. package/dist/universal/.kiro/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  43. package/dist/universal/.kiro/skills/citable/schemas/finding.schema.json +69 -0
  44. package/dist/universal/.kiro/skills/citable/schemas/remediation-verification.schema.json +98 -0
  45. package/dist/universal/.kiro/skills/citable/schemas/sow.schema.json +92 -0
  46. package/dist/universal/.opencode/skills/citable/SKILL.md +66 -1
  47. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  48. package/dist/universal/.opencode/skills/citable/manifest.json +9 -6
  49. package/dist/universal/.opencode/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  50. package/dist/universal/.opencode/skills/citable/schemas/finding.schema.json +69 -0
  51. package/dist/universal/.opencode/skills/citable/schemas/remediation-verification.schema.json +98 -0
  52. package/dist/universal/.opencode/skills/citable/schemas/sow.schema.json +92 -0
  53. package/dist/universal/.pi/agent/skills/citable/SKILL.md +66 -1
  54. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  55. package/dist/universal/.pi/agent/skills/citable/manifest.json +9 -6
  56. package/dist/universal/.pi/agent/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  57. package/dist/universal/.pi/agent/skills/citable/schemas/finding.schema.json +69 -0
  58. package/dist/universal/.pi/agent/skills/citable/schemas/remediation-verification.schema.json +98 -0
  59. package/dist/universal/.pi/agent/skills/citable/schemas/sow.schema.json +92 -0
  60. package/dist/universal/.qoder/skills/citable/SKILL.md +66 -1
  61. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  62. package/dist/universal/.qoder/skills/citable/manifest.json +9 -6
  63. package/dist/universal/.qoder/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  64. package/dist/universal/.qoder/skills/citable/schemas/finding.schema.json +69 -0
  65. package/dist/universal/.qoder/skills/citable/schemas/remediation-verification.schema.json +98 -0
  66. package/dist/universal/.qoder/skills/citable/schemas/sow.schema.json +92 -0
  67. package/dist/universal/.rovodev/skills/citable/SKILL.md +66 -1
  68. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  69. package/dist/universal/.rovodev/skills/citable/manifest.json +9 -6
  70. package/dist/universal/.rovodev/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  71. package/dist/universal/.rovodev/skills/citable/schemas/finding.schema.json +69 -0
  72. package/dist/universal/.rovodev/skills/citable/schemas/remediation-verification.schema.json +98 -0
  73. package/dist/universal/.rovodev/skills/citable/schemas/sow.schema.json +92 -0
  74. package/dist/universal/.trae/skills/citable/SKILL.md +66 -1
  75. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  76. package/dist/universal/.trae/skills/citable/manifest.json +9 -6
  77. package/dist/universal/.trae/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  78. package/dist/universal/.trae/skills/citable/schemas/finding.schema.json +69 -0
  79. package/dist/universal/.trae/skills/citable/schemas/remediation-verification.schema.json +98 -0
  80. package/dist/universal/.trae/skills/citable/schemas/sow.schema.json +92 -0
  81. package/dist/universal/.trae-cn/skills/citable/SKILL.md +66 -1
  82. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  83. package/dist/universal/.trae-cn/skills/citable/manifest.json +9 -6
  84. package/dist/universal/.trae-cn/skills/citable/schemas/cli-output-envelope.schema.json +30 -0
  85. package/dist/universal/.trae-cn/skills/citable/schemas/finding.schema.json +69 -0
  86. package/dist/universal/.trae-cn/skills/citable/schemas/remediation-verification.schema.json +98 -0
  87. package/dist/universal/.trae-cn/skills/citable/schemas/sow.schema.json +92 -0
  88. package/dist/universal/manifest.json +112 -76
  89. package/package.json +1 -1
  90. package/schemas/cli-output-envelope.schema.json +30 -0
  91. package/schemas/finding.schema.json +69 -0
  92. package/schemas/remediation-verification.schema.json +98 -0
  93. package/schemas/sow.schema.json +92 -0
  94. package/skill/SKILL.md +66 -1
  95. package/src/analysis/behavioral.js +126 -0
  96. package/src/analysis/croAudit.js +302 -0
  97. package/src/analysis/croRoadmap.js +121 -0
  98. package/src/analysis/eeat.js +300 -0
  99. package/src/analysis/funnelAnalysis.js +171 -0
  100. package/src/analysis/iceMatrix.js +205 -0
  101. package/src/analysis/offpage.js +228 -0
  102. package/src/analysis/readiness.js +253 -0
  103. package/src/analysis/saliency.js +119 -0
  104. package/src/analysis/schemaRecommendations.js +173 -0
  105. package/src/analysis/strategicRoadmap.js +148 -0
  106. package/src/cli/index.js +418 -9
  107. package/src/commands/answerEngineReadiness.js +48 -0
  108. package/src/commands/audit.js +2 -2
  109. package/src/commands/auditBacklinks.js +79 -0
  110. package/src/commands/ciWorkflow.js +63 -0
  111. package/src/commands/compatibility.js +205 -0
  112. package/src/commands/context.js +2 -1
  113. package/src/commands/croBacklog.js +182 -0
  114. package/src/commands/croSuite.js +156 -0
  115. package/src/commands/edgeRules.js +80 -4
  116. package/src/commands/edgeSecurity.js +192 -0
  117. package/src/commands/executive.js +6 -0
  118. package/src/commands/executiveCro.js +30 -0
  119. package/src/commands/executiveSearch.js +28 -0
  120. package/src/commands/experimentGuardrails.js +213 -0
  121. package/src/commands/goldenCorpus.js +155 -0
  122. package/src/commands/implementationKit.js +202 -0
  123. package/src/commands/inspectCro.js +67 -0
  124. package/src/commands/inspectEeat.js +53 -0
  125. package/src/commands/planExperiment.js +52 -0
  126. package/src/commands/previewCro.js +241 -0
  127. package/src/commands/prioritize.js +42 -6
  128. package/src/commands/remediate.js +461 -0
  129. package/src/commands/roadmapCmd.js +69 -0
  130. package/src/commands/schemaCmd.js +10 -2
  131. package/src/commands/sowCmd.js +67 -0
  132. package/src/commands/sweep.js +357 -0
  133. package/src/commands/verifyRemediation.js +204 -0
  134. package/src/commands/visualRegression.js +165 -0
  135. package/src/components/index.js +556 -0
  136. package/src/detectors/cro.js +48 -0
  137. package/src/detectors/framework.js +31 -1
  138. package/src/reporting/executiveCroReport.js +731 -0
  139. package/src/reporting/executiveExport.js +175 -1
  140. package/src/reporting/executiveSearchReport.js +704 -0
  141. package/src/sow/admissibilityGate.js +194 -0
  142. package/src/sow/generateSow.js +762 -0
@@ -0,0 +1,762 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { buildContext } from '../commands/context.js';
4
+ import { selectDetectors } from '../detectors/index.js';
5
+ import { runDetectors, indexTargets } from '../detectors/framework.js';
6
+ import { evaluateScopeAdmissibility } from './admissibilityGate.js';
7
+ import { readJson, nowIso } from '../shared/io.js';
8
+
9
+ /**
10
+ * Generate an Enterprise-Grade Statement of Work (SOW) from SEO, AEO, GEO, SERP, and CRO findings.
11
+ * Forces strict traceability: Evidence -> Obligation -> Acceptance Test.
12
+ */
13
+ export async function generateSow(root, {
14
+ target,
15
+ baseUrl,
16
+ refDate,
17
+ runId,
18
+ client = 'Acme Corporation',
19
+ clientContact = 'client-procurement@acme.test',
20
+ supplier = 'Nebula Components & Citable Practice',
21
+ supplierContact = 'advisory@nebulacomponents.test',
22
+ budget = 45000,
23
+ termDays = 90,
24
+ inScopeProperties = [],
25
+ minIceScore = 8.0,
26
+ sowId = null,
27
+ } = {}) {
28
+ const generatedAt = nowIso();
29
+ const sowIdentifier = sowId || `SOW-${Date.now().toString(36).toUpperCase()}`;
30
+
31
+ let findings = [];
32
+ let sitePages = [];
33
+
34
+ // Attempt building live or target context if target provided
35
+ if (target) {
36
+ try {
37
+ const ctx = await buildContext(root, { target, baseUrl, refDate });
38
+ if (ctx?.site) {
39
+ sitePages = indexTargets(ctx);
40
+ const detectors = selectDetectors({ scopes: ['technical', 'seo', 'aeo', 'geo', 'schema', 'entity'] });
41
+ const res = runDetectors(detectors, ctx);
42
+ findings = res.findings;
43
+ }
44
+ } catch (e) {
45
+ // Non-blocking fallback
46
+ }
47
+ }
48
+
49
+ // If runId provided or prior runs exist in .citable/runs, load recorded evidence
50
+ const runsDir = path.join(root, '.citable', 'runs');
51
+ let loadedRunId = runId;
52
+ if (!loadedRunId && fs.existsSync(runsDir)) {
53
+ const runs = fs.readdirSync(runsDir).filter((d) => !d.startsWith('.'));
54
+ if (runs.length > 0) loadedRunId = runs[runs.length - 1];
55
+ }
56
+
57
+ if (loadedRunId) {
58
+ const runPath = path.join(runsDir, loadedRunId);
59
+ const findPath = path.join(runPath, 'findings.json');
60
+ if (fs.existsSync(findPath) && findings.length === 0) {
61
+ try { findings = readJson(findPath); } catch {}
62
+ }
63
+ }
64
+
65
+ // If no findings exist from live run, supply standard baseline audit findings for SOW generation
66
+ if (findings.length === 0) {
67
+ findings = [
68
+ {
69
+ detector_id: 'TECH-001',
70
+ discipline: ['technical'],
71
+ classification: { severity: 'critical', confidence: 'deterministic' },
72
+ subject: { identifier: 'https://example.test/', url: 'https://example.test/' },
73
+ observation: { summary: 'Render-blocking JavaScript bundle degrades Mobile LCP to 4.2s', evidence: ['EVD-CWV-001'] },
74
+ remediation: { preferred: 'Implement asynchronous resource loading and preconnect headers' },
75
+ verification: { detector_to_rerun: 'TECH-001', method: 'Static CWV inspection and HTTP header probe' },
76
+ ice_score: 14.5,
77
+ },
78
+ {
79
+ detector_id: 'CRO-007',
80
+ discipline: ['cro'],
81
+ classification: { severity: 'high', confidence: 'deterministic' },
82
+ subject: { identifier: 'https://example.test/checkout', url: 'https://example.test/checkout' },
83
+ observation: { summary: 'Checkout form inputs lack HTML5 autocomplete attributes, increasing manual mobile entry by 68%', evidence: ['EVD-CRO-007'] },
84
+ remediation: { preferred: 'Inject standard autocomplete attributes (autocomplete="email", autocomplete="name", autocomplete="tel")' },
85
+ verification: { detector_to_rerun: 'CRO-007', method: 'DOM inspection and AST patch verification' },
86
+ ice_score: 18.0,
87
+ },
88
+ {
89
+ detector_id: 'CRO-013',
90
+ discipline: ['cro'],
91
+ classification: { severity: 'high', confidence: 'deterministic' },
92
+ subject: { identifier: 'https://example.test/checkout', url: 'https://example.test/checkout' },
93
+ observation: { summary: 'Dedicated checkout funnel contains 14 external header navigation links creating distraction leaks', evidence: ['EVD-CRO-013'] },
94
+ remediation: { preferred: 'Deploy enclosed distraction-free checkout layout stripping non-essential navigation' },
95
+ verification: { detector_to_rerun: 'CRO-013', method: 'Navigation link count verification' },
96
+ ice_score: 12.0,
97
+ },
98
+ {
99
+ detector_id: 'ANS-001',
100
+ discipline: ['aeo'],
101
+ classification: { severity: 'high', confidence: 'deterministic' },
102
+ subject: { identifier: 'https://example.test/saas/pricing.html', url: 'https://example.test/saas/pricing.html' },
103
+ observation: { summary: 'Commercial pricing questions lack direct-extract definition passages under 75 words', evidence: ['EVD-ANS-001'] },
104
+ remediation: { preferred: 'Restructure FAQ headings with immediate concise copular answer passages' },
105
+ verification: { detector_to_rerun: 'ANS-001', method: 'Passage length and question-answer extraction test' },
106
+ ice_score: 11.0,
107
+ },
108
+ {
109
+ detector_id: 'SCHEMA-001',
110
+ discipline: ['schema'],
111
+ classification: { severity: 'medium', confidence: 'deterministic' },
112
+ subject: { identifier: 'https://example.test/pricing', url: 'https://example.test/pricing' },
113
+ observation: { summary: 'Commercial FAQ content lacks FAQPage JSON-LD schema markup', evidence: ['EVD-SCH-001'] },
114
+ remediation: { preferred: 'Deploy validated Schema.org FAQPage structured data' },
115
+ verification: { detector_to_rerun: 'SCHEMA-001', method: 'JSON-LD schema validation gate' },
116
+ ice_score: 9.5,
117
+ },
118
+ // Inadmissible exploratory finding (for demonstrating the gate)
119
+ {
120
+ detector_id: 'EXP-GEO-999',
121
+ discipline: ['geo'],
122
+ classification: { severity: 'low', confidence: 'experimental', finding_type: 'experimental' },
123
+ subject: { identifier: 'https://unrelated-blog.test/post-1', url: 'https://unrelated-blog.test/post-1' },
124
+ observation: { summary: 'Speculative model hallucination on third-party forum', evidence: [] },
125
+ remediation: { preferred: 'Consult external legal counsel regarding public forum sentiment' },
126
+ ice_score: 2.0,
127
+ },
128
+ ];
129
+ }
130
+
131
+ const effectiveScopeProps = inScopeProperties.length > 0
132
+ ? inScopeProperties
133
+ : [baseUrl || 'https://example.test'];
134
+
135
+ // -------------------------------------------------------------
136
+ // THE ADMISSIBILITY GATE (Filter findings to contractual scope)
137
+ // -------------------------------------------------------------
138
+ const gateResult = evaluateScopeAdmissibility(findings, {
139
+ inScopeProperties: effectiveScopeProps,
140
+ minIceScore,
141
+ });
142
+
143
+ const admitted = gateResult.admitted_requirements;
144
+
145
+ // Group admitted requirements into Work Packages
146
+ const wpMap = new Map();
147
+ for (const item of admitted) {
148
+ if (!wpMap.has(item.work_package_id)) {
149
+ wpMap.set(item.work_package_id, {
150
+ work_package_id: item.work_package_id,
151
+ name: item.work_package_name,
152
+ deliverable_id: item.deliverable_id,
153
+ owner: item.owner,
154
+ requirements: [],
155
+ });
156
+ }
157
+ wpMap.get(item.work_package_id).requirements.push(item);
158
+ }
159
+ const workPackages = Array.from(wpMap.values());
160
+
161
+ // 25. THE FINAL TRACEABILITY MATRIX
162
+ // Mapping Finding -> Recommendation -> SOW Requirement -> Deliverable -> Acceptance Test -> Owner -> Evidence
163
+ const traceabilityMatrix = admitted.map((item) => ({
164
+ finding_id: item.finding_id,
165
+ recommendation: item.recommendation,
166
+ sow_requirement_id: item.sow_requirement_id,
167
+ work_package_id: item.work_package_id,
168
+ deliverable_id: item.deliverable_id,
169
+ acceptance_test_id: item.acceptance_test_id,
170
+ owner: item.owner,
171
+ evidence_id: item.evidence_id,
172
+ severity: item.severity,
173
+ target_subject: item.subject,
174
+ acceptance_criteria: item.acceptance_test,
175
+ }));
176
+
177
+ // Deliverables definitions
178
+ const deliverables = workPackages.map((wp, idx) => ({
179
+ deliverable_id: wp.deliverable_id,
180
+ work_package_id: wp.work_package_id,
181
+ title: `${wp.name} Implementation & Verification Package`,
182
+ artifact_type: 'Code Patches, AST Snapshots, and Evidence Package',
183
+ format: 'Git Pull Request + JSON Verification Receipt',
184
+ owner: wp.owner,
185
+ delivery_criteria: `All ${wp.requirements.length} requirements must pass automated verification (exit code 0) with zero regressions on Core Web Vitals.`,
186
+ }));
187
+
188
+ // Acceptance criteria definitions
189
+ const acceptanceCriteria = admitted.map((item) => ({
190
+ acceptance_test_id: item.acceptance_test_id,
191
+ sow_requirement_id: item.sow_requirement_id,
192
+ test_description: item.acceptance_test,
193
+ validation_method: 'citable verify remediation closed-loop command',
194
+ pass_threshold: '100% detector defect resolution on audited surface',
195
+ evidence_required: `Deterministic before-and-after observation JSON matching ${item.evidence_id}`,
196
+ }));
197
+
198
+ // Commercial structure
199
+ const feePerWp = Math.round(budget / (workPackages.length || 1));
200
+ const commercialMilestones = workPackages.map((wp, idx) => ({
201
+ milestone_id: `MILESTONE-0${idx + 1}`,
202
+ work_package_id: wp.work_package_id,
203
+ name: wp.name,
204
+ fee_usd: feePerWp,
205
+ billing_trigger: `Successful customer acceptance sign-off of Deliverable ${wp.deliverable_id}`,
206
+ target_delivery_week: (idx + 1) * 3,
207
+ }));
208
+
209
+ const sow = {
210
+ $schema: 'citable://schemas/sow.schema.json',
211
+ sow_id: sowIdentifier,
212
+ version: '1.0.0',
213
+ title: `Statement of Work: Enterprise Search & Conversion Intelligence Engineering`,
214
+ client: { name: client, contact: clientContact },
215
+ supplier: { name: supplier, contact: supplierContact },
216
+ effective_date: generatedAt.split('T')[0],
217
+ term_days: termDays,
218
+ commercial_total_fee_usd: budget,
219
+
220
+ // Pillar 1: Executive Scope Statement
221
+ executive_scope: {
222
+ business_objective: 'Eliminate deterministic technical search and conversion friction, establish AEO/GEO answer extraction architecture, and deploy governed CRO design remediations with verifiable evidence.',
223
+ in_scope_properties: effectiveScopeProps,
224
+ in_scope_systems: ['Web Front-End Codebase', 'CMS Rendering Layer', 'Search & Conversion Analytics (GSC, GA4, PostHog)', 'Edge Middleware / Reverse Proxy'],
225
+ channels: ['Organic Search (Google, Bing)', 'AI Answer Engines (Perplexity, ChatGPT, Copilot)', 'Direct Conversion Funnels'],
226
+ geographies: ['Global', 'North America (US/CA)', 'European Union (GDPR-compliant surfaces)'],
227
+ organizational_boundaries: 'Applies strictly to customer-owned digital production surfaces; excludes third-party partner portals and non-contracted subdomains.',
228
+ },
229
+
230
+ // Pillar 2: Evidence-to-Work Traceability & Admissibility Gate
231
+ admissibility_gate: {
232
+ total_findings_evaluated: gateResult.summary.total_evaluated,
233
+ admitted_count: gateResult.summary.admitted_count,
234
+ refused_count: gateResult.summary.refused_count,
235
+ admissibility_rate_pct: gateResult.summary.admissibility_rate_pct,
236
+ refusal_log: gateResult.refusal_log,
237
+ methodology: 'Admissibility Gate evaluates findings against 6 strict tests: Evidence Maturity, Scope Boundary, Technical Feasibility, Commercial Materiality, Measurable Acceptance, and Ownership Clarity.',
238
+ },
239
+
240
+ // Pillar 3: Explicit Assumptions, Dependencies, Exclusions & Constraints
241
+ assumptions_and_constraints: {
242
+ assumptions: [
243
+ 'Customer maintains active version control via GitHub or GitLab with standard pull-request workflow.',
244
+ 'Staging environment provides parity with production infrastructure for pre-release verification testing.',
245
+ 'Audited search and conversion telemetry represents normal operating seasonality.',
246
+ ],
247
+ dependencies: [
248
+ 'Customer delivers read-only credentials to Google Search Console and GA4 within 5 business days of effective date.',
249
+ 'Customer engineering performs technical reviews and merges approved pull requests within 48 hours of verification receipt.',
250
+ ],
251
+ exclusions: [
252
+ 'Paid media ad buy management or advertising budget spend.',
253
+ 'Complete brand identity overhaul or custom creative video production.',
254
+ 'Legal, privacy, or regulatory compliance counsel (medical, financial, GDPR legal defense).',
255
+ 'Refactoring core backend transactional databases or proprietary billing engines.',
256
+ ],
257
+ constraints: [
258
+ 'Zero deployment downtime allowed during production release windows.',
259
+ 'Zero regression permitted on Core Web Vitals (Mobile LCP <= 2.5s, CLS <= 0.10, INP <= 200ms).',
260
+ ],
261
+ unresolved_unknowns: [
262
+ 'In-memory citation query volume from ChatGPT search (requires server-side log ingestion phase).',
263
+ 'Post-cookie-consent degradation on regional EU mobile conversions.',
264
+ ],
265
+ },
266
+
267
+ // Pillar 4: Prioritized Work Packages
268
+ work_packages: workPackages,
269
+
270
+ // Pillar 5: Detailed Deliverables
271
+ deliverables,
272
+
273
+ // Pillar 6: Technical Implementation Requirements
274
+ technical_requirements: {
275
+ supported_frameworks: ['React', 'Next.js', 'Vue', 'Nuxt', 'HTML5/Tailwind', 'Astro'],
276
+ git_branching_model: 'citable/remediation-<finding-id>',
277
+ rollback_mechanism: 'Automated atomic snapshot generated in .citable/remediation/snapshots/ prior to file modification',
278
+ access_requirements: ['Read-only git repository access', 'Read-only GSC/GA4 analytics access', 'Staging deploy preview access'],
279
+ },
280
+
281
+ // Pillar 7: Acceptance Criteria
282
+ acceptance_criteria: acceptanceCriteria,
283
+
284
+ // Pillar 8: Baseline & Target-State Metrics
285
+ baseline_and_target_metrics: {
286
+ disclaimer: 'Metrics represent technical readiness, friction eradication, and modeled index targets. In adherence to Citable governance, this SOW never warrants guaranteed ranking or revenue volumes.',
287
+ metrics: [
288
+ { metric: 'Core Web Vitals Render-Blockers', baseline: '1 blocker', target: '0 blockers', validation: 'Lighthouse / static CWV sweep' },
289
+ { metric: 'HTML5 Autocomplete Form Coverage', baseline: '32%', target: '100%', validation: 'AST form field inspection' },
290
+ { metric: 'AEO Direct Answer Extraction Score', baseline: '58 / 100', target: '>= 80 / 100', validation: 'citable inspect readiness' },
291
+ { metric: 'Checkout Distraction Leaks', baseline: '14 header links', target: '0 links (Enclosed)', validation: 'DOM link count' },
292
+ ],
293
+ },
294
+
295
+ // Pillar 9: Experiment Specifications
296
+ experiment_specifications: {
297
+ standard: 'Two-tailed hypothesis testing (alpha = 0.05, 80% statistical power)',
298
+ stopping_criteria: 'Minimum 14 calendar days lock; mandatory daily Sample Ratio Mismatch (SRM) Chi-Square check (p < 0.001 terminates test)',
299
+ guardrails: [
300
+ 'SEO Retention: Variant must preserve all canonical tags, JSON-LD structured data, and meta robots tags',
301
+ 'Performance Guardrail: Mobile LCP must not degrade by > 250ms; CLS must remain <= 0.10',
302
+ ],
303
+ },
304
+
305
+ // Pillar 10: Roles & RACI Matrix
306
+ raci_matrix: [
307
+ { role: 'Customer Executive Sponsor', r: 'Approve SOW, sign off commercial milestones, resolve executive escalations', raci: 'Accountable (A)' },
308
+ { role: 'Customer Lead Engineer', r: 'Review code pull requests, grant repository access, execute production deploy', raci: 'Responsible (R)' },
309
+ { role: 'Supplier Principal Architect', r: 'Design AST patches, author verification receipts, direct technical delivery', raci: 'Responsible (R)' },
310
+ { role: 'Supplier QA & Governance Lead', r: 'Execute admissibility gate, validate acceptance criteria, maintain evidence packages', raci: 'Consulted (C)' },
311
+ ],
312
+
313
+ // Pillar 11: Customer Obligations
314
+ customer_obligations: [
315
+ 'Provide authorized read-only API access to required search and analytics tools within 5 business days.',
316
+ 'Review and respond to delivered Pull Requests and verification packages within 48 business hours.',
317
+ 'Maintain staging environment availability for automated closed-loop verification probes.',
318
+ ],
319
+
320
+ // Pillar 12: Delivery Sequencing & Milestone Schedule
321
+ delivery_schedule: {
322
+ total_duration_weeks: Math.ceil(termDays / 7),
323
+ milestones: commercialMilestones,
324
+ },
325
+
326
+ // Pillar 13: Scope Change-Control Process
327
+ change_control_process: {
328
+ procedure: 'Any expansion of in-scope systems, addition of new domains, or changes to accepted requirements requires a written Scope Change Request (SCR).',
329
+ authorization: 'SCR must be signed by Customer Executive Sponsor and Supplier Practice Lead before work begins.',
330
+ superceding_rules: 'Superseded requirements are archived in .citable/sow/history/ with reason code and date.',
331
+ },
332
+
333
+ // Pillar 14: Risk Register
334
+ risk_register: [
335
+ { id: 'RISK-01', category: 'deployment', description: 'Customer deployment freeze during holiday quarter delays PR merges', mitigation: 'Schedule staging verification ahead of freeze; stage patches in feature flags' },
336
+ { id: 'RISK-02', category: 'platform', description: 'Search engine or AI answer engine algorithmic updates shift third-party citation UI', mitigation: 'Focus on deterministic schema and direct entity corroboration rather than transient UI exploits' },
337
+ { id: 'RISK-03', category: 'srm_contamination', description: 'Paid ad campaign sudden burst contaminates running A/B test cohort', mitigation: 'Enforce UTM parameter isolation and SRM daily monitoring' },
338
+ ],
339
+
340
+ // Pillar 15: Data Governance Requirements
341
+ data_governance: {
342
+ authorized_sources: ['Audited customer DOM', 'Search Console telemetry', 'Public AI search observation endpoints'],
343
+ retention_period: '90 days post-completion, followed by immutable archive',
344
+ processing_purpose: 'Exclusively for fulfilling contracted SOW engineering and verification obligations',
345
+ deletion_upon_termination: 'Supplier will delete all customer source code clones within 14 calendar days of contract completion',
346
+ },
347
+
348
+ // Pillar 16: Security & Privacy Requirements
349
+ security_requirements: [
350
+ 'Zero plaintext credentials stored; all authentication managed via environment variable tokens (credential_env).',
351
+ 'Least privilege: Supplier requires only read-only repository and analytics access.',
352
+ 'No customer PII (personally identifiable customer data) will be stored, processed, or logged.',
353
+ 'Incident notification: Any suspected security anomaly reported to customer security within 24 hours.',
354
+ ],
355
+
356
+ // Pillar 17: Platform & Third-Party Dependency Statement
357
+ platform_dependencies: [
358
+ 'Customer acknowledges that third-party search engines (Google, Bing) and AI platforms (OpenAI, Anthropic, Perplexity) operate autonomously. Supplier cannot control, and does not warrant, unilateral external algorithm modifications.',
359
+ ],
360
+
361
+ // Pillar 18: Quality Assurance & Validation Plan
362
+ qa_plan: {
363
+ methodology: 'Three-tier verification: (1) Static AST patch linting, (2) Closed-loop detector rerun, (3) Visual screenshot layout regression check.',
364
+ evidence_package: 'Every accepted deliverable includes a cryptographic SHA-256 hash-locked verification envelope.',
365
+ },
366
+
367
+ // Pillar 19: Reporting Cadence & Governance Model
368
+ governance_model: {
369
+ weekly_sync: '30-minute sprint progress and blocker resolution call',
370
+ written_reports: 'Bi-weekly status dashboard and updated traceability matrix',
371
+ decision_logging: 'All material technical decisions logged to .citable/decisions/',
372
+ },
373
+
374
+ // Pillar 20: Commercial Structure
375
+ commercial_terms: {
376
+ total_fixed_fee_usd: budget,
377
+ payment_terms: 'Net 30 upon verified deliverable acceptance',
378
+ milestones: commercialMilestones,
379
+ },
380
+
381
+ // Pillar 21: Out-of-Scope Section
382
+ out_of_scope: [
383
+ 'Writing bespoke corporate PR press releases or off-site guest blogging.',
384
+ 'Modifying legacy subdomains not explicitly enumerated in Executive Scope.',
385
+ 'Purchasing media ad credits, paid backlinks, or advertising inventory.',
386
+ 'Providing legal counsel regarding privacy regulations or intellectual property.',
387
+ ],
388
+
389
+ // Pillar 22: Warranty & Remediation Terms
390
+ warranty_terms: {
391
+ warranty_window_days: 30,
392
+ defect_definition: 'A defect is strictly defined as a failure of an accepted deliverable to satisfy its explicit Acceptance Criteria test upon rerun under unchanged baseline conditions.',
393
+ exclusion: 'Defects caused by subsequent customer code modifications, third-party library updates, or external platform outages are excluded.',
394
+ },
395
+
396
+ // Pillar 23: Completion & Operational Handoff
397
+ completion_and_handoff: {
398
+ handoff_assets: [
399
+ 'Merged and verified Git Pull Requests',
400
+ 'Signed Acceptance Certificates for each Work Package',
401
+ 'Immutable Evidence Package and Cryptographic Verification Envelope',
402
+ 'Developer Documentation & Runbook for ongoing automated maintenance',
403
+ ],
404
+ operational_signoff: 'Final operational transfer completed upon customer tech lead sign-off.',
405
+ },
406
+
407
+ // Pillar 24: Exit & Termination Provisions
408
+ termination_provisions: {
409
+ convenience: 'Either party may terminate upon 14 calendar days written notice.',
410
+ compensation: 'Customer shall compensate Supplier for all completed and accepted deliverables plus pro-rata work in progress up to notice date.',
411
+ asset_transfer: 'Supplier delivers all completed patches and evidence packages generated up to the termination effective date.',
412
+ },
413
+
414
+ // Pillar 25: The Final Traceability Matrix
415
+ traceability_matrix: traceabilityMatrix,
416
+ };
417
+
418
+ return sow;
419
+ }
420
+
421
+ /**
422
+ * Render Statement of Work as GitHub-flavored Markdown
423
+ */
424
+ export function renderSowMarkdown(sow) {
425
+ const lines = [
426
+ `# ${sow.title}`,
427
+ `====================================================================`,
428
+ `- **SOW ID**: \`${sow.sow_id}\` | **Version**: \`${sow.version}\``,
429
+ `- **Client**: **${sow.client.name}** (${sow.client.contact})`,
430
+ `- **Supplier**: **${sow.supplier.name}** (${sow.supplier.contact})`,
431
+ `- **Effective Date**: \`${sow.effective_date}\` | **Term**: \`${sow.term_days} calendar days\``,
432
+ `- **Commercial Total**: **$${sow.commercial_total_fee_usd.toLocaleString()} USD**`,
433
+ ``,
434
+ `> **Contractual Principle**: This Statement of Work forces strict downward traceability from documented audit evidence to contractual obligation, and from obligation to verifiable acceptance. Findings are admitted strictly through a formal Admissibility Gate. In adherence to Citable governance principles, **no search rankings, AI citations, or conversion revenues are guaranteed**; fees are tied exclusively to objective deliverable acceptance.`,
435
+ ``,
436
+ `---`,
437
+ `## 1. Executive Scope Statement`,
438
+ `- **Core Business Objective**: ${sow.executive_scope.business_objective}`,
439
+ `- **In-Scope Digital Properties**: ${sow.executive_scope.in_scope_properties.join(', ')}`,
440
+ `- **In-Scope Systems**: ${sow.executive_scope.in_scope_systems.join('; ')}`,
441
+ `- **Contracted Channels**: ${sow.executive_scope.channels.join(', ')}`,
442
+ `- **Geographies & Jurisdictions**: ${sow.executive_scope.geographies.join(', ')}`,
443
+ `- **Organizational Boundary**: ${sow.executive_scope.organizational_boundaries}`,
444
+ ``,
445
+ `## 2. Scope Admissibility Gate (Evidence-to-Work Filter)`,
446
+ `- **Total Audit Findings Evaluated**: ${sow.admissibility_gate.total_findings_evaluated}`,
447
+ `- **Admitted Contractual Requirements**: **${sow.admissibility_gate.admitted_count}** (${sow.admissibility_gate.admissibility_rate_pct}% admission rate)`,
448
+ `- **Refused / Excluded Findings**: **${sow.admissibility_gate.refused_count}** (preventing unverified or exploratory creep)`,
449
+ ``,
450
+ `### Refused & Deferred Findings Log:`,
451
+ `| Finding ID | Subject | Gate Failed | Refusal Code | Contractual Rationale |`,
452
+ `| :--- | :--- | :--- | :--- | :--- |`,
453
+ ...(sow.admissibility_gate.refusal_log.length > 0
454
+ ? sow.admissibility_gate.refusal_log.map((r) => `| \`${r.finding_id}\` | \`${r.subject}\` | \`${r.gate_failed}\` | \`${r.refusal_code}\` | ${r.refusal_rationale.slice(0, 75)}... |`)
455
+ : ['| None | N/A | N/A | N/A | All evaluated findings met strict admissibility criteria |']),
456
+ ``,
457
+ `## 3. Assumptions, Dependencies, Exclusions & Constraints`,
458
+ `### Explicit Assumptions:`,
459
+ ...sow.assumptions_and_constraints.assumptions.map((a) => `- ${a}`),
460
+ `### Key Dependencies:`,
461
+ ...sow.assumptions_and_constraints.dependencies.map((d) => `- ${d}`),
462
+ `### Known Constraints:`,
463
+ ...sow.assumptions_and_constraints.constraints.map((c) => `- ${c}`),
464
+ `### Unresolved Unknowns:`,
465
+ ...sow.assumptions_and_constraints.unresolved_unknowns.map((u) => `- [?] ${u}`),
466
+ ``,
467
+ `## 4. Prioritized Work Packages (Derived from ICE-BV)`,
468
+ ...sow.work_packages.map((wp) => `### ${wp.work_package_id}: ${wp.name}\n- **Owner**: \`${wp.owner}\`\n- **Deliverable Binding**: \`${wp.deliverable_id}\`\n- **Requirements Count**: ${wp.requirements.length} requirement(s)`),
469
+ ``,
470
+ `## 5. Detailed Deliverables & Delivery Criteria`,
471
+ `| Deliverable ID | Title | Artifact Type | Format | Delivery & Acceptance Criteria |`,
472
+ `| :--- | :--- | :--- | :--- | :--- |`,
473
+ ...sow.deliverables.map((d) => `| **${d.deliverable_id}** | ${d.title} | \`${d.artifact_type}\` | ${d.format} | ${d.delivery_criteria} |`),
474
+ ``,
475
+ `## 6. Technical Implementation Requirements`,
476
+ `- **Supported Frameworks**: ${sow.technical_requirements.supported_frameworks.join(', ')}`,
477
+ `- **Branching Model**: \`${sow.technical_requirements.git_branching_model}\``,
478
+ `- **Rollback Safeguard**: ${sow.technical_requirements.rollback_mechanism}`,
479
+ ``,
480
+ `## 7. Acceptance Criteria & Objective Verification Methods`,
481
+ `| Test ID | SOW Requirement | Validation Method | Pass / Fail Threshold | Required Evidence |`,
482
+ `| :--- | :--- | :--- | :--- | :--- |`,
483
+ ...sow.acceptance_criteria.map((a) => `| **${a.acceptance_test_id}** | \`${a.sow_requirement_id}\` | \`${a.validation_method}\` | ${a.pass_threshold} | ${a.evidence_required} |`),
484
+ ``,
485
+ `## 8. Baseline & Target-State Metrics (Non-Guarantee Disclosure)`,
486
+ `> *${sow.baseline_and_target_metrics.disclaimer}*`,
487
+ ``,
488
+ `| Dimension | Baseline State | Contracted Target State | Objective Verification |`,
489
+ `| :--- | :--- | :--- | :--- |`,
490
+ ...sow.baseline_and_target_metrics.metrics.map((m) => `| ${m.metric} | **${m.baseline}** | **${m.target}** | \`${m.validation}\` |`),
491
+ ``,
492
+ `## 9. Governed Experiment Specifications`,
493
+ `- **Statistical Standard**: ${sow.experiment_specifications.standard}`,
494
+ `- **Stopping & Guardrails**: ${sow.experiment_specifications.stopping_criteria}`,
495
+ ...sow.experiment_specifications.guardrails.map((g) => `- ${g}`),
496
+ ``,
497
+ `## 10. Roles & RACI Matrix`,
498
+ `| Role | Responsibility Description | RACI Designation |`,
499
+ `| :--- | :--- | :--- |`,
500
+ ...sow.raci_matrix.map((r) => `| **${r.role}** | ${r.r} | **${r.raci}** |`),
501
+ ``,
502
+ `## 11. Customer Obligations & SLAs`,
503
+ ...sow.customer_obligations.map((o) => `- ${o}`),
504
+ ``,
505
+ `## 12. Delivery Sequencing & Milestone Schedule`,
506
+ `| Milestone | Work Package | Target Week | Fee (USD) | Acceptance Trigger |`,
507
+ `| :--- | :--- | :--- | :--- | :--- |`,
508
+ ...sow.delivery_schedule.milestones.map((m) => `| **${m.milestone_id}** | \`${m.work_package_id}\` | Week ${m.target_delivery_week} | **$${m.fee_usd.toLocaleString()}** | ${m.billing_trigger} |`),
509
+ ``,
510
+ `## 13. Scope Change-Control Process`,
511
+ `- **Procedure**: ${sow.change_control_process.procedure}`,
512
+ `- **Authorization**: ${sow.change_control_process.authorization}`,
513
+ `- **Superseded Controls**: ${sow.change_control_process.superceding_rules}`,
514
+ ``,
515
+ `## 14. Risk & Dependency Register`,
516
+ `| Risk ID | Category | Risk Description | Planned Mitigation |`,
517
+ `| :--- | :--- | :--- | :--- |`,
518
+ ...sow.risk_register.map((r) => `| **${r.id}** | \`${r.category}\` | ${r.description} | ${r.mitigation} |`),
519
+ ``,
520
+ `## 15. Data Governance & Information Handling`,
521
+ `- **Authorized Sources**: ${sow.data_governance.authorized_sources.join(', ')}`,
522
+ `- **Retention & Purging**: ${sow.data_governance.retention_period}; ${sow.data_governance.deletion_upon_termination}`,
523
+ ``,
524
+ `## 16. Security & Privacy Safeguards`,
525
+ ...sow.security_requirements.map((s) => `- ${s}`),
526
+ ``,
527
+ `## 17. Platform & Third-Party Dependency Disclosures`,
528
+ ...sow.platform_dependencies.map((p) => `> ${p}`),
529
+ ``,
530
+ `## 18. Quality Assurance & Validation Plan`,
531
+ `- **QA Methodology**: ${sow.qa_plan.methodology}`,
532
+ `- **Evidence Integrity**: ${sow.qa_plan.evidence_package}`,
533
+ ``,
534
+ `## 19. Governance Cadence & Reporting Model`,
535
+ `- **Weekly Sync**: ${sow.governance_model.weekly_sync}`,
536
+ `- **Status Reports**: ${sow.governance_model.written_reports}`,
537
+ `- **Decision Records**: ${sow.governance_model.decision_logging}`,
538
+ ``,
539
+ `## 20. Commercial Terms & Payment Schedule`,
540
+ `- **Total Contract Value**: **$${sow.commercial_terms.total_fixed_fee_usd.toLocaleString()} USD**`,
541
+ `- **Terms**: ${sow.commercial_terms.payment_terms}`,
542
+ ``,
543
+ `## 21. Explicit Out-of-Scope Declarations`,
544
+ ...sow.out_of_scope.map((item) => `- [x] **OUT OF SCOPE**: ${item}`),
545
+ ``,
546
+ `## 22. Warranty & Remediation Terms`,
547
+ `- **Warranty Period**: **${sow.warranty_terms.warranty_window_days} calendar days** following written deliverable acceptance.`,
548
+ `- **Defect Standard**: ${sow.warranty_terms.defect_definition}`,
549
+ `- **Warranty Exclusions**: ${sow.warranty_terms.exclusion}`,
550
+ ``,
551
+ `## 23. Completion & Operational Handoff`,
552
+ `### Required Deliverable Handoff Assets:`,
553
+ ...sow.completion_and_handoff.handoff_assets.map((h) => `- [x] ${h}`),
554
+ ``,
555
+ `## 24. Exit, Transition & Termination Provisions`,
556
+ `- **Termination for Convenience**: ${sow.termination_provisions.convenience}`,
557
+ `- **Accrued Compensation**: ${sow.termination_provisions.compensation}`,
558
+ `- **Asset Return**: ${sow.termination_provisions.asset_transfer}`,
559
+ ``,
560
+ `---`,
561
+ `## 25. THE FINAL TRACEABILITY MATRIX`,
562
+ `### Finding → Recommendation → SOW Requirement → Deliverable → Acceptance Test → Owner → Evidence`,
563
+ ``,
564
+ `| Finding ID | Recommendation | SOW Req ID | Deliverable ID | Acceptance Test ID | Responsible Owner | Source Evidence |`,
565
+ `| :--- | :--- | :--- | :--- | :--- | :--- | :--- |`,
566
+ ...sow.traceability_matrix.map((t) => `| **\`${t.finding_id}\`** | ${t.recommendation.slice(0, 45)}... | **\`${t.sow_requirement_id}\`** | \`${t.deliverable_id}\` | \`${t.acceptance_test_id}\` | ${t.owner} | \`${t.evidence_id}\` |`),
567
+ ``,
568
+ `---`,
569
+ `### Contract Execution & Authorization`,
570
+ ``,
571
+ `| On Behalf of Customer: ${sow.client.name} | On Behalf of Supplier: ${sow.supplier.name} |`,
572
+ `| :--- | :--- |`,
573
+ `| Signature: __________________________________ | Signature: __________________________________ |`,
574
+ `| Name: _____________________________________ | Name: _____________________________________ |`,
575
+ `| Title: ______________________________________ | Title: ______________________________________ |`,
576
+ `| Date: _______________________________________ | Date: _______________________________________ |`,
577
+ ];
578
+
579
+ return lines.join('\n');
580
+ }
581
+
582
+ /**
583
+ * Render Statement of Work as Standalone Enterprise HTML
584
+ */
585
+ export function renderSowHtml(sow) {
586
+ return `<!DOCTYPE html>
587
+ <html lang="en">
588
+ <head>
589
+ <meta charset="UTF-8">
590
+ <title>${sow.title} - ${sow.sow_id}</title>
591
+ <style>
592
+ :root { --bg: #0d1117; --card: #161b22; --border: #30363d; --text: #c9d1d9; --accent: #58a6ff; --danger: #f85149; --warning: #d29922; --success: #3fb950; }
593
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; margin: 0; padding: 40px 20px; }
594
+ .container { max-width: 1180px; margin: 0 auto; }
595
+ header { border-bottom: 2px solid var(--border); padding-bottom: 24px; margin-bottom: 32px; }
596
+ h1 { font-size: 28px; margin: 0 0 10px 0; color: #fff; }
597
+ .sow-badge { background: #1f6feb; color: #fff; padding: 4px 10px; border-radius: 4px; font-size: 13px; font-weight: bold; }
598
+ .meta-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin: 24px 0; }
599
+ .card { background: var(--card); border: 1px solid var(--border); border-radius: 6px; padding: 18px; }
600
+ .card-val { font-size: 26px; font-weight: bold; color: #fff; margin-top: 4px; }
601
+ .disclosure { background: rgba(56, 139, 253, 0.1); border-left: 4px solid var(--accent); padding: 14px 18px; border-radius: 4px; font-size: 13px; margin: 24px 0; }
602
+ .section-title { font-size: 20px; border-bottom: 1px solid var(--border); padding-bottom: 8px; margin: 36px 0 16px 0; color: #fff; }
603
+ table { width: 100%; border-collapse: collapse; margin: 20px 0; background: var(--card); border-radius: 6px; overflow: hidden; border: 1px solid var(--border); }
604
+ th, td { padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--border); font-size: 13px; }
605
+ th { background: #21262d; color: #8b949e; font-weight: 600; }
606
+ .badge { display: inline-block; padding: 2px 6px; border-radius: 4px; font-size: 11px; font-weight: bold; }
607
+ .badge-admit { background: rgba(63, 185, 80, 0.2); color: var(--success); }
608
+ .badge-refuse { background: rgba(248, 81, 73, 0.2); color: var(--danger); }
609
+ .code-ref { font-family: monospace; color: var(--accent); background: rgba(88, 166, 255, 0.15); padding: 2px 5px; border-radius: 3px; }
610
+ .sig-table { margin-top: 40px; }
611
+ .sig-table td { height: 60px; vertical-align: top; }
612
+ </style>
613
+ </head>
614
+ <body>
615
+ <div class="container">
616
+ <header>
617
+ <div style="display:flex; justify-content:space-between; align-items:center;">
618
+ <h1>${sow.title}</h1>
619
+ <span class="sow-badge">${sow.sow_id}</span>
620
+ </div>
621
+ <div style="color:#8b949e; font-size:14px; margin-top:8px;">
622
+ Client: <strong>${sow.client.name}</strong> &nbsp;|&nbsp; Supplier: <strong>${sow.supplier.name}</strong> &nbsp;|&nbsp; Term: <strong>${sow.term_days} Days</strong> &nbsp;|&nbsp; Effective: <strong>${sow.effective_date}</strong>
623
+ </div>
624
+ </header>
625
+
626
+ <div class="disclosure">
627
+ <strong>Enterprise Statement of Work Governance Notice:</strong> This agreement binds supplier fees exclusively to verified deliverable acceptance and closed-loop test execution. In compliance with Citable governance standards, <strong>no search engine ranking, AI citation presence, or commercial conversion revenue outcomes are guaranteed</strong>.
628
+ </div>
629
+
630
+ <div class="meta-grid">
631
+ <div class="card"><div>Total Contract Fee</div><div class="card-val">$${sow.commercial_total_fee_usd.toLocaleString()}</div></div>
632
+ <div class="card"><div>Admitted SOW Requirements</div><div class="card-val">${sow.admissibility_gate.admitted_count}</div></div>
633
+ <div class="card"><div>Refused / Excluded Scope</div><div class="card-val" style="color:var(--danger);">${sow.admissibility_gate.refused_count}</div></div>
634
+ <div class="card"><div>Contracted Work Packages</div><div class="card-val">${sow.work_packages.length}</div></div>
635
+ </div>
636
+
637
+ <h2 class="section-title">1. Executive Scope Statement</h2>
638
+ <div class="card">
639
+ <p><strong>Objective:</strong> ${sow.executive_scope.business_objective}</p>
640
+ <p><strong>In-Scope Properties:</strong> <code>${sow.executive_scope.in_scope_properties.join(', ')}</code></p>
641
+ <p><strong>In-Scope Systems:</strong> ${sow.executive_scope.in_scope_systems.join('; ')}</p>
642
+ <p><strong>Boundaries:</strong> ${sow.executive_scope.organizational_boundaries}</p>
643
+ </div>
644
+
645
+ <h2 class="section-title">2. Scope Admissibility Gate & Excluded Findings Log</h2>
646
+ <table>
647
+ <thead>
648
+ <tr><th>Finding ID</th><th>Subject</th><th>Gate Failed</th><th>Refusal Code</th><th>Contractual Refusal Rationale</th></tr>
649
+ </thead>
650
+ <tbody>
651
+ ${sow.admissibility_gate.refusal_log.map((r) => `
652
+ <tr>
653
+ <td><span class="code-ref">${r.finding_id}</span></td>
654
+ <td>${r.subject}</td>
655
+ <td><code>${r.gate_failed}</code></td>
656
+ <td><span class="badge badge-refuse">${r.refusal_code}</span></td>
657
+ <td>${r.refusal_rationale}</td>
658
+ </tr>
659
+ `).join('')}
660
+ </tbody>
661
+ </table>
662
+
663
+ <h2 class="section-title">3. Contracted Deliverables & Milestone Payment Schedule</h2>
664
+ <table>
665
+ <thead>
666
+ <tr><th>Milestone</th><th>Work Package</th><th>Deliverable ID</th><th>Delivery Criteria</th><th>Milestone Fee</th></tr>
667
+ </thead>
668
+ <tbody>
669
+ ${sow.delivery_schedule.milestones.map((m) => `
670
+ <tr>
671
+ <td><strong>${m.milestone_id}</strong></td>
672
+ <td>${m.name}</td>
673
+ <td><span class="code-ref">${m.work_package_id}</span></td>
674
+ <td>${m.billing_trigger}</td>
675
+ <td style="font-weight:bold; color:var(--success);">$${m.fee_usd.toLocaleString()} USD</td>
676
+ </tr>
677
+ `).join('')}
678
+ </tbody>
679
+ </table>
680
+
681
+ <h2 class="section-title">25. The Final Traceability Matrix</h2>
682
+ <p style="color:#8b949e; font-size:13px;">Proving exactly why work is performed, what must be delivered, who owns it, how it will be validated, and what evidence justifies it.</p>
683
+ <table>
684
+ <thead>
685
+ <tr><th>Finding ID</th><th>Recommendation</th><th>SOW Req ID</th><th>Deliverable</th><th>Acceptance Test ID</th><th>Responsible Owner</th><th>Source Evidence</th></tr>
686
+ </thead>
687
+ <tbody>
688
+ ${sow.traceability_matrix.map((t) => `
689
+ <tr>
690
+ <td><span class="code-ref">${t.finding_id}</span></td>
691
+ <td>${t.recommendation}</td>
692
+ <td><strong>${t.sow_requirement_id}</strong></td>
693
+ <td>${t.deliverable_id}</td>
694
+ <td><code>${t.acceptance_test_id}</code></td>
695
+ <td>${t.owner}</td>
696
+ <td><span class="code-ref">${t.evidence_id}</span></td>
697
+ </tr>
698
+ `).join('')}
699
+ </tbody>
700
+ </table>
701
+
702
+ <h2 class="section-title">Signatures & Contractual Authorization</h2>
703
+ <table class="sig-table">
704
+ <thead>
705
+ <tr><th>For Customer: ${sow.client.name}</th><th>For Supplier: ${sow.supplier.name}</th></tr>
706
+ </thead>
707
+ <tbody>
708
+ <tr>
709
+ <td>
710
+ <br>Signature: _______________________________<br><br>
711
+ Name: __________________________________<br><br>
712
+ Title: ___________________________________<br><br>
713
+ Date: ____________________________________
714
+ </td>
715
+ <td>
716
+ <br>Signature: _______________________________<br><br>
717
+ Name: __________________________________<br><br>
718
+ Title: ___________________________________<br><br>
719
+ Date: ____________________________________
720
+ </td>
721
+ </tr>
722
+ </tbody>
723
+ </table>
724
+ </div>
725
+ </body>
726
+ </html>`;
727
+ }
728
+
729
+ /**
730
+ * Export SOW deliverable to filesystem or string
731
+ */
732
+ export async function exportSow(root, options = {}) {
733
+ const sow = await generateSow(root, options);
734
+ const format = options.format || 'markdown';
735
+ let content = '';
736
+
737
+ if (format === 'html' || format === 'html-brief') {
738
+ content = renderSowHtml(sow);
739
+ } else if (format === 'json') {
740
+ content = JSON.stringify(sow, null, 2);
741
+ } else {
742
+ content = renderSowMarkdown(sow);
743
+ }
744
+
745
+ let outputPath = null;
746
+ if (options.output) {
747
+ outputPath = path.resolve(root, options.output);
748
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
749
+ fs.writeFileSync(outputPath, content, 'utf8');
750
+ }
751
+
752
+ return {
753
+ sow_id: sow.sow_id,
754
+ title: sow.title,
755
+ client: sow.client,
756
+ supplier: sow.supplier,
757
+ format,
758
+ output_path: outputPath,
759
+ content,
760
+ data: sow,
761
+ };
762
+ }