@nebulacomponents/citable 1.17.0 → 1.18.1
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.
- package/CHANGELOG.md +62 -0
- package/dist/universal/.agents/skills/citable/SKILL.md +41 -1
- package/dist/universal/.agents/skills/citable/VERSION +1 -1
- package/dist/universal/.agents/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.agents/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.agents/skills/citable/commands/README.md +13 -0
- package/dist/universal/.agents/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.agents/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.agents/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.agents/skills/citable/manifest.json +12 -7
- package/dist/universal/.agents/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.claude/agents/citable/citable-remediator.md +43 -0
- package/dist/universal/.claude/agents/citable/citable-sow-architect.md +43 -0
- package/dist/universal/.claude/agents/citable/manifest.json +6 -4
- package/dist/universal/.claude/skills/citable/SKILL.md +41 -1
- package/dist/universal/.claude/skills/citable/VERSION +1 -1
- package/dist/universal/.claude/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.claude/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.claude/skills/citable/commands/README.md +13 -0
- package/dist/universal/.claude/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.claude/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.claude/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.claude/skills/citable/manifest.json +16 -9
- package/dist/universal/.claude/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.cursor/skills/citable/SKILL.md +41 -1
- package/dist/universal/.cursor/skills/citable/VERSION +1 -1
- package/dist/universal/.cursor/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.cursor/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.cursor/skills/citable/commands/README.md +13 -0
- package/dist/universal/.cursor/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.cursor/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.cursor/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +12 -7
- package/dist/universal/.cursor/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.gemini/skills/citable/SKILL.md +41 -1
- package/dist/universal/.gemini/skills/citable/VERSION +1 -1
- package/dist/universal/.gemini/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.gemini/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.gemini/skills/citable/commands/README.md +13 -0
- package/dist/universal/.gemini/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.gemini/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.gemini/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +12 -7
- package/dist/universal/.gemini/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.github/skills/citable/SKILL.md +41 -1
- package/dist/universal/.github/skills/citable/VERSION +1 -1
- package/dist/universal/.github/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.github/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.github/skills/citable/commands/README.md +13 -0
- package/dist/universal/.github/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.github/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.github/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.github/skills/citable/manifest.json +12 -7
- package/dist/universal/.github/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.kiro/skills/citable/SKILL.md +41 -1
- package/dist/universal/.kiro/skills/citable/VERSION +1 -1
- package/dist/universal/.kiro/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.kiro/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.kiro/skills/citable/commands/README.md +13 -0
- package/dist/universal/.kiro/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.kiro/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.kiro/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +12 -7
- package/dist/universal/.kiro/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.opencode/skills/citable/SKILL.md +41 -1
- package/dist/universal/.opencode/skills/citable/VERSION +1 -1
- package/dist/universal/.opencode/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.opencode/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.opencode/skills/citable/commands/README.md +13 -0
- package/dist/universal/.opencode/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.opencode/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.opencode/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +12 -7
- package/dist/universal/.opencode/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.pi/agent/skills/citable/SKILL.md +41 -1
- package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
- package/dist/universal/.pi/agent/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.pi/agent/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.pi/agent/skills/citable/commands/README.md +13 -0
- package/dist/universal/.pi/agent/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.pi/agent/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.pi/agent/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +12 -7
- package/dist/universal/.pi/agent/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.qoder/skills/citable/SKILL.md +41 -1
- package/dist/universal/.qoder/skills/citable/VERSION +1 -1
- package/dist/universal/.qoder/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.qoder/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.qoder/skills/citable/commands/README.md +13 -0
- package/dist/universal/.qoder/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.qoder/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.qoder/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +12 -7
- package/dist/universal/.qoder/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.rovodev/skills/citable/SKILL.md +41 -1
- package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
- package/dist/universal/.rovodev/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.rovodev/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.rovodev/skills/citable/commands/README.md +13 -0
- package/dist/universal/.rovodev/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.rovodev/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.rovodev/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +12 -7
- package/dist/universal/.rovodev/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.trae/skills/citable/SKILL.md +41 -1
- package/dist/universal/.trae/skills/citable/VERSION +1 -1
- package/dist/universal/.trae/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.trae/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.trae/skills/citable/commands/README.md +13 -0
- package/dist/universal/.trae/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.trae/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.trae/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.trae/skills/citable/manifest.json +12 -7
- package/dist/universal/.trae/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/.trae-cn/skills/citable/SKILL.md +41 -1
- package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
- package/dist/universal/.trae-cn/skills/citable/agents/citable-remediator.md +43 -0
- package/dist/universal/.trae-cn/skills/citable/agents/citable-sow-architect.md +43 -0
- package/dist/universal/.trae-cn/skills/citable/commands/README.md +13 -0
- package/dist/universal/.trae-cn/skills/citable/commands/remediation.md +55 -0
- package/dist/universal/.trae-cn/skills/citable/commands/reporting.md +28 -0
- package/dist/universal/.trae-cn/skills/citable/commands/sow.md +95 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +12 -7
- package/dist/universal/.trae-cn/skills/citable/schemas/sow.schema.json +409 -0
- package/dist/universal/manifest.json +150 -88
- package/package.json +1 -1
- package/schemas/sow.schema.json +409 -0
- package/skill/SKILL.md +41 -1
- package/skill/agents/citable-remediator.md +43 -0
- package/skill/agents/citable-sow-architect.md +43 -0
- package/skill/commands/README.md +13 -0
- package/skill/commands/remediation.md +55 -0
- package/skill/commands/reporting.md +28 -0
- package/skill/commands/sow.md +95 -0
- package/src/analysis/behavioral.js +126 -0
- package/src/analysis/croAudit.js +302 -0
- package/src/analysis/croRoadmap.js +121 -0
- package/src/analysis/eeat.js +300 -0
- package/src/analysis/funnelAnalysis.js +171 -0
- package/src/analysis/iceMatrix.js +205 -0
- package/src/analysis/offpage.js +228 -0
- package/src/analysis/readiness.js +253 -0
- package/src/analysis/schemaRecommendations.js +173 -0
- package/src/analysis/strategicRoadmap.js +148 -0
- package/src/cli/index.js +149 -3
- package/src/commands/answerEngineReadiness.js +48 -0
- package/src/commands/auditBacklinks.js +79 -0
- package/src/commands/croBacklog.js +182 -0
- package/src/commands/croSuite.js +156 -0
- package/src/commands/executive.js +6 -0
- package/src/commands/executiveCro.js +30 -0
- package/src/commands/executiveSearch.js +28 -0
- package/src/commands/inspectCro.js +7 -0
- package/src/commands/inspectEeat.js +53 -0
- package/src/commands/prioritize.js +42 -6
- package/src/commands/roadmapCmd.js +69 -0
- package/src/commands/schemaCmd.js +10 -2
- package/src/commands/sowCmd.js +84 -0
- package/src/commands/sweep.js +357 -0
- package/src/reporting/executiveCroReport.js +731 -0
- package/src/reporting/executiveExport.js +62 -0
- package/src/reporting/executiveSearchReport.js +704 -0
- package/src/sow/admissibilityGate.js +364 -0
- package/src/sow/generateSow.js +1178 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
command: /citable remediate --finding <id> [--target <file>] [--write]
|
|
3
|
+
purpose: Apply safe, validated AST code patches for deterministic defects with automated rollback snapshots, structural syntax validation, and confidence gating.
|
|
4
|
+
preconditions: [valid finding from audit run; target source file identified and writeable]
|
|
5
|
+
failure_behaviour: unknown framework -> fail closed; invalid syntax after patch -> rollback and refuse; confidence < 0.7 -> refuse write; semantic microcopy changes -> always refuse automated write (human editorial decision required)
|
|
6
|
+
artifacts_created: [.citable/remediation/snapshots/<snapshot-id>/, unified diff on stdout]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Closed-Loop Code Remediation & Verification
|
|
10
|
+
|
|
11
|
+
The remediation suite provides safe, gated code fixes for deterministic technical, schema, and CRO defects discovered during audits. It bridges the gap between audit findings and customer-verified pull requests.
|
|
12
|
+
|
|
13
|
+
## 1. Safe Patch Application (`citable remediate`)
|
|
14
|
+
|
|
15
|
+
1. **Framework Detection**: Identifies target source syntax (`jsx`, `tsx`, `vue`, `html`). Fails closed on unknown or ambiguous frameworks.
|
|
16
|
+
2. **Idempotent AST Patching**: Patches are mathematically verified to be idempotent (`applyPatchDetailed`): applying the patch a second time produces an identical AST (a fixed point).
|
|
17
|
+
3. **Structural Validation Gate**: Runs `validatePatchedSource` to confirm that the patch does not break AST structure, introduce syntax errors, or alter unrelated code blocks.
|
|
18
|
+
4. **Confidence Threshold**: Computes an explicit multi-factor confidence score (`computeConfidence`). `--write` is refused if confidence falls below `0.70`.
|
|
19
|
+
5. **Editorial Boundary (Semantic Microcopy Refusal)**: Automated `--write` is strictly refused for semantic copy, CTA wording, or headline changes (e.g. `CRO-012`, `COMP-003`). Microcopy is a human editorial and brand judgment (fact ≠ inference).
|
|
20
|
+
6. **Rollback Snapshot**: Every `--write` automatically snapshots the target file under `.citable/remediation/snapshots/<timestamp>/` with a SHA-256 manifest before making any disk modifications.
|
|
21
|
+
|
|
22
|
+
## 2. Closed-Loop Verification (`citable verify remediation`)
|
|
23
|
+
|
|
24
|
+
Running a patch is NOT proof that a defect is resolved:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
citable verify remediation --run <run-id> --finding <id> [--target <file>] [--apply]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
1. **Deterministic Detector Rerun**: Re-executes the exact source detector (`detector_to_rerun`) against the patched target.
|
|
31
|
+
2. **Regression Sweep**: Sweeps for newly introduced critical or high severity defects compared to the baseline run.
|
|
32
|
+
3. **Verification Envelopes**: Emits a checksum-bound before/after verification envelope conforming to `schemas/remediation-verification.schema.json`.
|
|
33
|
+
4. **Verdict Classification**:
|
|
34
|
+
* `verified`: Target detector no longer reports the defect; zero regressions introduced.
|
|
35
|
+
* `not_resolved`: Target detector still detects the condition on the patched surface.
|
|
36
|
+
* `blocked`: Prerequisite dependencies, build tools, or environments unavailable.
|
|
37
|
+
* `patch_refused`: Confidence below threshold, semantic copy gated, or syntax check failed.
|
|
38
|
+
5. **Outcome Boundary**: Resolution means the detector no longer flags the subject — **it is never an outcome guarantee of rankings, AI citations, or conversion lift**.
|
|
39
|
+
|
|
40
|
+
## 3. Customer Implementation Kits (`citable kit export`)
|
|
41
|
+
|
|
42
|
+
Produce an engineer-ready delivery kit for customer development teams:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
citable kit export --run <run-id> --finding <id> [--target <file>]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Creates a self-contained directory containing:
|
|
49
|
+
* Verbatim finding with evidence lineage.
|
|
50
|
+
* Exact unified diff for code review.
|
|
51
|
+
* Reusable Nebula design system component template (React / Vue / HTML).
|
|
52
|
+
* Rendering-evidence manifest (real captured DOM/visual state; synthetic evidence forbidden).
|
|
53
|
+
* Acceptance test criteria and re-audit verification script.
|
|
54
|
+
* Deployment and rollback instructions.
|
|
55
|
+
* Explicit technical limitations and non-guarantee disclosures.
|
|
@@ -71,3 +71,31 @@ any observed change to a specific intervention.
|
|
|
71
71
|
authoritative index guarantees. Divergences are reported as factual observations,
|
|
72
72
|
never fabricated or interpolated.
|
|
73
73
|
|
|
74
|
+
# Enterprise Search Intelligence Briefing (`citable report search`)
|
|
75
|
+
|
|
76
|
+
1. Run `citable report search [--target <dir|url>] [--run <id>] [--format md|html|json] [--output <file>]`
|
|
77
|
+
to generate the 19-pillar Executive Search Intelligence Briefing.
|
|
78
|
+
2. Synthesizes technical crawlability, indexation, Core Web Vitals readiness,
|
|
79
|
+
AEO answer-extractability, GEO citation frequency, knowledge graph schema
|
|
80
|
+
architecture, and competitor SERP landscape into an executive document.
|
|
81
|
+
3. Every recommendation binds to a verified finding in the Evidence Register.
|
|
82
|
+
4. Facts and inferences are strictly segregated: deterministic observations are
|
|
83
|
+
reported in green data panels; strategic hypotheses and inferences are explicitly
|
|
84
|
+
labeled with confidence ratings.
|
|
85
|
+
5. Refusal boundary: Never promises rankings, algorithmic immunity, or indexing
|
|
86
|
+
guarantees.
|
|
87
|
+
|
|
88
|
+
# Enterprise CRO & Customer Journey Briefing (`citable report cro`)
|
|
89
|
+
|
|
90
|
+
1. Run `citable report cro [--target <dir|url>] [--input <file>] [--format md|html|json] [--output <file>]`
|
|
91
|
+
to generate the 25-pillar Executive Conversion & Customer Journey Briefing.
|
|
92
|
+
2. Covers end-to-end conversion paths: above-the-fold clarity, message-match
|
|
93
|
+
scoring, cognitive load, checkout friction, trust and objection analysis, offer
|
|
94
|
+
architecture, and prioritized A/B experiment blueprints.
|
|
95
|
+
3. Strictly adheres to the **Observation vs Hypothesis vs Causation** taxonomy:
|
|
96
|
+
- **Observations**: Verbatim DOM defects (e.g. missing autocomplete, undersized touch targets).
|
|
97
|
+
- **Hypotheses**: Falsifiable experiment statements with measurable primary metrics and guardrails.
|
|
98
|
+
- **Causation**: Statistical lift attribution requiring concluded, SRM-clean A/B experiments.
|
|
99
|
+
4. Refusal boundary: Revenue lift, conversion percentage improvements, and visual
|
|
100
|
+
saliency scores are modeled heuristic indices, never observed behavior or guaranteed revenue.
|
|
101
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
command: /citable sow generate [--target <dir|url>] [--run <id>] [--budget <amount>] [--budget-minor <cents>] [--format md|html|json] [--output <path>] [--sample] [--draft]
|
|
3
|
+
purpose: Generate a contractually binding, evidence-traceable enterprise Statement of Work (SOW) from verified audit findings through a formal 7-gate scope admissibility filter and 7-column traceability matrix.
|
|
4
|
+
preconditions: [at least one finalized audit run with verified findings or live target; sample mode required for synthetic demonstrations]
|
|
5
|
+
failure_behaviour: absent or unverified findings in contractual mode -> NoFindingsError; all findings refused -> NoAdmissibleRequirementsError; non-existent run -> RunNotFoundError; negative or sub-cent budget -> BudgetCalculationError; invariant drift -> SowInvariantError
|
|
6
|
+
artifacts_created: [SOW.md, SOW.html, or SOW.json at specified output path]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Enterprise Statement of Work (SOW) Contract
|
|
10
|
+
|
|
11
|
+
The `citable sow` command generates enterprise-grade, evidence-backed Statements of Work derived from verified technical SEO, AEO, GEO, schema, and CRO audit findings. It establishes rigid, downward traceability:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
Evidence (observation envelope)
|
|
15
|
+
↓
|
|
16
|
+
Observation (deterministic DOM / HTTP probe)
|
|
17
|
+
↓
|
|
18
|
+
Finding (verified defect / friction)
|
|
19
|
+
↓
|
|
20
|
+
Recommendation (governed remediation)
|
|
21
|
+
↓
|
|
22
|
+
SOW Requirement (contractual scope)
|
|
23
|
+
↓
|
|
24
|
+
Deliverable (code patch / AST modification)
|
|
25
|
+
↓
|
|
26
|
+
Acceptance Test (automated closed-loop detector rerun)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 1. Operating Premises & Commercial Disclaimers
|
|
30
|
+
|
|
31
|
+
1. **Fee Binding**: Supplier fees are bound exclusively to verified deliverable acceptance and closed-loop test execution.
|
|
32
|
+
2. **Strict Outcome Disclaimers**: In strict compliance with Citable governance principles, **no search engine crawling, indexation, ranking, AI answer citation, or conversion revenue is guaranteed**.
|
|
33
|
+
3. **No Synthetic Data in Contracts**: Attempting to generate a `CONTRACTUAL` SOW without verified empirical findings immediately fails closed with `NoFindingsError`. Synthetic findings are strictly confined to `--sample` / `--demo`.
|
|
34
|
+
|
|
35
|
+
## 2. The Scope Admissibility Gate
|
|
36
|
+
|
|
37
|
+
Audit findings do NOT automatically become contractual obligations. Every candidate finding must pass 7 admissibility gates:
|
|
38
|
+
|
|
39
|
+
| Gate | Verification Check | Failure Refusal Code | Contractual Handling |
|
|
40
|
+
| :--- | :--- | :--- | :--- |
|
|
41
|
+
| **1. Exclusion Gate** | Check against explicit excluded detectors list | `REFUSE-EXCLUDED` | Track in internal backlog; execute under separate advisory engagement. |
|
|
42
|
+
| **2. Discipline Authorization** | Check if discipline is authorized under contract | `REFUSE-DISCIPLINE-NOT-AUTHORIZED` | Expand authorized disciplines in SOW engagement terms or contract under separate SOW. |
|
|
43
|
+
| **3. Evidence Maturity** | Require deterministic/observed confidence & evidence | `REFUSE-EXPERIMENTAL` / `REFUSE-NO-EVIDENCE` | Run controlled observation probes before considering for contractual obligation. |
|
|
44
|
+
| **4. Scope Boundary** | Verify URL matches authorized host, subdomain, or path | `REFUSE-OUT-OF-SCOPE` | Escalate domain ownership verification or expand contractual executive scope. |
|
|
45
|
+
| **5. Feasibility Gate** | Reject legal, trademark, GDPR, or unfeasible remediation | `REFUSE-UNFEASIBLE-REMEDIATION` | Refer to specialized legal or compliance counsel outside scope. |
|
|
46
|
+
| **6. Materiality Gate** | Require critical/high severity or ICE score >= threshold | `REFUSE-LOW-MATERIALITY` | Log to internal product maintenance backlog; omit from high-value SOW. |
|
|
47
|
+
| **7. Acceptance Gate** | Require automated rerun detector or objective pass/fail test | `REFUSE-UNVERIFIABLE` | Define deterministic verification criteria before adding to scope. |
|
|
48
|
+
| **8. Ownership Clarity** | Resolve accountable owner from finding or role mappings | `REFUSE-OWNER-UNRESOLVED` | Specify delivery_owner on finding or map discipline to accountable role. |
|
|
49
|
+
|
|
50
|
+
All refused findings are recorded in the SOW's `admissibility_gate.refusal_log` with standard refusal codes and contractual handling guidance.
|
|
51
|
+
|
|
52
|
+
## 3. The 7-Column Traceability Matrix
|
|
53
|
+
|
|
54
|
+
Every admitted requirement must satisfy complete 7-column bidirectional traceability:
|
|
55
|
+
|
|
56
|
+
1. **Finding ID**: Verbatim identifier of the empirical defect (e.g. `F-TECH-001`).
|
|
57
|
+
2. **Recommendation**: Governed, safe remediation instruction.
|
|
58
|
+
3. **SOW Requirement ID**: Contractual clause identifier (`REQ-SOW-001`).
|
|
59
|
+
4. **Deliverable ID**: Accountable work package deliverable (`DELIV-01`).
|
|
60
|
+
5. **Acceptance Test ID**: Automated closed-loop test (`ACC-TEST-001`).
|
|
61
|
+
6. **Responsible Owner**: Named lead dev, architect, or agency practice owner.
|
|
62
|
+
7. **Source Evidence IDs**: Array of cryptographic observation IDs (`['EVD-CWV-001']`).
|
|
63
|
+
|
|
64
|
+
## 4. Commercial Currency & Minor-Unit Semantics
|
|
65
|
+
|
|
66
|
+
To eliminate commercial fee drift and rounding leaks, all internal calculations use exact **integer minor units (cents, exponent 2, currency `USD`)**:
|
|
67
|
+
|
|
68
|
+
* `currency`: Declared as `USD`.
|
|
69
|
+
* `currency_minor_unit_exponent`: Declared as `2`.
|
|
70
|
+
* `commercial_total_fee_minor`: Integer cents (e.g. `$50,000.00` = `5000000` cents).
|
|
71
|
+
* `milestones[].fee_minor`: Integer floor allocation across milestones with remainder pennies distributed deterministically to initial milestones.
|
|
72
|
+
* `commercial_total_fee_usd` / `milestones[].fee_usd`: Derived dollar representation formatted at presentation boundaries (`$33.34`, `$50,000`).
|
|
73
|
+
* Sub-cent fractional budgets (`100.001`) and negative budgets are strictly rejected.
|
|
74
|
+
|
|
75
|
+
## 5. Generation Modes & Machine-Readable Provenance
|
|
76
|
+
|
|
77
|
+
Every generated SOW embeds an immutable `generation_provenance` block:
|
|
78
|
+
|
|
79
|
+
* **`CONTRACTUAL`**: Generated from verified historical run findings or live target; synthetic evidence forbidden.
|
|
80
|
+
* **`DRAFT`**: Generated with preliminary scope or unfinalized commercial terms; requires executive sign-off.
|
|
81
|
+
* **`NON_CONTRACTUAL_SAMPLE`**: Generated with synthetic baseline findings strictly for evaluation/demo (`--sample`).
|
|
82
|
+
|
|
83
|
+
Provenance tracks:
|
|
84
|
+
* `generator_version`: Exact Citable semver.
|
|
85
|
+
* `generated_at`: ISO 8601 timestamp.
|
|
86
|
+
* `source_type`: `HISTORICAL_RUN`, `LIVE_INSPECTION`, `DIRECT_FINDINGS`, or `SAMPLE_BASELINE`.
|
|
87
|
+
* `source_identifier`: Target URL, run ID, or sample identifier.
|
|
88
|
+
* `source_findings_count`: Integer count of evaluated findings.
|
|
89
|
+
* `findings_integrity_hash`: SHA-256 hash of input findings.
|
|
90
|
+
|
|
91
|
+
## 6. SOW Verification Command
|
|
92
|
+
|
|
93
|
+
Run `citable sow validate <sow.json>` to verify:
|
|
94
|
+
1. Strict schema compliance against `schemas/sow.schema.json` (`additionalProperties: false`).
|
|
95
|
+
2. Cross-object invariants via `validateSowInvariants` (fee balancing, work package and deliverable parity, non-empty evidence links).
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze behavioral interaction evidence across funnels, sessions, cohorts, and interaction signals.
|
|
3
|
+
*/
|
|
4
|
+
export function analyzeBehavioralTelemetry(telemetryData = {}) {
|
|
5
|
+
const sessions = telemetryData.sessions || telemetryData.metrics || {};
|
|
6
|
+
const cohorts = telemetryData.cohorts || {};
|
|
7
|
+
const interactions = telemetryData.interactions || {};
|
|
8
|
+
const funnelSteps = telemetryData.funnel || [];
|
|
9
|
+
|
|
10
|
+
const findings = [];
|
|
11
|
+
const frictionIndicators = [];
|
|
12
|
+
|
|
13
|
+
// 1. Mobile vs Desktop Cohort Divergence
|
|
14
|
+
const mobileCr = cohorts.mobile?.conversion_rate ?? null;
|
|
15
|
+
const desktopCr = cohorts.desktop?.conversion_rate ?? null;
|
|
16
|
+
|
|
17
|
+
let cohortDivergence = null;
|
|
18
|
+
if (mobileCr !== null && desktopCr !== null && desktopCr > 0) {
|
|
19
|
+
const ratio = mobileCr / desktopCr;
|
|
20
|
+
cohortDivergence = {
|
|
21
|
+
mobile_cr: mobileCr,
|
|
22
|
+
desktop_cr: desktopCr,
|
|
23
|
+
mobile_to_desktop_ratio: Math.round(ratio * 100) / 100,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (ratio < 0.5) {
|
|
27
|
+
frictionIndicators.push({
|
|
28
|
+
type: 'mobile_conversion_gap',
|
|
29
|
+
severity: 'high',
|
|
30
|
+
evidence: `Mobile conversion rate (${(mobileCr * 100).toFixed(1)}%) is under half of desktop (${(desktopCr * 100).toFixed(1)}%)`,
|
|
31
|
+
hypothesis: 'Mobile friction (virtual keyboard effort, diminutive tap targets, or slow paint) impedes mobile buyers',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 2. Scroll Depth vs CTA Placement
|
|
37
|
+
const p50Scroll = interactions.scroll_depth_p50_pct ?? interactions.median_scroll_depth ?? null;
|
|
38
|
+
const ctaPosition = interactions.primary_cta_vertical_pct ?? null;
|
|
39
|
+
|
|
40
|
+
if (p50Scroll !== null && ctaPosition !== null) {
|
|
41
|
+
if (ctaPosition > p50Scroll) {
|
|
42
|
+
frictionIndicators.push({
|
|
43
|
+
type: 'buried_cta',
|
|
44
|
+
severity: 'high',
|
|
45
|
+
evidence: `Primary CTA is positioned at ${ctaPosition}% page depth, but median user scroll depth is only ${p50Scroll}%`,
|
|
46
|
+
hypothesis: 'Over 50% of visitors never view the primary conversion CTA before abandoning',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. Rage Clicks and Dead Clicks
|
|
52
|
+
const rageClicks = interactions.rage_click_rate_pct ?? interactions.rage_clicks_count ?? 0;
|
|
53
|
+
const deadClicks = interactions.dead_click_rate_pct ?? interactions.dead_clicks_count ?? 0;
|
|
54
|
+
|
|
55
|
+
if (rageClicks > 3 || rageClicks > 50) {
|
|
56
|
+
frictionIndicators.push({
|
|
57
|
+
type: 'rage_clicks',
|
|
58
|
+
severity: 'high',
|
|
59
|
+
evidence: `Elevated rage click frequency (${rageClicks}) indicates user frustration with unresponsive or broken interactive elements`,
|
|
60
|
+
hypothesis: 'Interactive components fail to provide immediate visual feedback or fail on tap',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (deadClicks > 5 || deadClicks > 80) {
|
|
65
|
+
frictionIndicators.push({
|
|
66
|
+
type: 'dead_clicks',
|
|
67
|
+
severity: 'medium',
|
|
68
|
+
evidence: `High dead click count (${deadClicks}): users attempt to click static elements perceived as interactive`,
|
|
69
|
+
hypothesis: 'Visual affordances mislead users into clicking non-actionable elements',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 4. Funnel Drop-off Analysis
|
|
74
|
+
const funnelDropOffs = [];
|
|
75
|
+
if (Array.isArray(funnelSteps) && funnelSteps.length >= 2) {
|
|
76
|
+
for (let i = 0; i < funnelSteps.length - 1; i++) {
|
|
77
|
+
const curr = funnelSteps[i];
|
|
78
|
+
const next = funnelSteps[i + 1];
|
|
79
|
+
const dropOffRate = curr.visitors > 0 ? Math.round(((curr.visitors - next.visitors) / curr.visitors) * 100) : 0;
|
|
80
|
+
funnelDropOffs.push({
|
|
81
|
+
from_step: curr.name || `Step ${i + 1}`,
|
|
82
|
+
to_step: next.name || `Step ${i + 2}`,
|
|
83
|
+
drop_off_pct: dropOffRate,
|
|
84
|
+
retained_visitors: next.visitors,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (dropOffRate > 70) {
|
|
88
|
+
frictionIndicators.push({
|
|
89
|
+
type: 'steep_funnel_leak',
|
|
90
|
+
severity: 'critical',
|
|
91
|
+
evidence: `Severe drop-off between ${curr.name} and ${next.name} (${dropOffRate}% abandon rate)`,
|
|
92
|
+
hypothesis: `Significant cognitive load, price shock, or friction barrier encountered at ${curr.name}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 5. Form Field Abandonment Peak
|
|
99
|
+
const fieldAbandons = interactions.form_field_abandonment || [];
|
|
100
|
+
let peakAbandonField = null;
|
|
101
|
+
if (fieldAbandons.length > 0) {
|
|
102
|
+
fieldAbandons.sort((a, b) => b.abandon_count - a.abandon_count);
|
|
103
|
+
peakAbandonField = fieldAbandons[0];
|
|
104
|
+
frictionIndicators.push({
|
|
105
|
+
type: 'form_field_bottleneck',
|
|
106
|
+
severity: 'high',
|
|
107
|
+
evidence: `Peak form abandonment occurs on field "${peakAbandonField.field_name}" (${peakAbandonField.abandon_count} drop-offs)`,
|
|
108
|
+
hypothesis: `Field "${peakAbandonField.field_name}" creates high friction or privacy resistance; consider making optional or eliminating`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
fact_status: 'observed_behavioral_telemetry',
|
|
114
|
+
summary: {
|
|
115
|
+
total_friction_indicators: frictionIndicators.length,
|
|
116
|
+
critical_indicators: frictionIndicators.filter((i) => i.severity === 'critical').length,
|
|
117
|
+
high_indicators: frictionIndicators.filter((i) => i.severity === 'high').length,
|
|
118
|
+
cohort_divergence: cohortDivergence,
|
|
119
|
+
},
|
|
120
|
+
funnel_drop_offs: funnelDropOffs,
|
|
121
|
+
friction_indicators: frictionIndicators,
|
|
122
|
+
limitations: [
|
|
123
|
+
'Behavioral signals indicate correlation and user interaction bottlenecks; causal mechanisms must be verified via controlled A/B experiments.',
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { parse as parseHtml } from 'node-html-parser';
|
|
2
|
+
import { calculateVisualSaliency } from './saliency.js';
|
|
3
|
+
import { registryPageFor, safePath } from '../detectors/framework.js';
|
|
4
|
+
|
|
5
|
+
const GENERIC_CTA_RX = /^(?:submit|click\s*here|continue|next|send|ok|go|learn\s*more|more)$/i;
|
|
6
|
+
const VALUE_CTA_RX = /\b(get|start|try|claim|unlock|explore|join|download|access|calculate|book|schedule|request)\b/i;
|
|
7
|
+
const RISK_REVERSAL_RX = /\b(no\s*credit\s*card\s*required|cancel\s*anytime|money-back\s*guarantee|\d+-day\s*guarantee|risk-free|free\s*(?:\d+-day\s*)?trial|no\s*commitment|guaranteed)\b/i;
|
|
8
|
+
const SOCIAL_PROOF_RX = /\b(trusted\s*by|over\s*\d+[\d,]*\s*(?:users|customers|teams|companies)|customer\s*reviews?|what\s*(?:our\s*)?customers\s*say|case\s*studies|testimonials?)\b/i;
|
|
9
|
+
const OBJECTION_RX = /\b(frequently\s*asked\s*questions|faq|common\s*questions|how\s*much|pricing\s*details|cancel\s*policy|security\s*standards)\b/i;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Perform comprehensive CRO audit on a page model
|
|
13
|
+
*/
|
|
14
|
+
export function auditPageCro(page, ctx = {}) {
|
|
15
|
+
const html = page.html || '';
|
|
16
|
+
const root = parseHtml(html);
|
|
17
|
+
const text = (page.text || root.textContent || '').replace(/\s+/g, ' ').trim();
|
|
18
|
+
const ctas = page.ctas || [];
|
|
19
|
+
const forms = page.forms || [];
|
|
20
|
+
const trustBadges = page.trustBadges || [];
|
|
21
|
+
const headings = page.headings || [];
|
|
22
|
+
|
|
23
|
+
// -------------------------------------------------------------
|
|
24
|
+
// 1. ABOVE-THE-FOLD (ATF) CLARITY & MESSAGE-MATCH (0-100)
|
|
25
|
+
// -------------------------------------------------------------
|
|
26
|
+
let atfScore = 0;
|
|
27
|
+
const atfSignals = [];
|
|
28
|
+
const atfGaps = [];
|
|
29
|
+
|
|
30
|
+
// Scent match: Title to H1 alignment
|
|
31
|
+
const titleStem = page.title ? page.title.split(/[|—–-]/)[0].trim().toLowerCase() : '';
|
|
32
|
+
const h1Text = (headings.find((h) => h.level === 1)?.text || '').trim();
|
|
33
|
+
const h1Lower = h1Text.toLowerCase();
|
|
34
|
+
|
|
35
|
+
let scentMatch = false;
|
|
36
|
+
if (titleStem && h1Lower) {
|
|
37
|
+
const titleWords = titleStem.split(/\s+/).filter((w) => w.length > 3);
|
|
38
|
+
const matchedWords = titleWords.filter((w) => h1Lower.includes(w));
|
|
39
|
+
if (matchedWords.length >= 1 || titleStem.includes(h1Lower) || h1Lower.includes(titleStem)) {
|
|
40
|
+
scentMatch = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (scentMatch) {
|
|
45
|
+
atfScore += 30;
|
|
46
|
+
atfSignals.push(`Strong information scent: Title and primary H1 corroborate core value proposition ("${h1Text.slice(0, 50)}")`);
|
|
47
|
+
} else if (h1Text) {
|
|
48
|
+
atfScore += 15;
|
|
49
|
+
atfGaps.push(`Scent gap: Primary H1 ("${h1Text.slice(0, 40)}") diverges from title tag ("${titleStem.slice(0, 40)}")`);
|
|
50
|
+
} else {
|
|
51
|
+
atfGaps.push('Missing H1 headline above the fold to establish page purpose');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Hero CTA presence & conspicuity
|
|
55
|
+
const heroCtas = ctas.filter((c) => c.inHero);
|
|
56
|
+
const primaryHeroCta = heroCtas.find((c) => c.isPrimary) || heroCtas[0];
|
|
57
|
+
|
|
58
|
+
const saliency = calculateVisualSaliency({
|
|
59
|
+
ctas: ctas.map((c) => ({ ...c, isPrimary: c.isPrimary })),
|
|
60
|
+
headings: headings.map((h) => ({ level: h.level || 1, text: h.text })),
|
|
61
|
+
forms: forms.map((f) => ({ fieldCount: f.fieldCount })),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const pci = saliency.primary_cta_conspicuity_index || 0;
|
|
65
|
+
|
|
66
|
+
if (primaryHeroCta && pci >= 0.60) {
|
|
67
|
+
atfScore += 30;
|
|
68
|
+
atfSignals.push(`Prominent hero CTA with optimal conspicuity (${Math.round(pci * 100)}% PCI score)`);
|
|
69
|
+
} else if (primaryHeroCta) {
|
|
70
|
+
atfScore += 20;
|
|
71
|
+
atfSignals.push(`Hero CTA present ("${primaryHeroCta.text}") but visual conspicuity is diluted (${Math.round(pci * 100)}% PCI score)`);
|
|
72
|
+
} else {
|
|
73
|
+
atfGaps.push('No primary CTA visible above the fold in the hero viewport');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Choice overload penalty
|
|
77
|
+
if (heroCtas.filter((c) => c.isPrimary).length > 1) {
|
|
78
|
+
atfScore -= 10;
|
|
79
|
+
atfGaps.push(`Choice overload: ${heroCtas.filter((c) => c.isPrimary).length} competing primary CTAs in hero zone induce decision paralysis`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Value proposition lead copy (opening 80 words)
|
|
83
|
+
const firstP = page.paragraphs?.[0] || '';
|
|
84
|
+
if (firstP.length >= 40 && firstP.length <= 400) {
|
|
85
|
+
atfScore += 25;
|
|
86
|
+
atfSignals.push('Concise value proposition paragraph immediately supports hero headline');
|
|
87
|
+
} else if (firstP.length > 400) {
|
|
88
|
+
atfScore += 15;
|
|
89
|
+
atfGaps.push('Opening hero lead text is too verbose (>400 chars); condense into clear benefit bullets');
|
|
90
|
+
} else {
|
|
91
|
+
atfGaps.push('Missing explanatory sub-headline or lead benefit description above the fold');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Supporting micro-signals (risk reversal near hero)
|
|
95
|
+
const heroText = (h1Text + ' ' + firstP + ' ' + (primaryHeroCta?.text || '')).toLowerCase();
|
|
96
|
+
if (RISK_REVERSAL_RX.test(heroText)) {
|
|
97
|
+
atfScore += 15;
|
|
98
|
+
atfSignals.push('Friction-reducing risk reversal (e.g. "No credit card required") placed directly proximate to hero CTA');
|
|
99
|
+
} else {
|
|
100
|
+
atfGaps.push('Add an explicit risk-reversal micro-copy badge under hero CTA (e.g. "Free 14-day trial • No credit card required")');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
atfScore = Math.min(100, Math.max(0, atfScore));
|
|
104
|
+
|
|
105
|
+
// -------------------------------------------------------------
|
|
106
|
+
// 2. UX FRICTION, COGNITIVE LOAD & ABANDONMENT ANALYSIS
|
|
107
|
+
// -------------------------------------------------------------
|
|
108
|
+
const frictionIssues = [];
|
|
109
|
+
let frictionPoints = 0;
|
|
110
|
+
|
|
111
|
+
// Form field count & Keystroke Effort Index (KEI)
|
|
112
|
+
const totalInputs = forms.reduce((sum, f) => sum + (f.fieldCount || 0), 0);
|
|
113
|
+
const inputsWithAutocomplete = forms.reduce((sum, f) => sum + f.inputs.filter((inp) => Boolean(inp.autocomplete)).length, 0);
|
|
114
|
+
const manualKeystrokes = totalInputs * 14;
|
|
115
|
+
const autofillKeystrokes = totalInputs > 0 && inputsWithAutocomplete > 0
|
|
116
|
+
? (totalInputs - inputsWithAutocomplete) * 14 + 1
|
|
117
|
+
: manualKeystrokes;
|
|
118
|
+
const keystrokeReductionPct = manualKeystrokes > 0
|
|
119
|
+
? Math.round(((manualKeystrokes - autofillKeystrokes) / manualKeystrokes) * 100)
|
|
120
|
+
: 0;
|
|
121
|
+
|
|
122
|
+
for (const f of forms) {
|
|
123
|
+
if (f.fieldCount > 6) {
|
|
124
|
+
frictionPoints += 20;
|
|
125
|
+
frictionIssues.push({
|
|
126
|
+
severity: 'high',
|
|
127
|
+
type: 'form_length',
|
|
128
|
+
issue: `Form contains ${f.fieldCount} fields (recommend <= 4 fields for top-of-funnel lead capture)`,
|
|
129
|
+
remediation: 'Progressive profiling: reduce initial form fields to work email and name; capture details on subsequent step',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const missingAuto = f.inputs.filter((inp) => !inp.autocomplete && ['email', 'tel', 'text', 'name'].includes(inp.type));
|
|
134
|
+
if (missingAuto.length > 0) {
|
|
135
|
+
frictionPoints += 10;
|
|
136
|
+
frictionIssues.push({
|
|
137
|
+
severity: 'medium',
|
|
138
|
+
type: 'autocomplete_missing',
|
|
139
|
+
issue: `${missingAuto.length} input field(s) lack HTML5 autocomplete attributes, increasing mobile entry friction`,
|
|
140
|
+
remediation: 'Add standard autocomplete attributes (e.g. autocomplete="email", autocomplete="name", autocomplete="tel")',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!f.hasSubmit) {
|
|
145
|
+
frictionPoints += 30;
|
|
146
|
+
frictionIssues.push({
|
|
147
|
+
severity: 'critical',
|
|
148
|
+
type: 'missing_submit',
|
|
149
|
+
issue: 'Form has no explicit submit button or trigger mechanism',
|
|
150
|
+
remediation: 'Add an accessible <button type="submit"> element with clear action microcopy',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Navigation distraction on conversion surfaces (leaks)
|
|
156
|
+
const reg = registryPageFor(ctx, page);
|
|
157
|
+
const isCheckoutOrCapture = ['checkout', 'pricing', 'signup', 'demo', 'cart'].some((t) => (page.url || '').toLowerCase().includes(t));
|
|
158
|
+
const navLinks = page.navLinksCount || root.querySelectorAll('header nav a, footer a').length;
|
|
159
|
+
|
|
160
|
+
if (isCheckoutOrCapture && navLinks > 15) {
|
|
161
|
+
frictionPoints += 15;
|
|
162
|
+
frictionIssues.push({
|
|
163
|
+
severity: 'medium',
|
|
164
|
+
type: 'funnel_leak',
|
|
165
|
+
issue: `High-intent conversion page contains ${navLinks} external/header navigation links (funnel leak)`,
|
|
166
|
+
remediation: 'Enclose conversion funnel: remove non-essential header navigation and social links during checkout/signup',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Cognitive load index
|
|
171
|
+
let cognitiveLoad = 'minimal';
|
|
172
|
+
if (frictionPoints >= 40) cognitiveLoad = 'critical_friction';
|
|
173
|
+
else if (frictionPoints >= 25) cognitiveLoad = 'high_cognitive_load';
|
|
174
|
+
else if (frictionPoints >= 10) cognitiveLoad = 'moderate';
|
|
175
|
+
|
|
176
|
+
// -------------------------------------------------------------
|
|
177
|
+
// 3. TRUST, CREDIBILITY, OBJECTIONS & RISK-REVERSAL (0-100)
|
|
178
|
+
// -------------------------------------------------------------
|
|
179
|
+
let trustScore = 0;
|
|
180
|
+
const trustSignals = [];
|
|
181
|
+
const trustGaps = [];
|
|
182
|
+
|
|
183
|
+
// Social proof
|
|
184
|
+
const hasSocialProof = SOCIAL_PROOF_RX.test(text) || trustBadges.some((b) => /rating|review|g2|capterra|trustpilot/i.test(b.signal || ''));
|
|
185
|
+
if (hasSocialProof) {
|
|
186
|
+
trustScore += 25;
|
|
187
|
+
trustSignals.push('Customer social proof and review signals detected');
|
|
188
|
+
} else {
|
|
189
|
+
trustGaps.push('Add customer social proof (client logos, quantitative adoption stats, or verified review quotes)');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Security credentials & badges
|
|
193
|
+
const hasSecurityBadge = trustBadges.some((b) => /security|ssl|soc-?2|iso|hipaa|pci|verified/i.test(b.signal || '')) ||
|
|
194
|
+
Boolean(root.querySelector('[class*="security"], [class*="trust"], [class*="badge"]'));
|
|
195
|
+
if (hasSecurityBadge) {
|
|
196
|
+
trustScore += 25;
|
|
197
|
+
trustSignals.push('Security compliance, SSL, or verification badges present');
|
|
198
|
+
} else {
|
|
199
|
+
trustGaps.push('Display enterprise security credentials (SOC-2, ISO, HIPAA, or encryption badges) proximate to conversion action');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Risk reversal
|
|
203
|
+
const hasRiskReversal = RISK_REVERSAL_RX.test(text);
|
|
204
|
+
if (hasRiskReversal) {
|
|
205
|
+
trustScore += 25;
|
|
206
|
+
trustSignals.push('Explicit risk-reversal guarantees present (money-back guarantee, free trial, or cancel anytime)');
|
|
207
|
+
} else {
|
|
208
|
+
trustGaps.push('Eliminate buyer perceived risk with explicit guarantees ("Cancel anytime", "30-day money back guarantee")');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Objection handling (FAQ or comparison)
|
|
212
|
+
const hasObjectionHandling = OBJECTION_RX.test(text) || root.querySelectorAll('details, .faq, #faq').length > 0;
|
|
213
|
+
if (hasObjectionHandling) {
|
|
214
|
+
trustScore += 25;
|
|
215
|
+
trustSignals.push('Pre-purchase objection handling and structured FAQ content detected');
|
|
216
|
+
} else {
|
|
217
|
+
trustGaps.push('Include a pre-purchase FAQ addressing common pricing, onboarding, and contract objections');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
trustScore = Math.min(100, Math.max(0, trustScore));
|
|
221
|
+
|
|
222
|
+
// -------------------------------------------------------------
|
|
223
|
+
// 4. OFFER ARCHITECTURE & CTA HIERARCHY
|
|
224
|
+
// -------------------------------------------------------------
|
|
225
|
+
const offerFindings = [];
|
|
226
|
+
let primaryCtaCount = 0;
|
|
227
|
+
let genericCtaCount = 0;
|
|
228
|
+
|
|
229
|
+
for (const cta of ctas) {
|
|
230
|
+
if (cta.isPrimary) primaryCtaCount++;
|
|
231
|
+
if (GENERIC_CTA_RX.test(cta.text)) {
|
|
232
|
+
genericCtaCount++;
|
|
233
|
+
offerFindings.push({
|
|
234
|
+
cta: cta.text,
|
|
235
|
+
type: 'generic_microcopy',
|
|
236
|
+
remediation: `Replace low-intent generic copy "${cta.text}" with high-value benefit action copy (e.g. "Get Started Free", "Claim Your Audit")`,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const ctaHierarchy = {
|
|
242
|
+
total_ctas: ctas.length,
|
|
243
|
+
primary_ctas: primaryCtaCount,
|
|
244
|
+
secondary_ctas: ctas.length - primaryCtaCount,
|
|
245
|
+
generic_microcopy_count: genericCtaCount,
|
|
246
|
+
hierarchy_status: primaryCtaCount === 1 ? 'optimal' : primaryCtaCount > 1 ? 'choice_overload' : 'missing_primary',
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Express checkout
|
|
250
|
+
const walletRx = /apple\s*pay|google\s*pay|paypal|one-click/i;
|
|
251
|
+
const hasExpressPayment = ctas.some((c) => walletRx.test(c.text || '')) ||
|
|
252
|
+
trustBadges.some((t) => walletRx.test(t.signal || ''));
|
|
253
|
+
|
|
254
|
+
// -------------------------------------------------------------
|
|
255
|
+
// OVERALL CONVERSION READINESS SCORE (0-100)
|
|
256
|
+
// -------------------------------------------------------------
|
|
257
|
+
const conversionReadiness = Math.round(
|
|
258
|
+
(atfScore * 0.35) +
|
|
259
|
+
(trustScore * 0.30) +
|
|
260
|
+
(Math.max(0, 100 - frictionPoints) * 0.25) +
|
|
261
|
+
(ctaHierarchy.hierarchy_status === 'optimal' ? 10 : 5)
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
url: page.url,
|
|
266
|
+
fact_status: 'modeled_cro_evaluation',
|
|
267
|
+
conversion_readiness_score: conversionReadiness,
|
|
268
|
+
atf_clarity: {
|
|
269
|
+
score: atfScore,
|
|
270
|
+
scent_match: scentMatch,
|
|
271
|
+
title_stem: titleStem,
|
|
272
|
+
h1_headline: h1Text,
|
|
273
|
+
pci_score_pct: Math.round(pci * 100),
|
|
274
|
+
signals: atfSignals,
|
|
275
|
+
gaps: atfGaps,
|
|
276
|
+
},
|
|
277
|
+
cognitive_load_and_friction: {
|
|
278
|
+
load_assessment: cognitiveLoad,
|
|
279
|
+
friction_points: frictionPoints,
|
|
280
|
+
keystroke_effort: {
|
|
281
|
+
total_inputs: totalInputs,
|
|
282
|
+
inputs_with_autocomplete: inputsWithAutocomplete,
|
|
283
|
+
keystroke_reduction_pct: keystrokeReductionPct,
|
|
284
|
+
},
|
|
285
|
+
issues: frictionIssues,
|
|
286
|
+
},
|
|
287
|
+
trust_and_credibility: {
|
|
288
|
+
score: trustScore,
|
|
289
|
+
signals: trustSignals,
|
|
290
|
+
gaps: trustGaps,
|
|
291
|
+
social_proof_detected: hasSocialProof,
|
|
292
|
+
security_badges_detected: hasSecurityBadge,
|
|
293
|
+
risk_reversal_detected: hasRiskReversal,
|
|
294
|
+
objection_handling_detected: hasObjectionHandling,
|
|
295
|
+
},
|
|
296
|
+
offer_architecture: {
|
|
297
|
+
cta_hierarchy: ctaHierarchy,
|
|
298
|
+
express_checkout_supported: hasExpressPayment,
|
|
299
|
+
findings: offerFindings,
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
}
|