@nebulacomponents/citable 0.1.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.
- package/CHANGELOG.md +26 -0
- package/LICENSE +201 -0
- package/README.md +150 -0
- package/cli/bin/citable.js +5 -0
- package/dist/universal/.agents/skills/citable/SKILL.md +137 -0
- package/dist/universal/.agents/skills/citable/VERSION +1 -0
- package/dist/universal/.agents/skills/citable/commands/README.md +36 -0
- package/dist/universal/.agents/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.agents/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.agents/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.agents/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.agents/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.agents/skills/citable/manifest.json +54 -0
- package/dist/universal/.agents/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.agents/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.agents/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.agents/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.agents/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.agents/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.agents/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.agents/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.agents/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.agents/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.agents/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.agents/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.agents/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.agents/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.agents/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.agents/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.agents/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.agents/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.agents/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.agents/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.agents/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.agents/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.agents/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.agents/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.agents/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.agents/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.agents/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.agents/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.agents/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.agents/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.claude/skills/citable/SKILL.md +137 -0
- package/dist/universal/.claude/skills/citable/VERSION +1 -0
- package/dist/universal/.claude/skills/citable/commands/README.md +36 -0
- package/dist/universal/.claude/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.claude/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.claude/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.claude/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.claude/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.claude/skills/citable/manifest.json +54 -0
- package/dist/universal/.claude/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.claude/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.claude/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.claude/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.claude/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.claude/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.claude/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.claude/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.claude/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.claude/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.claude/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.claude/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.claude/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.claude/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.claude/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.claude/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.claude/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.claude/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.claude/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.claude/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.claude/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.claude/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.claude/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.claude/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.claude/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.claude/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.claude/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.claude/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.claude/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.claude/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.cursor/skills/citable/SKILL.md +137 -0
- package/dist/universal/.cursor/skills/citable/VERSION +1 -0
- package/dist/universal/.cursor/skills/citable/commands/README.md +36 -0
- package/dist/universal/.cursor/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.cursor/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.cursor/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.cursor/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.cursor/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +54 -0
- package/dist/universal/.cursor/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.cursor/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.cursor/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.cursor/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.cursor/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.cursor/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.cursor/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.cursor/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.cursor/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.cursor/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.cursor/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.cursor/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.cursor/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.cursor/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.cursor/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.cursor/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.cursor/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.cursor/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.cursor/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.cursor/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.cursor/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.cursor/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.cursor/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.cursor/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.cursor/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.cursor/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.cursor/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.gemini/skills/citable/SKILL.md +137 -0
- package/dist/universal/.gemini/skills/citable/VERSION +1 -0
- package/dist/universal/.gemini/skills/citable/commands/README.md +36 -0
- package/dist/universal/.gemini/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.gemini/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.gemini/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.gemini/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.gemini/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +54 -0
- package/dist/universal/.gemini/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.gemini/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.gemini/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.gemini/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.gemini/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.gemini/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.gemini/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.gemini/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.gemini/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.gemini/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.gemini/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.gemini/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.gemini/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.gemini/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.gemini/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.gemini/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.gemini/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.gemini/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.gemini/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.gemini/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.gemini/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.gemini/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.gemini/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.gemini/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.gemini/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.gemini/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.gemini/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.github/skills/citable/SKILL.md +137 -0
- package/dist/universal/.github/skills/citable/VERSION +1 -0
- package/dist/universal/.github/skills/citable/commands/README.md +36 -0
- package/dist/universal/.github/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.github/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.github/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.github/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.github/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.github/skills/citable/manifest.json +54 -0
- package/dist/universal/.github/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.github/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.github/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.github/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.github/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.github/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.github/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.github/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.github/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.github/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.github/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.github/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.github/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.github/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.github/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.github/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.github/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.github/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.github/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.github/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.github/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.github/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.github/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.github/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.github/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.github/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.github/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.github/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.github/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.github/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.kiro/skills/citable/SKILL.md +137 -0
- package/dist/universal/.kiro/skills/citable/VERSION +1 -0
- package/dist/universal/.kiro/skills/citable/commands/README.md +36 -0
- package/dist/universal/.kiro/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.kiro/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.kiro/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.kiro/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.kiro/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +54 -0
- package/dist/universal/.kiro/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.kiro/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.kiro/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.kiro/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.kiro/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.kiro/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.kiro/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.kiro/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.kiro/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.kiro/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.kiro/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.kiro/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.kiro/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.kiro/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.kiro/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.kiro/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.kiro/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.kiro/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.kiro/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.kiro/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.kiro/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.kiro/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.kiro/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.kiro/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.kiro/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.kiro/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.kiro/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.opencode/skills/citable/SKILL.md +137 -0
- package/dist/universal/.opencode/skills/citable/VERSION +1 -0
- package/dist/universal/.opencode/skills/citable/commands/README.md +36 -0
- package/dist/universal/.opencode/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.opencode/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.opencode/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.opencode/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.opencode/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +54 -0
- package/dist/universal/.opencode/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.opencode/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.opencode/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.opencode/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.opencode/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.opencode/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.opencode/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.opencode/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.opencode/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.opencode/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.opencode/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.opencode/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.opencode/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.opencode/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.opencode/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.opencode/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.opencode/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.opencode/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.opencode/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.opencode/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.opencode/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.opencode/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.opencode/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.opencode/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.opencode/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.opencode/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.opencode/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.pi/agent/skills/citable/SKILL.md +137 -0
- package/dist/universal/.pi/agent/skills/citable/VERSION +1 -0
- package/dist/universal/.pi/agent/skills/citable/commands/README.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.pi/agent/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.pi/agent/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.pi/agent/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.pi/agent/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +54 -0
- package/dist/universal/.pi/agent/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.pi/agent/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.pi/agent/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.pi/agent/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.qoder/skills/citable/SKILL.md +137 -0
- package/dist/universal/.qoder/skills/citable/VERSION +1 -0
- package/dist/universal/.qoder/skills/citable/commands/README.md +36 -0
- package/dist/universal/.qoder/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.qoder/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.qoder/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.qoder/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.qoder/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +54 -0
- package/dist/universal/.qoder/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.qoder/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.qoder/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.qoder/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.qoder/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.qoder/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.qoder/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.qoder/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.qoder/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.qoder/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.qoder/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.qoder/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.qoder/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.qoder/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.qoder/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.qoder/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.qoder/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.qoder/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.qoder/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.qoder/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.qoder/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.qoder/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.qoder/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.qoder/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.qoder/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.qoder/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.qoder/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.rovodev/skills/citable/SKILL.md +137 -0
- package/dist/universal/.rovodev/skills/citable/VERSION +1 -0
- package/dist/universal/.rovodev/skills/citable/commands/README.md +36 -0
- package/dist/universal/.rovodev/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.rovodev/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.rovodev/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.rovodev/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.rovodev/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +54 -0
- package/dist/universal/.rovodev/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.rovodev/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.rovodev/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.rovodev/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.rovodev/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.rovodev/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.rovodev/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.rovodev/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.rovodev/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.rovodev/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.rovodev/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.rovodev/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.rovodev/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.rovodev/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.trae/skills/citable/SKILL.md +137 -0
- package/dist/universal/.trae/skills/citable/VERSION +1 -0
- package/dist/universal/.trae/skills/citable/commands/README.md +36 -0
- package/dist/universal/.trae/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.trae/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.trae/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.trae/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.trae/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.trae/skills/citable/manifest.json +54 -0
- package/dist/universal/.trae/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.trae/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.trae/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.trae/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.trae/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.trae/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.trae/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.trae/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.trae/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.trae/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.trae/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.trae/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.trae/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.trae/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.trae/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.trae/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.trae/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.trae/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.trae/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.trae/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.trae/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.trae/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.trae/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.trae/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.trae/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.trae/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.trae/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.trae/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.trae/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.trae/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.trae-cn/skills/citable/SKILL.md +137 -0
- package/dist/universal/.trae-cn/skills/citable/VERSION +1 -0
- package/dist/universal/.trae-cn/skills/citable/commands/README.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.trae-cn/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.trae-cn/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.trae-cn/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.trae-cn/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +54 -0
- package/dist/universal/.trae-cn/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.trae-cn/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.trae-cn/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.trae-cn/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/manifest.json +598 -0
- package/package.json +89 -0
- package/schemas/claim.schema.json +53 -0
- package/schemas/common.defs.json +33 -0
- package/schemas/competitor.schema.json +28 -0
- package/schemas/config.schema.json +41 -0
- package/schemas/crawler.schema.json +33 -0
- package/schemas/detector-quality.schema.json +39 -0
- package/schemas/entity.schema.json +39 -0
- package/schemas/evidence.schema.json +41 -0
- package/schemas/experiment.schema.json +37 -0
- package/schemas/finding.schema.json +101 -0
- package/schemas/page.schema.json +40 -0
- package/schemas/project.schema.json +29 -0
- package/schemas/prompt-result.schema.json +37 -0
- package/schemas/prompt.schema.json +41 -0
- package/schemas/query.schema.json +43 -0
- package/schemas/run.schema.json +36 -0
- package/scripts/build-dist.js +143 -0
- package/skill/SKILL.md +137 -0
- package/skill/commands/README.md +36 -0
- package/skill/commands/ingest.md +44 -0
- package/skill/commands/measurement.md +49 -0
- package/skill/commands/optimize-page.md +53 -0
- package/skill/commands/page-work.md +48 -0
- package/skill/commands/validate-render.md +24 -0
- package/skill/policies/crawler-policy-template.md +47 -0
- package/skill/references/anti-patterns.md +61 -0
- package/skill/rubrics/README.md +30 -0
- package/skill/rubrics/answer-extractability.md +44 -0
- package/skill/rubrics/claim-boundedness.md +36 -0
- package/skill/rubrics/comparison-fairness.md +30 -0
- package/skill/rubrics/conversion-alignment.md +37 -0
- package/skill/rubrics/entity-clarity.md +41 -0
- package/skill/rubrics/evidence-strength.md +53 -0
- package/skill/rubrics/information-gain.md +33 -0
- package/skill/rubrics/intent-alignment.md +41 -0
- package/skill/rubrics/narrative-accuracy.md +46 -0
- package/skill/rubrics/recommendation-eligibility.md +36 -0
- package/skill/rubrics/semantic-clarity.md +42 -0
- package/skill/rubrics/source-authority.md +37 -0
- package/skill/templates/finding-review.md +54 -0
- package/src/cli/index.js +135 -0
- package/src/commands/audit.js +111 -0
- package/src/commands/compareSnapshots.js +48 -0
- package/src/commands/context.js +62 -0
- package/src/commands/init.js +111 -0
- package/src/commands/inspect.js +61 -0
- package/src/commands/mapClaims.js +89 -0
- package/src/commands/schemaCmd.js +71 -0
- package/src/commands/substantiate.js +121 -0
- package/src/commands/validate.js +27 -0
- package/src/crawler/fetch.js +31 -0
- package/src/crawler/robots.js +67 -0
- package/src/crawler/sitemap.js +25 -0
- package/src/detectors/ans.js +219 -0
- package/src/detectors/arch.js +154 -0
- package/src/detectors/claim.js +230 -0
- package/src/detectors/crawl.js +143 -0
- package/src/detectors/entity.js +202 -0
- package/src/detectors/evd.js +164 -0
- package/src/detectors/framework.js +137 -0
- package/src/detectors/geoReco.js +218 -0
- package/src/detectors/index.js +50 -0
- package/src/detectors/lifeMeas.js +212 -0
- package/src/detectors/link.js +121 -0
- package/src/detectors/page.js +202 -0
- package/src/detectors/schemaData.js +249 -0
- package/src/detectors/tech.js +397 -0
- package/src/evidence/run.js +88 -0
- package/src/extractor/page.js +125 -0
- package/src/extractor/site.js +175 -0
- package/src/installer/index.js +1117 -0
- package/src/installer/providers.js +164 -0
- package/src/registries/index.js +127 -0
- package/src/reporting/report.js +82 -0
- package/src/shared/io.js +56 -0
- package/src/shared/schemaValidator.js +29 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { defineDetector, indexTargets, registryPageFor, sitePageFor, pageSubject, entrySubject } from './framework.js';
|
|
2
|
+
|
|
3
|
+
const D = [];
|
|
4
|
+
|
|
5
|
+
/* ---------------- EXT: external corroboration ---------------- */
|
|
6
|
+
|
|
7
|
+
D.push(defineDetector({
|
|
8
|
+
id: 'EXT-001', name: 'Corroboration claimed from owned surface', namespace: 'EXT',
|
|
9
|
+
description: 'A claim lists "external corroboration" whose source is the organization’s own domain — self-corroboration.',
|
|
10
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
11
|
+
impact: { representation: 'medium', reputational: 'medium' },
|
|
12
|
+
applicable_requirement: 'AEO §7: corroboration must be editorially independent; premise 3.6',
|
|
13
|
+
remediation: 'Move the reference to evidence (owned) and pursue genuinely independent corroboration.',
|
|
14
|
+
verification: 'External corroboration entries resolve to non-owned domains.',
|
|
15
|
+
check(ctx) {
|
|
16
|
+
const ownDomains = new Set();
|
|
17
|
+
try { ownDomains.add(new URL(ctx.config?.site?.base_url ?? 'https://invalid.test').hostname); } catch { /* no base url */ }
|
|
18
|
+
const ev = new Map((ctx.registries.evidence?.entries || []).map((e) => [e.evidence_id, e]));
|
|
19
|
+
const hits = [];
|
|
20
|
+
for (const c of ctx.registries.claims?.entries || []) {
|
|
21
|
+
for (const ref of c.external_corroboration || []) {
|
|
22
|
+
const e = ev.get(ref);
|
|
23
|
+
const src = e?.source ?? (typeof ref === 'string' && ref.startsWith('http') ? ref : null);
|
|
24
|
+
if (!src) continue;
|
|
25
|
+
try {
|
|
26
|
+
if (ownDomains.has(new URL(src).hostname)) {
|
|
27
|
+
hits.push({
|
|
28
|
+
subject: entrySubject('claims', c.claim_id),
|
|
29
|
+
summary: `External corroboration for claim ${c.claim_id} points at owned domain ${new URL(src).hostname}`,
|
|
30
|
+
evidence: [`corroboration source: ${src}`],
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
} catch { /* non-URL sources cannot be classified */ }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return hits;
|
|
37
|
+
},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
D.push(defineDetector({
|
|
41
|
+
id: 'EXT-002', name: 'Comparative claim lacking independent corroboration', namespace: 'EXT',
|
|
42
|
+
description: 'A verified comparative claim has no external corroboration recorded at all.',
|
|
43
|
+
discipline: ['geo'], severity: 'low', deterministic: true, requires: ['registries'],
|
|
44
|
+
impact: { representation: 'medium', citation: 'low' },
|
|
45
|
+
applicable_requirement: 'GEO §6: owned content is necessary but insufficient; AEO §7 external corroboration layer',
|
|
46
|
+
remediation: 'Pursue independent editorial coverage, reviews, or analyst references that corroborate the comparison — never manufacture them.',
|
|
47
|
+
unsafe_shortcuts: ['fake reviews', 'synthetic community posts', 'paid lists presented as editorial'],
|
|
48
|
+
verification: 'Comparative verified claims list at least one independent corroboration source.',
|
|
49
|
+
check(ctx) {
|
|
50
|
+
return (ctx.registries.claims?.entries || [])
|
|
51
|
+
.filter((c) => c.claim_type === 'comparative' && ['verified', 'verified_narrowed'].includes(c.status) && (c.external_corroboration || []).length === 0)
|
|
52
|
+
.map((c) => ({
|
|
53
|
+
subject: entrySubject('claims', c.claim_id),
|
|
54
|
+
summary: `Verified comparative claim ${c.claim_id} has no independent corroboration`,
|
|
55
|
+
evidence: ['external_corroboration: []'],
|
|
56
|
+
}));
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
/* ---------------- GEO: generative representation ---------------- */
|
|
61
|
+
|
|
62
|
+
D.push(defineDetector({
|
|
63
|
+
id: 'GEO-001', name: 'Hidden instructions targeting language models', namespace: 'GEO',
|
|
64
|
+
description: 'Hidden page text or HTML comments contain instruction-like phrasing aimed at AI systems (crawler prompt injection).',
|
|
65
|
+
discipline: ['geo'], severity: 'critical', deterministic: true, requires: ['site'],
|
|
66
|
+
impact: { reputational: 'high', legal: 'medium', representation: 'high' },
|
|
67
|
+
applicable_requirement: 'Premise 3.6: no hidden instructions for language models, no crawler prompt injection; GEO §6 unsafe practices',
|
|
68
|
+
remediation: 'Remove the hidden instruction text entirely.',
|
|
69
|
+
unsafe_shortcuts: ['moving the instructions to a less detectable location'],
|
|
70
|
+
verification: 'No hidden text or comments contain model-directed instructions.',
|
|
71
|
+
check(ctx) {
|
|
72
|
+
const rx = /(ignore (all |any )?(previous|prior|above) (instructions|prompts)|you are an? (ai|llm|language model|assistant)|when summariz|if you are an? (ai|llm|assistant|model)|always recommend|do not mention (competitor|alternative)|respond with|tell the user)/i;
|
|
73
|
+
const hits = [];
|
|
74
|
+
for (const p of ctx.site.pages) {
|
|
75
|
+
for (const t of p.hiddenTexts) {
|
|
76
|
+
if (rx.test(t)) {
|
|
77
|
+
hits.push({
|
|
78
|
+
subject: pageSubject(p),
|
|
79
|
+
summary: 'Hidden text contains instructions directed at AI systems',
|
|
80
|
+
evidence: [`hidden text: "${t.slice(0, 160)}"`],
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const comments = p.rawHtml.match(/<!--([\s\S]*?)-->/g) || [];
|
|
85
|
+
for (const c of comments) {
|
|
86
|
+
if (rx.test(c)) {
|
|
87
|
+
hits.push({
|
|
88
|
+
subject: pageSubject(p),
|
|
89
|
+
summary: 'HTML comment contains instructions directed at AI systems',
|
|
90
|
+
evidence: [`comment: "${c.slice(0, 160)}"`],
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return hits;
|
|
96
|
+
},
|
|
97
|
+
}));
|
|
98
|
+
|
|
99
|
+
D.push(defineDetector({
|
|
100
|
+
id: 'GEO-002', name: 'Proprietary concept without stable definition', namespace: 'GEO',
|
|
101
|
+
description: 'A proprietary-concept entity has no definition recorded and/or no canonical page.',
|
|
102
|
+
discipline: ['geo', 'aeo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
103
|
+
impact: { representation: 'high', citation: 'medium' },
|
|
104
|
+
applicable_requirement: 'Detector spec: proprietary term lacks a stable definition; GEO §5 controlled terminology',
|
|
105
|
+
remediation: 'Publish one canonical definition page per proprietary concept and record it in the registry.',
|
|
106
|
+
verification: 'Concept entity has definition and canonical_url.',
|
|
107
|
+
check(ctx) {
|
|
108
|
+
return (ctx.registries.entities?.entries || [])
|
|
109
|
+
.filter((e) => e.entity_type === 'proprietary_concept' && e.status !== 'retired')
|
|
110
|
+
.filter((e) => !e.definition || !e.canonical_url)
|
|
111
|
+
.map((e) => ({
|
|
112
|
+
subject: entrySubject('entities', e.entity_id),
|
|
113
|
+
summary: `Proprietary concept "${e.canonical_name}" lacks ${!e.definition ? 'a definition' : ''}${!e.definition && !e.canonical_url ? ' and ' : ''}${!e.canonical_url ? 'a canonical page' : ''}`,
|
|
114
|
+
evidence: [`definition: ${e.definition ? 'present' : 'missing'}; canonical_url: ${e.canonical_url ?? 'missing'}`],
|
|
115
|
+
}));
|
|
116
|
+
},
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
D.push(defineDetector({
|
|
120
|
+
id: 'GEO-003', name: 'Entity absent from its category page', namespace: 'GEO',
|
|
121
|
+
description: 'A product entity declares a category for which a category page exists, but the page never mentions the entity.',
|
|
122
|
+
discipline: ['geo'], severity: 'medium', deterministic: true, requires: ['site', 'registries'],
|
|
123
|
+
impact: { representation: 'medium', citation: 'low' },
|
|
124
|
+
applicable_requirement: 'Detector spec: entity omitted from its relevant category page; GEO §3 category placement',
|
|
125
|
+
remediation: 'Reference the entity (with its canonical name) on the category page it belongs to.',
|
|
126
|
+
verification: 'Category page text contains the entity canonical name or an alias.',
|
|
127
|
+
check(ctx) {
|
|
128
|
+
const categoryPages = (ctx.registries.pages?.entries || []).filter((p) => p.page_type === 'category' && p.status !== 'retired');
|
|
129
|
+
if (categoryPages.length === 0) return [];
|
|
130
|
+
const hits = [];
|
|
131
|
+
for (const e of (ctx.registries.entities?.entries || []).filter((e) => ['product', 'product_family'].includes(e.entity_type) && e.category)) {
|
|
132
|
+
for (const cp of categoryPages) {
|
|
133
|
+
if (!(cp.primary_entities || []).some((pe) => {
|
|
134
|
+
const cat = (ctx.registries.entities?.entries || []).find((x) => x.entity_id === pe);
|
|
135
|
+
return cat && (cat.canonical_name.toLowerCase() === String(e.category).toLowerCase() || cat.entity_id === e.category);
|
|
136
|
+
})) continue;
|
|
137
|
+
const page = sitePageFor(ctx, cp);
|
|
138
|
+
if (!page) continue;
|
|
139
|
+
const names = [e.canonical_name, ...(e.aliases || [])].map((n) => n.toLowerCase());
|
|
140
|
+
if (!names.some((n) => page.text.toLowerCase().includes(n))) {
|
|
141
|
+
hits.push({
|
|
142
|
+
subject: entrySubject('entities', e.entity_id),
|
|
143
|
+
summary: `Entity "${e.canonical_name}" is not mentioned on its category page ${cp.page_id}`,
|
|
144
|
+
evidence: [`category: ${e.category}`, `category page: ${cp.url}`],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return hits;
|
|
150
|
+
},
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
D.push(defineDetector({
|
|
154
|
+
id: 'GEO-004', name: 'llms.txt treated as authority mechanism', namespace: 'GEO',
|
|
155
|
+
description: 'llms.txt exists and contains directive/authority language, which no engine honors as an authorization mechanism.',
|
|
156
|
+
discipline: ['geo'], severity: 'low', deterministic: false, requires: ['site'],
|
|
157
|
+
impact: { representation: 'low', legal: 'low' },
|
|
158
|
+
applicable_requirement: 'Anti-pattern: treating llms.txt as an authority mechanism; GEO §9 llms.txt is optional and experimental',
|
|
159
|
+
false_positive_conditions: ['descriptive llms.txt files that merely index documentation'],
|
|
160
|
+
remediation: 'Treat llms.txt as optional discovery metadata only; move access decisions to robots.txt and the crawler policy registry.',
|
|
161
|
+
verification: 'llms.txt contains no directive/authorization language.',
|
|
162
|
+
check(ctx) {
|
|
163
|
+
const page = ctx.site.pages.find((p) => p.url.endsWith('/llms.txt'));
|
|
164
|
+
const raw = page?.rawHtml ?? ctx.site.llmsTxt ?? null;
|
|
165
|
+
if (!raw) return [];
|
|
166
|
+
if (/\b(must not|do not (train|use|crawl)|prohibited|required to|you must|licen[cs]e enforcement)\b/i.test(raw)) {
|
|
167
|
+
return [{
|
|
168
|
+
subject: { type: 'url', identifier: 'llms.txt' },
|
|
169
|
+
summary: 'llms.txt contains directive language it cannot enforce',
|
|
170
|
+
evidence: ['llms.txt is not a recognized authorization mechanism; Google explicitly does not use it'],
|
|
171
|
+
confidence: 'high',
|
|
172
|
+
}];
|
|
173
|
+
}
|
|
174
|
+
return [];
|
|
175
|
+
},
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
/* ---------------- RECO: recommendation eligibility ---------------- */
|
|
179
|
+
|
|
180
|
+
const RECO_CHECKS = [
|
|
181
|
+
['RECO-001', 'target user', /\b((designed|built|intended|best|ideal) for|who (is|are) (this|it) for|target (user|customer|audience)|for (teams|organizations|enterprises|companies) (that|who|with))\b/i, 'Recommendation-eligible page never states who the product is for.', 'GEO §7 target user'],
|
|
182
|
+
['RECO-002', 'non-target user / exclusions', /\b(not (for|intended for|suitable for|a fit for|designed for)|who should not|isn'?t for|poor fit|when not to use)\b/i, 'Page never states who the product is NOT for.', 'GEO §7 non-target user; recommendation page lacks non-target user'],
|
|
183
|
+
['RECO-003', 'deployment model', /\b(saas|self-?hosted|on-?prem(ise|ises)?|cloud[- ]hosted|hybrid deployment|deployment (model|option))\b/i, 'Page never states the deployment model.', 'GEO §7 deployment'],
|
|
184
|
+
['RECO-004', 'pricing qualification', /\b(pricing|price|cost|quote|per (seat|user|month|year)|contact (us|sales) for pricing|free (tier|trial))\b/i, 'Page gives no pricing information or qualification.', 'GEO §7 pricing public or clearly qualified'],
|
|
185
|
+
['RECO-005', 'limitations', /\b(limitation|constraint|does not (support|cover|solve)|not (yet )?(supported|available)|known (issue|limitation)|trade-?off)\b/i, 'Page states no limitations.', 'GEO §7 limitations; detector spec: missing limitations'],
|
|
186
|
+
['RECO-006', 'geography', /\b(available in|supported (market|countr|region)|north america|europe|global(ly)? available|jurisdiction)\b/i, 'Page never states supported geography.', 'GEO §7 geography'],
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
for (const [id, label, rx, desc, req] of RECO_CHECKS) {
|
|
190
|
+
D.push(defineDetector({
|
|
191
|
+
id, name: `Recommendation data missing: ${label}`, namespace: 'RECO',
|
|
192
|
+
description: desc,
|
|
193
|
+
discipline: ['geo'], severity: 'medium', deterministic: false, requires: ['site', 'registries'],
|
|
194
|
+
impact: { representation: 'high', conversion: 'medium' },
|
|
195
|
+
applicable_requirement: req,
|
|
196
|
+
false_positive_conditions: [`${label} expressed with vocabulary outside the matched set`],
|
|
197
|
+
remediation: `State the ${label} explicitly on product and recommendation pages.`,
|
|
198
|
+
verification: `${label} phrasing present on the page.`,
|
|
199
|
+
check(ctx) {
|
|
200
|
+
const hits = [];
|
|
201
|
+
for (const p of indexTargets(ctx)) {
|
|
202
|
+
const reg = registryPageFor(ctx, p);
|
|
203
|
+
if (!reg || !['product', 'recommendation'].includes(reg.page_type) || p.status !== 200) continue;
|
|
204
|
+
if (!rx.test(p.text)) {
|
|
205
|
+
hits.push({
|
|
206
|
+
subject: pageSubject(p),
|
|
207
|
+
summary: `${reg.page_type} page ${reg.page_id}: no ${label} stated`,
|
|
208
|
+
evidence: [`no ${label} phrasing found in page text`],
|
|
209
|
+
confidence: 'medium',
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return hits;
|
|
214
|
+
},
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default D;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import tech from './tech.js';
|
|
2
|
+
import crawl from './crawl.js';
|
|
3
|
+
import arch from './arch.js';
|
|
4
|
+
import page from './page.js';
|
|
5
|
+
import ans from './ans.js';
|
|
6
|
+
import entity from './entity.js';
|
|
7
|
+
import claim from './claim.js';
|
|
8
|
+
import evd from './evd.js';
|
|
9
|
+
import schemaData from './schemaData.js';
|
|
10
|
+
import link from './link.js';
|
|
11
|
+
import geoReco from './geoReco.js';
|
|
12
|
+
import lifeMeas from './lifeMeas.js';
|
|
13
|
+
|
|
14
|
+
export const ALL_DETECTORS = [...tech, ...crawl, ...arch, ...page, ...ans, ...entity, ...claim, ...evd, ...schemaData, ...link, ...geoReco, ...lifeMeas];
|
|
15
|
+
|
|
16
|
+
const ids = new Set();
|
|
17
|
+
for (const d of ALL_DETECTORS) {
|
|
18
|
+
if (ids.has(d.id)) throw new Error(`duplicate detector id: ${d.id}`);
|
|
19
|
+
ids.add(d.id);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function detectorsByNamespace() {
|
|
23
|
+
const out = {};
|
|
24
|
+
for (const d of ALL_DETECTORS) (out[d.namespace] ||= []).push(d);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function selectDetectors({ scope, namespaces, discipline } = {}) {
|
|
29
|
+
let ds = ALL_DETECTORS;
|
|
30
|
+
if (namespaces?.length) ds = ds.filter((d) => namespaces.includes(d.namespace));
|
|
31
|
+
if (discipline) ds = ds.filter((d) => d.discipline.includes(discipline));
|
|
32
|
+
if (scope) {
|
|
33
|
+
const scopeMap = {
|
|
34
|
+
technical: ['TECH', 'CRAWL', 'LINK'],
|
|
35
|
+
seo: null, // discipline filter handles it
|
|
36
|
+
aeo: null,
|
|
37
|
+
geo: null,
|
|
38
|
+
architecture: ['ARCH', 'LINK'],
|
|
39
|
+
entity: ['ENTITY'],
|
|
40
|
+
claims: ['CLAIM'],
|
|
41
|
+
evidence: ['EVD'],
|
|
42
|
+
schema: ['SCHEMA'],
|
|
43
|
+
lifecycle: ['LIFE'],
|
|
44
|
+
corroboration: ['EXT'],
|
|
45
|
+
};
|
|
46
|
+
if (scopeMap[scope]) ds = ds.filter((d) => scopeMap[scope].includes(d.namespace));
|
|
47
|
+
else if (['seo', 'aeo', 'geo'].includes(scope)) ds = ds.filter((d) => d.discipline.includes(scope));
|
|
48
|
+
}
|
|
49
|
+
return ds;
|
|
50
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { defineDetector, entrySubject } from './framework.js';
|
|
2
|
+
import { isPastDate } from '../shared/io.js';
|
|
3
|
+
|
|
4
|
+
const D = [];
|
|
5
|
+
|
|
6
|
+
/* ---------------- LIFE: lifecycle and ownership ---------------- */
|
|
7
|
+
|
|
8
|
+
D.push(defineDetector({
|
|
9
|
+
id: 'LIFE-001', name: 'Page without content owner', namespace: 'LIFE',
|
|
10
|
+
description: 'An active page registry entry has no accountable content owner.',
|
|
11
|
+
discipline: ['seo', 'aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
12
|
+
impact: { maintainability: 'high' },
|
|
13
|
+
applicable_requirement: 'SEO §14 lifecycle: owner assigned; AEO §13 content owner assigned',
|
|
14
|
+
remediation: 'Assign a named accountable content owner.',
|
|
15
|
+
verification: 'content_owner set on all active pages.',
|
|
16
|
+
check(ctx) {
|
|
17
|
+
return activePages(ctx).filter((p) => !p.content_owner).map((p) => ({
|
|
18
|
+
subject: entrySubject('pages', p.page_id),
|
|
19
|
+
summary: `Page ${p.page_id} has no content owner`,
|
|
20
|
+
evidence: ['content_owner: missing'],
|
|
21
|
+
}));
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
D.push(defineDetector({
|
|
26
|
+
id: 'LIFE-002', name: 'Claim-bearing page without factual reviewer', namespace: 'LIFE',
|
|
27
|
+
description: 'A page that publishes registered claims has no factual reviewer.',
|
|
28
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
29
|
+
impact: { legal: 'medium', maintainability: 'medium' },
|
|
30
|
+
applicable_requirement: 'AEO §8 required update controls: factual reviewer; SEO §12 subject-matter expert role',
|
|
31
|
+
remediation: 'Assign a factual reviewer for pages that publish claims.',
|
|
32
|
+
verification: 'factual_reviewer set on claim-bearing pages.',
|
|
33
|
+
check(ctx) {
|
|
34
|
+
return activePages(ctx)
|
|
35
|
+
.filter((p) => (p.published_claims || []).length > 0 && !p.factual_reviewer)
|
|
36
|
+
.map((p) => ({
|
|
37
|
+
subject: entrySubject('pages', p.page_id),
|
|
38
|
+
summary: `Page ${p.page_id} publishes ${(p.published_claims || []).length} claim(s) but has no factual reviewer`,
|
|
39
|
+
evidence: [`published_claims: ${(p.published_claims || []).join(', ')}`],
|
|
40
|
+
}));
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
D.push(defineDetector({
|
|
45
|
+
id: 'LIFE-003', name: 'Review overdue', namespace: 'LIFE',
|
|
46
|
+
description: 'A page has passed its next review date.',
|
|
47
|
+
discipline: ['seo', 'aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
48
|
+
impact: { representation: 'medium', maintainability: 'medium' },
|
|
49
|
+
applicable_requirement: 'AEO §8 lifecycle classification and review intervals; SEO §12 content review dates',
|
|
50
|
+
remediation: 'Perform the scheduled factual review and set the next review date.',
|
|
51
|
+
verification: 'next_review_date in the future for all active pages.',
|
|
52
|
+
check(ctx) {
|
|
53
|
+
return activePages(ctx)
|
|
54
|
+
.filter((p) => isPastDate(p.next_review_date, ctx.refDate))
|
|
55
|
+
.map((p) => ({
|
|
56
|
+
subject: entrySubject('pages', p.page_id),
|
|
57
|
+
summary: `Page ${p.page_id} review overdue (due ${p.next_review_date})`,
|
|
58
|
+
evidence: [`next_review_date: ${p.next_review_date}`],
|
|
59
|
+
}));
|
|
60
|
+
},
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
D.push(defineDetector({
|
|
64
|
+
id: 'LIFE-004', name: 'Page without lifecycle classification', namespace: 'LIFE',
|
|
65
|
+
description: 'An active page has no lifecycle class, so no review model can apply.',
|
|
66
|
+
discipline: ['seo', 'aeo', 'geo'], severity: 'low', deterministic: true, requires: ['registries'],
|
|
67
|
+
impact: { maintainability: 'medium' },
|
|
68
|
+
applicable_requirement: 'AEO §8 every page needs a lifecycle classification; detector spec: content lacks lifecycle classification',
|
|
69
|
+
remediation: 'Classify the page (foundational, product_capability, regulatory, pricing, …) and derive its review cadence.',
|
|
70
|
+
verification: 'lifecycle_class set on all active pages.',
|
|
71
|
+
check(ctx) {
|
|
72
|
+
return activePages(ctx)
|
|
73
|
+
.filter((p) => !p.lifecycle_class || p.lifecycle_class === 'unclassified')
|
|
74
|
+
.map((p) => ({
|
|
75
|
+
subject: entrySubject('pages', p.page_id),
|
|
76
|
+
summary: `Page ${p.page_id} has no lifecycle classification`,
|
|
77
|
+
evidence: [`lifecycle_class: ${p.lifecycle_class ?? 'missing'}`],
|
|
78
|
+
}));
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
D.push(defineDetector({
|
|
83
|
+
id: 'LIFE-005', name: 'Regulatory content without jurisdiction', namespace: 'LIFE',
|
|
84
|
+
description: 'A page classified regulatory (or carrying legal claims) records no jurisdiction.',
|
|
85
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
86
|
+
impact: { legal: 'high' },
|
|
87
|
+
applicable_requirement: 'Detector spec: regulatory content lacks jurisdiction; AEO §1 jurisdiction field',
|
|
88
|
+
remediation: 'Record the jurisdiction the content applies to and state it on the page.',
|
|
89
|
+
verification: 'jurisdiction set on regulatory pages.',
|
|
90
|
+
check(ctx) {
|
|
91
|
+
const legalClaims = new Set((ctx.registries.claims?.entries || []).filter((c) => c.claim_type === 'legal_regulatory').map((c) => c.claim_id));
|
|
92
|
+
return activePages(ctx)
|
|
93
|
+
.filter((p) => (p.lifecycle_class === 'regulatory' || (p.published_claims || []).some((c) => legalClaims.has(c))) && !p.jurisdiction)
|
|
94
|
+
.map((p) => ({
|
|
95
|
+
subject: entrySubject('pages', p.page_id),
|
|
96
|
+
summary: `Regulatory page ${p.page_id} records no jurisdiction`,
|
|
97
|
+
evidence: [`lifecycle_class: ${p.lifecycle_class}; jurisdiction: missing`],
|
|
98
|
+
}));
|
|
99
|
+
},
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
D.push(defineDetector({
|
|
103
|
+
id: 'LIFE-006', name: 'Freshness theater (date bumped, content unchanged)', namespace: 'LIFE',
|
|
104
|
+
description: 'Between snapshots, a page’s dateModified advanced while its content hash stayed identical.',
|
|
105
|
+
discipline: ['seo', 'aeo'], severity: 'medium', deterministic: true, requires: ['site', 'snapshots'],
|
|
106
|
+
impact: { reputational: 'medium', representation: 'medium' },
|
|
107
|
+
applicable_requirement: 'AEO §8 do not update dates without materially updating content ("freshness theater")',
|
|
108
|
+
remediation: 'Only advance revision dates alongside substantive updates.',
|
|
109
|
+
verification: 'Compare content hash and dateModified across snapshots.',
|
|
110
|
+
check(ctx) {
|
|
111
|
+
const prev = ctx.snapshots?.pages;
|
|
112
|
+
if (!prev) return [];
|
|
113
|
+
const hits = [];
|
|
114
|
+
for (const p of ctx.site.pages) {
|
|
115
|
+
const old = prev[p.url];
|
|
116
|
+
if (!old) continue;
|
|
117
|
+
const currentDate = extractModified(p);
|
|
118
|
+
if (old.contentHash && ctx.hashPage && old.contentHash === ctx.hashPage(p) && old.dateModified && currentDate && currentDate > old.dateModified) {
|
|
119
|
+
hits.push({
|
|
120
|
+
subject: { type: 'page', identifier: p.url, url: p.url },
|
|
121
|
+
summary: `dateModified advanced (${old.dateModified} → ${currentDate}) with identical content`,
|
|
122
|
+
evidence: [`content hash unchanged: ${old.contentHash.slice(0, 12)}…`],
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return hits;
|
|
127
|
+
},
|
|
128
|
+
}));
|
|
129
|
+
|
|
130
|
+
export function extractModified(page) {
|
|
131
|
+
for (const j of page.jsonLd) {
|
|
132
|
+
for (const b of j.blocks) {
|
|
133
|
+
if (b.dateModified) return String(b.dateModified);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return page.metas?.['article:modified_time']?.[0] ?? null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* ---------------- MEAS: measurement integrity ---------------- */
|
|
140
|
+
|
|
141
|
+
D.push(defineDetector({
|
|
142
|
+
id: 'MEAS-001', name: 'Prompt observation missing required metadata', namespace: 'MEAS',
|
|
143
|
+
description: 'A recorded prompt-test observation lacks engine, model/interface, locale, or timestamp context.',
|
|
144
|
+
discipline: ['geo', 'aeo'], severity: 'medium', deterministic: true, requires: ['promptResults'],
|
|
145
|
+
impact: { maintainability: 'high' },
|
|
146
|
+
applicable_requirement: '§8.8 test-prompts must record model, interface, locale, date; GEO §12 evidence capture',
|
|
147
|
+
remediation: 'Re-record the observation with full context; discard observations that cannot be contextualized.',
|
|
148
|
+
verification: 'All observations validate against prompt-result.schema.json.',
|
|
149
|
+
check(ctx) {
|
|
150
|
+
const hits = [];
|
|
151
|
+
for (const o of ctx.promptResults || []) {
|
|
152
|
+
const missing = ['engine', 'locale', 'date_time', 'prompt_text'].filter((k) => !o[k]);
|
|
153
|
+
if (missing.length) {
|
|
154
|
+
hits.push({
|
|
155
|
+
subject: { type: 'prompt', identifier: o.observation_id ?? o.prompt_id ?? 'unknown' },
|
|
156
|
+
summary: `Prompt observation missing: ${missing.join(', ')}`,
|
|
157
|
+
evidence: [`observation ${o.observation_id ?? '?'} lacks ${missing.join(', ')}`],
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return hits;
|
|
162
|
+
},
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
D.push(defineDetector({
|
|
166
|
+
id: 'MEAS-002', name: 'Single observation treated as stable outcome', namespace: 'MEAS',
|
|
167
|
+
description: 'A prompt has exactly one recorded observation but its registry accuracy_status asserts a definitive outcome.',
|
|
168
|
+
discipline: ['geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
169
|
+
impact: { maintainability: 'medium', representation: 'low' },
|
|
170
|
+
applicable_requirement: 'AEO §10 statistical caution: do not claim improvement from one prompt/one day; GEO §12 repeatability',
|
|
171
|
+
remediation: 'Collect repeated observations across engines, dates, and variants before recording a definitive accuracy status.',
|
|
172
|
+
verification: 'Prompts with definitive status have ≥3 observations.',
|
|
173
|
+
check(ctx) {
|
|
174
|
+
const counts = new Map();
|
|
175
|
+
for (const o of ctx.promptResults || []) {
|
|
176
|
+
counts.set(o.prompt_id, (counts.get(o.prompt_id) || 0) + 1);
|
|
177
|
+
}
|
|
178
|
+
return (ctx.registries.prompts?.entries || [])
|
|
179
|
+
.filter((p) => ['accurate', 'inaccurate'].includes(p.accuracy_status) && (counts.get(p.prompt_id) || 0) < 3)
|
|
180
|
+
.map((p) => ({
|
|
181
|
+
subject: entrySubject('prompts', p.prompt_id),
|
|
182
|
+
summary: `Prompt ${p.prompt_id} has definitive accuracy_status "${p.accuracy_status}" from only ${counts.get(p.prompt_id) || 0} observation(s)`,
|
|
183
|
+
evidence: [`observations recorded: ${counts.get(p.prompt_id) || 0}; minimum for definitive status: 3`],
|
|
184
|
+
}));
|
|
185
|
+
},
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
D.push(defineDetector({
|
|
189
|
+
id: 'MEAS-003', name: 'Causal experiment conclusion without controls', namespace: 'MEAS',
|
|
190
|
+
description: 'A concluded experiment asserts a result but records no control group, baseline window, or confounders.',
|
|
191
|
+
discipline: ['seo', 'geo'], severity: 'medium', deterministic: true, requires: ['registries'],
|
|
192
|
+
impact: { maintainability: 'medium' },
|
|
193
|
+
applicable_requirement: 'SEO §11 required experiment record; GEO §14 invalid conclusion pattern',
|
|
194
|
+
remediation: 'Re-open the experiment with a control/baseline design, or downgrade the result confidence to low.',
|
|
195
|
+
verification: 'Concluded experiments carry control/baseline and confounders.',
|
|
196
|
+
check(ctx) {
|
|
197
|
+
return (ctx.registries.experiments?.entries || [])
|
|
198
|
+
.filter((e) => e.status === 'concluded' && e.result && e.result_confidence !== 'low')
|
|
199
|
+
.filter((e) => (!e.control_group && !e.baseline_window) || (e.known_confounders || []).length === 0)
|
|
200
|
+
.map((e) => ({
|
|
201
|
+
subject: entrySubject('experiments', e.experiment_id),
|
|
202
|
+
summary: `Experiment ${e.experiment_id} concludes "${String(e.result).slice(0, 60)}" without ${(!e.control_group && !e.baseline_window) ? 'control/baseline' : ''}${((!e.control_group && !e.baseline_window) && (e.known_confounders || []).length === 0) ? ' or ' : ''}${(e.known_confounders || []).length === 0 ? 'recorded confounders' : ''}`,
|
|
203
|
+
evidence: [`control_group: ${e.control_group ?? 'none'}; baseline_window: ${e.baseline_window ?? 'none'}; known_confounders: ${(e.known_confounders || []).length}`],
|
|
204
|
+
}));
|
|
205
|
+
},
|
|
206
|
+
}));
|
|
207
|
+
|
|
208
|
+
function activePages(ctx) {
|
|
209
|
+
return (ctx.registries.pages?.entries || []).filter((p) => !['retired', 'draft'].includes(p.status));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export default D;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { defineDetector, pageSubject } from './framework.js';
|
|
2
|
+
|
|
3
|
+
const D = [];
|
|
4
|
+
|
|
5
|
+
D.push(defineDetector({
|
|
6
|
+
id: 'LINK-001', name: 'Broken internal link', namespace: 'LINK',
|
|
7
|
+
description: 'An internal link targets a URL that is missing from the audited output or returns 4xx/5xx.',
|
|
8
|
+
discipline: ['seo', 'aeo'], severity: 'medium', deterministic: true, requires: ['site'],
|
|
9
|
+
impact: { retrieval: 'medium', conversion: 'low' },
|
|
10
|
+
applicable_requirement: 'SEO §12 broken internal-link detection; §2 crawlable internal links',
|
|
11
|
+
remediation: 'Fix or remove the link; add a redirect if the target moved.',
|
|
12
|
+
verification: 'All internal links resolve to 200 pages.',
|
|
13
|
+
check(ctx) {
|
|
14
|
+
const hits = [];
|
|
15
|
+
for (const p of ctx.site.pages) {
|
|
16
|
+
const seen = new Set();
|
|
17
|
+
for (const e of ctx.site.outbound.get(ctx.site.normalize(p.url)) || []) {
|
|
18
|
+
if (seen.has(e.to)) continue;
|
|
19
|
+
seen.add(e.to);
|
|
20
|
+
const target = ctx.site.byUrl.get(e.to);
|
|
21
|
+
if (!target) {
|
|
22
|
+
hits.push({
|
|
23
|
+
subject: pageSubject(p),
|
|
24
|
+
summary: `Internal link to missing URL ${e.to}`,
|
|
25
|
+
evidence: [`link "${e.text || e.href}" → ${e.to} (not found in audited output)`],
|
|
26
|
+
});
|
|
27
|
+
} else if (target.status >= 400) {
|
|
28
|
+
hits.push({
|
|
29
|
+
subject: pageSubject(p),
|
|
30
|
+
summary: `Internal link to ${e.to} returning HTTP ${target.status}`,
|
|
31
|
+
evidence: [`link "${e.text || e.href}" → ${e.to} (status ${target.status})`],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return hits;
|
|
37
|
+
},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
D.push(defineDetector({
|
|
41
|
+
id: 'LINK-002', name: 'Internal link to redirect', namespace: 'LINK',
|
|
42
|
+
description: 'An internal link targets a URL that redirects instead of the final destination.',
|
|
43
|
+
discipline: ['seo'], severity: 'low', deterministic: true, requires: ['site'],
|
|
44
|
+
impact: { retrieval: 'low' },
|
|
45
|
+
applicable_requirement: 'SEO §3 avoid links to redirects or canonical duplicates',
|
|
46
|
+
remediation: 'Update the link to the final destination URL.',
|
|
47
|
+
verification: 'Internal links point directly at 200 URLs.',
|
|
48
|
+
check(ctx) {
|
|
49
|
+
const hits = [];
|
|
50
|
+
for (const p of ctx.site.pages) {
|
|
51
|
+
for (const e of ctx.site.outbound.get(ctx.site.normalize(p.url)) || []) {
|
|
52
|
+
const target = ctx.site.byUrl.get(e.to);
|
|
53
|
+
if (target && target.status >= 300 && target.status < 400) {
|
|
54
|
+
hits.push({
|
|
55
|
+
subject: pageSubject(p),
|
|
56
|
+
summary: `Internal link to redirecting URL ${e.to} (HTTP ${target.status})`,
|
|
57
|
+
evidence: [`link "${e.text || e.href}" → ${e.to} (status ${target.status})`],
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return hits;
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
D.push(defineDetector({
|
|
67
|
+
id: 'LINK-003', name: 'Generic anchor text', namespace: 'LINK',
|
|
68
|
+
description: 'Internal links use non-descriptive anchors ("click here", "read more", "learn more").',
|
|
69
|
+
discipline: ['seo', 'aeo'], severity: 'low', deterministic: true, requires: ['site'],
|
|
70
|
+
impact: { ranking: 'low' },
|
|
71
|
+
applicable_requirement: 'SEO §3 meaningful anchor text; avoid "click here"',
|
|
72
|
+
remediation: 'Rewrite anchors to describe the target ("AI execution governance definition", not "learn more").',
|
|
73
|
+
verification: 'No internal anchors match the generic set.',
|
|
74
|
+
check(ctx) {
|
|
75
|
+
const generic = /^(click here|read more|learn more|here|more|this page|link)$/i;
|
|
76
|
+
const hits = [];
|
|
77
|
+
for (const p of ctx.site.pages) {
|
|
78
|
+
const bad = (ctx.site.outbound.get(ctx.site.normalize(p.url)) || []).filter((e) => generic.test(e.text));
|
|
79
|
+
if (bad.length) {
|
|
80
|
+
hits.push({
|
|
81
|
+
subject: pageSubject(p),
|
|
82
|
+
summary: `${bad.length} internal link(s) with generic anchor text`,
|
|
83
|
+
evidence: bad.slice(0, 5).map((e) => `"${e.text}" → ${e.to}`),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return hits;
|
|
88
|
+
},
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
D.push(defineDetector({
|
|
92
|
+
id: 'LINK-004', name: 'Sitewide repeated exact-match anchor', namespace: 'LINK',
|
|
93
|
+
description: 'The same exact anchor text points at the same URL from a large share of pages — a pattern of mechanical link insertion.',
|
|
94
|
+
discipline: ['seo'], severity: 'low', deterministic: false, requires: ['site'],
|
|
95
|
+
impact: { ranking: 'low', reputational: 'low' },
|
|
96
|
+
applicable_requirement: 'SEO §3 avoid sitewide exact-match anchors and automated keyword-matched links',
|
|
97
|
+
false_positive_conditions: ['legitimate navigation labels (nav/footer) repeated by design'],
|
|
98
|
+
remediation: 'Vary contextual anchors naturally; keep repeated labels to navigation chrome only.',
|
|
99
|
+
verification: 'Re-measure anchor repetition after cleanup.',
|
|
100
|
+
check(ctx) {
|
|
101
|
+
if (ctx.site.pages.length < 5) return [];
|
|
102
|
+
const counts = new Map();
|
|
103
|
+
for (const p of ctx.site.pages) {
|
|
104
|
+
for (const e of ctx.site.outbound.get(ctx.site.normalize(p.url)) || []) {
|
|
105
|
+
if (!e.text || e.text.split(' ').length < 3) continue; // navigation labels are short; target phrase-anchors
|
|
106
|
+
const key = `${e.text.toLowerCase()}→${e.to}`;
|
|
107
|
+
counts.set(key, (counts.get(key) || 0) + 1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return [...counts.entries()]
|
|
111
|
+
.filter(([, n]) => n >= Math.max(5, Math.ceil(ctx.site.pages.length * 0.8)))
|
|
112
|
+
.map(([key, n]) => ({
|
|
113
|
+
subject: { type: 'site', identifier: key },
|
|
114
|
+
summary: `Exact-match anchor repeated ${n} times sitewide: ${key.split('→')[0]}`,
|
|
115
|
+
evidence: [`${n} occurrences across ${ctx.site.pages.length} pages`],
|
|
116
|
+
confidence: 'medium',
|
|
117
|
+
}));
|
|
118
|
+
},
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
export default D;
|