@nebulacomponents/citable 1.18.1 → 1.18.2

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 (135) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/universal/.agents/skills/citable/SKILL.md +1 -1
  3. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  4. package/dist/universal/.agents/skills/citable/commands/artifact-interchange.md +5 -0
  5. package/dist/universal/.agents/skills/citable/commands/remediation.md +1 -1
  6. package/dist/universal/.agents/skills/citable/commands/sow.md +2 -2
  7. package/dist/universal/.agents/skills/citable/manifest.json +11 -9
  8. package/dist/universal/.agents/skills/citable/schemas/cro-report.schema.json +112 -0
  9. package/dist/universal/.agents/skills/citable/schemas/search-report.schema.json +99 -0
  10. package/dist/universal/.agents/skills/citable/schemas/sow.schema.json +3 -2
  11. package/dist/universal/.claude/agents/citable/manifest.json +2 -2
  12. package/dist/universal/.claude/skills/citable/SKILL.md +1 -1
  13. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  14. package/dist/universal/.claude/skills/citable/commands/artifact-interchange.md +5 -0
  15. package/dist/universal/.claude/skills/citable/commands/remediation.md +1 -1
  16. package/dist/universal/.claude/skills/citable/commands/sow.md +2 -2
  17. package/dist/universal/.claude/skills/citable/manifest.json +11 -9
  18. package/dist/universal/.claude/skills/citable/schemas/cro-report.schema.json +112 -0
  19. package/dist/universal/.claude/skills/citable/schemas/search-report.schema.json +99 -0
  20. package/dist/universal/.claude/skills/citable/schemas/sow.schema.json +3 -2
  21. package/dist/universal/.cursor/skills/citable/SKILL.md +1 -1
  22. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  23. package/dist/universal/.cursor/skills/citable/commands/artifact-interchange.md +5 -0
  24. package/dist/universal/.cursor/skills/citable/commands/remediation.md +1 -1
  25. package/dist/universal/.cursor/skills/citable/commands/sow.md +2 -2
  26. package/dist/universal/.cursor/skills/citable/manifest.json +11 -9
  27. package/dist/universal/.cursor/skills/citable/schemas/cro-report.schema.json +112 -0
  28. package/dist/universal/.cursor/skills/citable/schemas/search-report.schema.json +99 -0
  29. package/dist/universal/.cursor/skills/citable/schemas/sow.schema.json +3 -2
  30. package/dist/universal/.gemini/skills/citable/SKILL.md +1 -1
  31. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  32. package/dist/universal/.gemini/skills/citable/commands/artifact-interchange.md +5 -0
  33. package/dist/universal/.gemini/skills/citable/commands/remediation.md +1 -1
  34. package/dist/universal/.gemini/skills/citable/commands/sow.md +2 -2
  35. package/dist/universal/.gemini/skills/citable/manifest.json +11 -9
  36. package/dist/universal/.gemini/skills/citable/schemas/cro-report.schema.json +112 -0
  37. package/dist/universal/.gemini/skills/citable/schemas/search-report.schema.json +99 -0
  38. package/dist/universal/.gemini/skills/citable/schemas/sow.schema.json +3 -2
  39. package/dist/universal/.github/skills/citable/SKILL.md +1 -1
  40. package/dist/universal/.github/skills/citable/VERSION +1 -1
  41. package/dist/universal/.github/skills/citable/commands/artifact-interchange.md +5 -0
  42. package/dist/universal/.github/skills/citable/commands/remediation.md +1 -1
  43. package/dist/universal/.github/skills/citable/commands/sow.md +2 -2
  44. package/dist/universal/.github/skills/citable/manifest.json +11 -9
  45. package/dist/universal/.github/skills/citable/schemas/cro-report.schema.json +112 -0
  46. package/dist/universal/.github/skills/citable/schemas/search-report.schema.json +99 -0
  47. package/dist/universal/.github/skills/citable/schemas/sow.schema.json +3 -2
  48. package/dist/universal/.kiro/skills/citable/SKILL.md +1 -1
  49. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  50. package/dist/universal/.kiro/skills/citable/commands/artifact-interchange.md +5 -0
  51. package/dist/universal/.kiro/skills/citable/commands/remediation.md +1 -1
  52. package/dist/universal/.kiro/skills/citable/commands/sow.md +2 -2
  53. package/dist/universal/.kiro/skills/citable/manifest.json +11 -9
  54. package/dist/universal/.kiro/skills/citable/schemas/cro-report.schema.json +112 -0
  55. package/dist/universal/.kiro/skills/citable/schemas/search-report.schema.json +99 -0
  56. package/dist/universal/.kiro/skills/citable/schemas/sow.schema.json +3 -2
  57. package/dist/universal/.opencode/skills/citable/SKILL.md +1 -1
  58. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  59. package/dist/universal/.opencode/skills/citable/commands/artifact-interchange.md +5 -0
  60. package/dist/universal/.opencode/skills/citable/commands/remediation.md +1 -1
  61. package/dist/universal/.opencode/skills/citable/commands/sow.md +2 -2
  62. package/dist/universal/.opencode/skills/citable/manifest.json +11 -9
  63. package/dist/universal/.opencode/skills/citable/schemas/cro-report.schema.json +112 -0
  64. package/dist/universal/.opencode/skills/citable/schemas/search-report.schema.json +99 -0
  65. package/dist/universal/.opencode/skills/citable/schemas/sow.schema.json +3 -2
  66. package/dist/universal/.pi/agent/skills/citable/SKILL.md +1 -1
  67. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  68. package/dist/universal/.pi/agent/skills/citable/commands/artifact-interchange.md +5 -0
  69. package/dist/universal/.pi/agent/skills/citable/commands/remediation.md +1 -1
  70. package/dist/universal/.pi/agent/skills/citable/commands/sow.md +2 -2
  71. package/dist/universal/.pi/agent/skills/citable/manifest.json +11 -9
  72. package/dist/universal/.pi/agent/skills/citable/schemas/cro-report.schema.json +112 -0
  73. package/dist/universal/.pi/agent/skills/citable/schemas/search-report.schema.json +99 -0
  74. package/dist/universal/.pi/agent/skills/citable/schemas/sow.schema.json +3 -2
  75. package/dist/universal/.qoder/skills/citable/SKILL.md +1 -1
  76. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  77. package/dist/universal/.qoder/skills/citable/commands/artifact-interchange.md +5 -0
  78. package/dist/universal/.qoder/skills/citable/commands/remediation.md +1 -1
  79. package/dist/universal/.qoder/skills/citable/commands/sow.md +2 -2
  80. package/dist/universal/.qoder/skills/citable/manifest.json +11 -9
  81. package/dist/universal/.qoder/skills/citable/schemas/cro-report.schema.json +112 -0
  82. package/dist/universal/.qoder/skills/citable/schemas/search-report.schema.json +99 -0
  83. package/dist/universal/.qoder/skills/citable/schemas/sow.schema.json +3 -2
  84. package/dist/universal/.rovodev/skills/citable/SKILL.md +1 -1
  85. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  86. package/dist/universal/.rovodev/skills/citable/commands/artifact-interchange.md +5 -0
  87. package/dist/universal/.rovodev/skills/citable/commands/remediation.md +1 -1
  88. package/dist/universal/.rovodev/skills/citable/commands/sow.md +2 -2
  89. package/dist/universal/.rovodev/skills/citable/manifest.json +11 -9
  90. package/dist/universal/.rovodev/skills/citable/schemas/cro-report.schema.json +112 -0
  91. package/dist/universal/.rovodev/skills/citable/schemas/search-report.schema.json +99 -0
  92. package/dist/universal/.rovodev/skills/citable/schemas/sow.schema.json +3 -2
  93. package/dist/universal/.trae/skills/citable/SKILL.md +1 -1
  94. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  95. package/dist/universal/.trae/skills/citable/commands/artifact-interchange.md +5 -0
  96. package/dist/universal/.trae/skills/citable/commands/remediation.md +1 -1
  97. package/dist/universal/.trae/skills/citable/commands/sow.md +2 -2
  98. package/dist/universal/.trae/skills/citable/manifest.json +11 -9
  99. package/dist/universal/.trae/skills/citable/schemas/cro-report.schema.json +112 -0
  100. package/dist/universal/.trae/skills/citable/schemas/search-report.schema.json +99 -0
  101. package/dist/universal/.trae/skills/citable/schemas/sow.schema.json +3 -2
  102. package/dist/universal/.trae-cn/skills/citable/SKILL.md +1 -1
  103. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  104. package/dist/universal/.trae-cn/skills/citable/commands/artifact-interchange.md +5 -0
  105. package/dist/universal/.trae-cn/skills/citable/commands/remediation.md +1 -1
  106. package/dist/universal/.trae-cn/skills/citable/commands/sow.md +2 -2
  107. package/dist/universal/.trae-cn/skills/citable/manifest.json +11 -9
  108. package/dist/universal/.trae-cn/skills/citable/schemas/cro-report.schema.json +112 -0
  109. package/dist/universal/.trae-cn/skills/citable/schemas/search-report.schema.json +99 -0
  110. package/dist/universal/.trae-cn/skills/citable/schemas/sow.schema.json +3 -2
  111. package/dist/universal/manifest.json +136 -112
  112. package/package.json +2 -1
  113. package/schemas/cro-report.schema.json +112 -0
  114. package/schemas/search-report.schema.json +99 -0
  115. package/schemas/sow.schema.json +3 -2
  116. package/skill/SKILL.md +1 -1
  117. package/skill/commands/artifact-interchange.md +5 -0
  118. package/skill/commands/remediation.md +1 -1
  119. package/skill/commands/sow.md +2 -2
  120. package/src/analysis/behavioral.js +5 -4
  121. package/src/analysis/eeat.js +10 -9
  122. package/src/analysis/offpage.js +19 -36
  123. package/src/analysis/readiness.js +8 -2
  124. package/src/artifacts/verifyCustomerArtifact.js +283 -0
  125. package/src/cli/index.js +8 -1
  126. package/src/reporting/executiveCroReport.js +393 -229
  127. package/src/reporting/executiveExport.js +6 -2
  128. package/src/reporting/executiveSearchReport.js +519 -271
  129. package/src/shared/domainUtils.js +140 -0
  130. package/src/shared/epistemicStatus.js +111 -0
  131. package/src/shared/evidenceSourceResolver.js +286 -0
  132. package/src/shared/htmlEscape.js +65 -0
  133. package/src/shared/runPackageVerifier.js +153 -0
  134. package/src/sow/admissibilityGate.js +20 -2
  135. package/src/sow/generateSow.js +125 -159
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebulacomponents/citable",
3
- "version": "1.18.1",
3
+ "version": "1.18.2",
4
4
  "description": "Production-grade SEO, AEO, and GEO agent skill with auditable detection, claim governance, evidence validation, and multi-agent installation.",
5
5
  "keywords": [
6
6
  "seo",
@@ -52,6 +52,7 @@
52
52
  "test:integration": "node --test --test-concurrency=1 --test-reporter=spec 'tests/integration/**/*.test.js'",
53
53
  "test:e2e": "node --test --test-concurrency=1 'tests/e2e/**/*.test.js'",
54
54
  "build:dist": "node scripts/build-dist.js",
55
+ "validate:schemas": "node scripts/validate-schemas.js",
55
56
  "release:prepare": "node scripts/release-process.js prepare",
56
57
  "release:validate": "node scripts/release-process.js validate",
57
58
  "release:manifest": "node scripts/release-governance.js manifest",
@@ -0,0 +1,112 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "citable://schemas/cro-report.schema.json",
4
+ "title": "Enterprise CRO & Journey Intelligence Executive Report",
5
+ "type": "object",
6
+ "required": [
7
+ "fact_status",
8
+ "report_title",
9
+ "client_name",
10
+ "target_domain",
11
+ "generated_at",
12
+ "overall_conversion_readiness",
13
+ "pillars",
14
+ "evidence_register",
15
+ "decision_summary",
16
+ "generation_provenance"
17
+ ],
18
+ "properties": {
19
+ "$schema": { "type": "string" },
20
+ "fact_status": { "type": "string" },
21
+ "epistemic_status": { "type": "string" },
22
+ "report_title": { "type": "string" },
23
+ "client_name": { "type": "string" },
24
+ "target_domain": { "type": "string" },
25
+ "generated_at": { "type": "string" },
26
+ "overall_conversion_readiness": { "type": "number", "minimum": 0, "maximum": 100 },
27
+ "epistemological_framework": {
28
+ "type": "object",
29
+ "properties": {
30
+ "observation": { "type": "string" },
31
+ "hypothesis": { "type": "string" },
32
+ "causation": { "type": "string" },
33
+ "unknowns": { "type": "string" }
34
+ }
35
+ },
36
+ "pillars": {
37
+ "type": "object",
38
+ "required": [
39
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
40
+ "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
41
+ "21", "22", "23", "24", "25"
42
+ ],
43
+ "additionalProperties": false,
44
+ "patternProperties": {
45
+ "^[0-9]+$": {
46
+ "type": "object",
47
+ "required": ["name", "data"],
48
+ "properties": {
49
+ "name": { "type": "string" },
50
+ "data": {}
51
+ }
52
+ }
53
+ }
54
+ },
55
+ "evidence_register": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "object",
59
+ "required": ["evidence_id", "source", "methodology", "confidence_level"],
60
+ "properties": {
61
+ "evidence_id": { "type": "string", "pattern": "^EVD-CRO-[0-9]+$" },
62
+ "source": { "type": "string" },
63
+ "title": { "type": "string" },
64
+ "observation_date": { "type": "string" },
65
+ "methodology": { "type": "string" },
66
+ "confidence_level": { "type": "string" },
67
+ "data_snapshot": {}
68
+ }
69
+ }
70
+ },
71
+ "decision_summary": {
72
+ "type": "object",
73
+ "required": [
74
+ "observed_conversion_failures",
75
+ "evidence_supported_hypotheses",
76
+ "causal_findings",
77
+ "unresolved_unknowns",
78
+ "recommended_interventions"
79
+ ],
80
+ "properties": {
81
+ "observed_conversion_failures": { "type": "array", "items": { "type": "string" } },
82
+ "evidence_supported_hypotheses": { "type": "array", "items": { "type": "string" } },
83
+ "causal_findings": { "type": "array", "items": { "type": "string" } },
84
+ "unresolved_unknowns": { "type": "array", "items": { "type": "string" } },
85
+ "recommended_interventions": { "type": "array", "items": { "type": "string" } }
86
+ },
87
+ "additionalProperties": false
88
+ },
89
+ "generation_provenance": {
90
+ "type": "object",
91
+ "required": [
92
+ "generated_at",
93
+ "generator_version",
94
+ "generation_mode",
95
+ "source_type",
96
+ "synthetic_evidence"
97
+ ],
98
+ "properties": {
99
+ "generated_at": { "type": "string" },
100
+ "generator_version": { "type": "string" },
101
+ "generation_mode": { "type": "string", "enum": ["CONTRACTUAL", "DRAFT", "NON_CONTRACTUAL_SAMPLE"] },
102
+ "source_type": { "type": "string" },
103
+ "source_identifier": { "type": ["string", "null"] },
104
+ "source_findings_count": { "type": "integer", "minimum": 0 },
105
+ "integrity_hash": { "type": ["string", "null"] },
106
+ "synthetic_evidence": { "type": "boolean" }
107
+ },
108
+ "additionalProperties": false
109
+ }
110
+ },
111
+ "additionalProperties": false
112
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "citable://schemas/search-report.schema.json",
4
+ "title": "Enterprise Search Intelligence & Governance Executive Report",
5
+ "type": "object",
6
+ "required": [
7
+ "fact_status",
8
+ "report_title",
9
+ "client_name",
10
+ "target_domain",
11
+ "generated_at",
12
+ "overall_readiness_score",
13
+ "pillars",
14
+ "evidence_register",
15
+ "decision_summary",
16
+ "generation_provenance"
17
+ ],
18
+ "properties": {
19
+ "$schema": { "type": "string" },
20
+ "fact_status": { "type": "string" },
21
+ "epistemic_status": { "type": "string" },
22
+ "report_title": { "type": "string" },
23
+ "client_name": { "type": "string" },
24
+ "target_domain": { "type": "string" },
25
+ "generated_at": { "type": "string" },
26
+ "overall_readiness_score": { "type": "number", "minimum": 0, "maximum": 100 },
27
+ "pillars": {
28
+ "type": "object",
29
+ "required": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
30
+ "additionalProperties": false,
31
+ "patternProperties": {
32
+ "^[0-9]+$": {
33
+ "type": "object",
34
+ "required": ["name", "data"],
35
+ "properties": {
36
+ "name": { "type": "string" },
37
+ "data": {}
38
+ }
39
+ }
40
+ }
41
+ },
42
+ "evidence_register": {
43
+ "type": "array",
44
+ "items": {
45
+ "type": "object",
46
+ "required": ["evidence_id", "source", "methodology", "confidence_level"],
47
+ "properties": {
48
+ "evidence_id": { "type": "string", "pattern": "^EVD-SRCH-[0-9]+$" },
49
+ "source": { "type": "string" },
50
+ "title": { "type": "string" },
51
+ "observation_date": { "type": "string" },
52
+ "methodology": { "type": "string" },
53
+ "confidence_level": { "type": "string" },
54
+ "data_snapshot": {}
55
+ }
56
+ }
57
+ },
58
+ "decision_summary": {
59
+ "type": "object",
60
+ "required": [
61
+ "confirmed_findings",
62
+ "inferred_opportunities",
63
+ "unresolved_unknowns",
64
+ "strategic_risks",
65
+ "actions_requiring_leadership_approval"
66
+ ],
67
+ "properties": {
68
+ "confirmed_findings": { "type": "array", "items": { "type": "string" } },
69
+ "inferred_opportunities": { "type": "array", "items": { "type": "string" } },
70
+ "unresolved_unknowns": { "type": "array", "items": { "type": "string" } },
71
+ "strategic_risks": { "type": "array", "items": { "type": "string" } },
72
+ "actions_requiring_leadership_approval": { "type": "array", "items": { "type": "string" } }
73
+ },
74
+ "additionalProperties": false
75
+ },
76
+ "generation_provenance": {
77
+ "type": "object",
78
+ "required": [
79
+ "generated_at",
80
+ "generator_version",
81
+ "generation_mode",
82
+ "source_type",
83
+ "synthetic_evidence"
84
+ ],
85
+ "properties": {
86
+ "generated_at": { "type": "string" },
87
+ "generator_version": { "type": "string" },
88
+ "generation_mode": { "type": "string", "enum": ["CONTRACTUAL", "DRAFT", "NON_CONTRACTUAL_SAMPLE"] },
89
+ "source_type": { "type": "string" },
90
+ "source_identifier": { "type": ["string", "null"] },
91
+ "source_findings_count": { "type": "integer", "minimum": 0 },
92
+ "integrity_hash": { "type": ["string", "null"] },
93
+ "synthetic_evidence": { "type": "boolean" }
94
+ },
95
+ "additionalProperties": false
96
+ }
97
+ },
98
+ "additionalProperties": false
99
+ }
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "additionalProperties": false
54
54
  },
55
- "effective_date": { "type": "string" },
55
+ "effective_date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
56
56
  "term_days": { "type": "integer", "minimum": 1 },
57
57
  "currency": { "type": "string", "enum": ["USD"] },
58
58
  "currency_minor_unit_exponent": { "type": "integer", "enum": [2] },
@@ -377,7 +377,8 @@
377
377
  "evidence_ids": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
378
378
  "severity": { "type": "string" },
379
379
  "target_subject": { "type": "string" },
380
- "acceptance_criteria": { "type": "string" }
380
+ "acceptance_criteria": { "type": "string" },
381
+ "acceptance_basis": { "type": "string" }
381
382
  },
382
383
  "additionalProperties": false
383
384
  }
package/skill/SKILL.md CHANGED
@@ -7,7 +7,7 @@ description: >
7
7
  generative engine optimization, structured data governance, claim substantiation,
8
8
  crawler policy, entity consistency, content discoverability, or wants a site audited
9
9
  for how search and AI systems will retrieve, understand, cite, or recommend it.
10
- version: 1.18.1
10
+ version: 1.18.2
11
11
  ---
12
12
 
13
13
  # Citable — evidence and change control for search and AI citation readiness
@@ -7,6 +7,7 @@ external workspaces without changing its canonical bytes.
7
7
  citable artifacts export <run-id> --output <directory>
8
8
  citable artifacts verify --input <directory>
9
9
  citable artifacts import --input <directory>
10
+ citable artifacts verify-customer <file>
10
11
  ```
11
12
 
12
13
  An export contains the original run package plus
@@ -26,3 +27,7 @@ was authentic, that external observations were representative or complete, or
26
27
  that an intervention caused an outcome. Hosted tenancy, authentication,
27
28
  storage, retention, billing, scheduling, and dashboards are outside this
28
29
  contract.
30
+
31
+ Use `citable artifacts verify-customer <file>` to validate customer deliverables
32
+ (SOW, Search, and CRO JSON reports) against their JSON Schemas, verify arithmetic
33
+ consistency (e.g. minor-unit fee totals), and reject unescaped script or event handler injections.
@@ -12,7 +12,7 @@ The remediation suite provides safe, gated code fixes for deterministic technica
12
12
 
13
13
  ## 1. Safe Patch Application (`citable remediate`)
14
14
 
15
- 1. **Framework Detection**: Identifies target source syntax (`jsx`, `tsx`, `vue`, `html`). Fails closed on unknown or ambiguous frameworks.
15
+ 1. **Framework Detection**: Identifies target source syntax (`jsx`, `tsx`, `vue`, `svelte`, `html`). Fails closed on unknown or ambiguous frameworks.
16
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
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
18
  4. **Confidence Threshold**: Computes an explicit multi-factor confidence score (`computeConfidence`). `--write` is refused if confidence falls below `0.70`.
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
3
+ purpose: Generate a contractually binding, evidence-traceable enterprise Statement of Work (SOW) from verified audit findings through a formal 8-gate scope admissibility filter and 7-column traceability matrix.
4
4
  preconditions: [at least one finalized audit run with verified findings or live target; sample mode required for synthetic demonstrations]
5
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
6
  artifacts_created: [SOW.md, SOW.html, or SOW.json at specified output path]
@@ -34,7 +34,7 @@ Acceptance Test (automated closed-loop detector rerun)
34
34
 
35
35
  ## 2. The Scope Admissibility Gate
36
36
 
37
- Audit findings do NOT automatically become contractual obligations. Every candidate finding must pass 7 admissibility gates:
37
+ Audit findings do NOT automatically become contractual obligations. Every candidate finding must pass 8 admissibility gates:
38
38
 
39
39
  | Gate | Verification Check | Failure Refusal Code | Contractual Handling |
40
40
  | :--- | :--- | :--- | :--- |
@@ -2,10 +2,11 @@
2
2
  * Analyze behavioral interaction evidence across funnels, sessions, cohorts, and interaction signals.
3
3
  */
4
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 || [];
5
+ const data = telemetryData || {};
6
+ const sessions = data.sessions || data.metrics || {};
7
+ const cohorts = data.cohorts || {};
8
+ const interactions = data.interactions || {};
9
+ const funnelSteps = data.funnel || [];
9
10
 
10
11
  const findings = [];
11
12
  const frictionIndicators = [];
@@ -1,5 +1,6 @@
1
1
  import { parse as parseHtml } from 'node-html-parser';
2
2
  import { registryPageFor, safePath } from '../detectors/framework.js';
3
+ import { isAuthoritativeDomain } from '../shared/domainUtils.js';
3
4
 
4
5
  /**
5
6
  * Evaluates on-page content against Google's E-E-A-T rubric on a 0.0 - 5.0 scale.
@@ -101,7 +102,7 @@ export function evaluateEeat(page, ctx = {}) {
101
102
  const BIO_RX = /\b(?:ph\.?d|m\.?d|engineer|architect|researcher|director|specialist|consultant|analyst|professor|founder|lead)\b/i;
102
103
  if (authorSameAs || BIO_RX.test(text)) {
103
104
  expertScore += 1.2;
104
- expertSignals.push('Author credentials, professional title, or external disambiguation profiles verified');
105
+ expertSignals.push(authorSameAs ? 'Author disambiguation profile linked' : 'Author professional title or credentials indicator detected');
105
106
  } else {
106
107
  expertMissing.push('Link author to authoritative profile (sameAs: LinkedIn, ORCID, GitHub) and list credentials');
107
108
  }
@@ -132,12 +133,7 @@ export function evaluateEeat(page, ctx = {}) {
132
133
  }));
133
134
 
134
135
  const externalLinks = links.filter((l) => /^https?:\/\//i.test(l.href));
135
- const authoritativeDomains = externalLinks.filter((l) => {
136
- const u = l.href.toLowerCase();
137
- return u.includes('.edu') || u.includes('.gov') || u.includes('.org') ||
138
- u.includes('w3.org') || u.includes('rfc-editor.org') || u.includes('github.com') ||
139
- u.includes('arxiv.org') || u.includes('developer.mozilla.org') || u.includes('web.dev');
140
- });
136
+ const authoritativeDomains = externalLinks.filter((l) => isAuthoritativeDomain(l.href));
141
137
 
142
138
  if (authoritativeDomains.length >= 2) {
143
139
  authScore += 1.5;
@@ -150,9 +146,13 @@ export function evaluateEeat(page, ctx = {}) {
150
146
  authMissing.push('Add outbound citations to primary sources and industry standards');
151
147
  }
152
148
 
153
- // Registry claim grounding
149
+ // Registry claim grounding (strictly page-scoped)
154
150
  const claims = ctx.registries?.claims?.entries || [];
155
- const pageClaims = claims.filter((c) => c.canonical_url === page.url || c.claim_id);
151
+ const pageClaims = claims.filter((c) => {
152
+ if (!c) return false;
153
+ const target = c.canonical_url || c.subject?.url || c.page_id;
154
+ return Boolean(target && (target === page.url || target === page.canonicalUrl));
155
+ });
156
156
  const verifiedClaims = pageClaims.filter((c) => c.status === 'verified');
157
157
  if (verifiedClaims.length >= 1) {
158
158
  authScore += 1.5;
@@ -259,6 +259,7 @@ export function evaluateEeat(page, ctx = {}) {
259
259
  return {
260
260
  url: page.url,
261
261
  fact_status: 'modeled_rubric_evaluation',
262
+ epistemic_status: 'MODELED',
262
263
  methodology: 'Google Search Quality Rater Guidelines (E-E-A-T Evaluative Rubric)',
263
264
  disclaimer: 'E-E-A-T is an evaluative heuristic rubric modeled on Quality Rater Guidelines, not an algorithmic ranking score. Google does not calculate a single E-E-A-T metric.',
264
265
  composite_score: composite,
@@ -1,4 +1,5 @@
1
1
  import { URL } from 'node:url';
2
+ import { extractHostname, extractRegistrableDomain, extractPublicSuffix } from '../shared/domainUtils.js';
2
3
 
3
4
  const SPAM_TLDS = new Set([
4
5
  'top', 'work', 'gdn', 'click', 'monster', 'buzz', 'cfd', 'sbs',
@@ -7,27 +8,6 @@ const SPAM_TLDS = new Set([
7
8
 
8
9
  const COMMERCIAL_SPAM_KEYWORDS = /\b(casino|viagra|cialis|payday\s*loans?|replica|cheap\s*essay|free\s*download|warez|crack|hack|gambling|betting|slots|crypto\s*airdrop)\b/i;
9
10
 
10
- function extractHostname(urlString) {
11
- try {
12
- return new URL(urlString).hostname.toLowerCase();
13
- } catch {
14
- return null;
15
- }
16
- }
17
-
18
- function extractRootDomain(hostname) {
19
- if (!hostname) return null;
20
- const parts = hostname.split('.');
21
- if (parts.length <= 2) return hostname;
22
- return parts.slice(-2).join('.');
23
- }
24
-
25
- function extractTld(hostname) {
26
- if (!hostname) return null;
27
- const parts = hostname.split('.');
28
- return parts.at(-1) || null;
29
- }
30
-
31
11
  /**
32
12
  * Audit an inbound backlink profile for authority distribution and toxic domain risks.
33
13
  */
@@ -59,18 +39,18 @@ export function auditBacklinkProfile(backlinks, { targetDomain = null } = {}) {
59
39
  for (const link of links) {
60
40
  const srcHost = extractHostname(link.source_url);
61
41
  if (!srcHost) continue;
62
- const rootDomain = extractRootDomain(srcHost) || srcHost;
63
- const tld = extractTld(srcHost);
42
+ const rootDomain = extractRegistrableDomain(srcHost) || srcHost;
43
+ const tld = extractPublicSuffix(srcHost);
64
44
  const anchor = (link.anchor_text || '').trim();
65
- const rel = (link.rel || '').toLowerCase();
66
- const isNofollow = rel.includes('nofollow');
67
- const isUgc = rel.includes('ugc');
68
- const isSponsored = rel.includes('sponsored');
45
+ const relTokens = (link.rel || '').toLowerCase().split(/\s+/).filter(Boolean);
46
+ const isNofollow = relTokens.includes('nofollow');
47
+ const isUgc = relTokens.includes('ugc');
48
+ const isSponsored = relTokens.includes('sponsored');
69
49
 
70
50
  if (isNofollow) nofollowCount++;
71
- else if (isUgc) ugcCount++;
72
- else if (isSponsored) sponsoredCount++;
73
- else dofollowCount++;
51
+ if (isUgc) ugcCount++;
52
+ if (isSponsored) sponsoredCount++;
53
+ if (!isNofollow && !isUgc && !isSponsored) dofollowCount++;
74
54
 
75
55
  // Deep link vs homepage
76
56
  const targetPath = link.target_url ? (() => { try { return new URL(link.target_url).pathname; } catch { return '/'; } })() : '/';
@@ -78,13 +58,13 @@ export function auditBacklinkProfile(backlinks, { targetDomain = null } = {}) {
78
58
  else deepLinksCount++;
79
59
 
80
60
  // Anchor categorization
81
- if (normalizedTarget && (anchor.toLowerCase().includes(normalizedTarget) || normalizedTarget.includes(anchor.toLowerCase()))) {
61
+ if (anchor && normalizedTarget && (anchor.toLowerCase().includes(normalizedTarget) || (anchor.length >= 3 && normalizedTarget.includes(anchor.toLowerCase())))) {
82
62
  anchorTypes.branded++;
83
- } else if (/^https?:\/\//i.test(anchor) || anchor.includes('www.') || anchor.includes('.com') || anchor.includes('.org')) {
63
+ } else if (anchor && (/^https?:\/\//i.test(anchor) || anchor.includes('www.') || anchor.includes('.com') || anchor.includes('.org'))) {
84
64
  anchorTypes.naked_url++;
85
- } else if (GENERIC_ANCHORS.test(anchor)) {
65
+ } else if (anchor && GENERIC_ANCHORS.test(anchor)) {
86
66
  anchorTypes.generic++;
87
- } else if (COMMERCIAL_SPAM_KEYWORDS.test(anchor) || /\b(buy|best|cheap|discount|order)\b/i.test(anchor)) {
67
+ } else if (anchor && (COMMERCIAL_SPAM_KEYWORDS.test(anchor) || /\b(buy|best|cheap|discount|order)\b/i.test(anchor))) {
88
68
  anchorTypes.exact_match_commercial++;
89
69
  } else {
90
70
  anchorTypes.other++;
@@ -166,8 +146,9 @@ export function auditBacklinkProfile(backlinks, { targetDomain = null } = {}) {
166
146
  }
167
147
  }
168
148
 
169
- // Sort toxic domains by severity (critical first)
170
- toxicDomains.sort((a, b) => (a.risk_tier === 'critical' ? -1 : 1));
149
+ // Sort flagged domains by severity (critical first) with deterministic secondary key
150
+ const tierWeight = { critical: 2, high: 1, clean: 0 };
151
+ toxicDomains.sort((a, b) => (tierWeight[b.risk_tier] || 0) - (tierWeight[a.risk_tier] || 0) || a.domain.localeCompare(b.domain));
171
152
 
172
153
  const totalLinks = links.length;
173
154
  const totalDomains = referringDomains.size;
@@ -197,6 +178,7 @@ export function auditBacklinkProfile(backlinks, { targetDomain = null } = {}) {
197
178
 
198
179
  return {
199
180
  fact_status: 'observable_risk_indicators',
181
+ epistemic_status: 'DERIVED',
200
182
  target_domain: targetDomain,
201
183
  profile_health: profileHealth,
202
184
  summary: {
@@ -219,6 +201,7 @@ export function auditBacklinkProfile(backlinks, { targetDomain = null } = {}) {
219
201
  over_optimization_risk: commercialAnchorPct > 25 ? 'elevated' : 'normal',
220
202
  },
221
203
  toxic_domains: toxicDomains,
204
+ risk_indicators: toxicDomains,
222
205
  disavow_export: disavowLines.join('\n'),
223
206
  limitations: [
224
207
  'Search engines do not disclose algorithmic penalty thresholds; toxic classifications reflect observable risk patterns.',
@@ -217,10 +217,16 @@ export function evaluateAnswerEngineReadiness(page, ctx = {}) {
217
217
  });
218
218
  }
219
219
 
220
+ const boundedScore = Math.max(0, Math.min(100, Number.isFinite(compositeScore) ? Math.round(compositeScore) : 0));
221
+
220
222
  return {
221
223
  url: page.url,
222
- fact_status: 'deterministic_engine_readiness_audit',
223
- composite_readiness_score: compositeScore,
224
+ fact_status: 'modeled_extraction_readiness',
225
+ epistemic_status: 'MODELED',
226
+ evaluation_type: 'TECHNICAL_ELIGIBILITY',
227
+ score: boundedScore,
228
+ readiness_score: boundedScore,
229
+ composite_readiness_score: boundedScore,
224
230
  engines: {
225
231
  perplexity: {
226
232
  score: perplexityScore,