@nebulacomponents/citable 1.12.0 → 1.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +163 -0
- package/README.md +23 -1
- package/dist/universal/.agents/skills/citable/SKILL.md +12 -1
- package/dist/universal/.agents/skills/citable/VERSION +1 -1
- package/dist/universal/.agents/skills/citable/commands/README.md +2 -1
- package/dist/universal/.agents/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.agents/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.agents/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.agents/skills/citable/manifest.json +30 -10
- package/dist/universal/.agents/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.agents/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.agents/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.agents/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.agents/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.agents/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.agents/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.agents/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.agents/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.agents/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.agents/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.agents/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.agents/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.agents/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.agents/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.agents/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.agents/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.agents/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.agents/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.agents/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.agents/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.claude/skills/citable/SKILL.md +12 -1
- package/dist/universal/.claude/skills/citable/VERSION +1 -1
- package/dist/universal/.claude/skills/citable/commands/README.md +2 -1
- package/dist/universal/.claude/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.claude/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.claude/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.claude/skills/citable/manifest.json +30 -10
- package/dist/universal/.claude/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.claude/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.claude/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.claude/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.claude/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.claude/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.claude/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.claude/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.claude/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.claude/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.claude/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.claude/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.claude/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.claude/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.claude/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.claude/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.claude/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.claude/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.claude/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.claude/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.claude/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.cursor/skills/citable/SKILL.md +12 -1
- package/dist/universal/.cursor/skills/citable/VERSION +1 -1
- package/dist/universal/.cursor/skills/citable/commands/README.md +2 -1
- package/dist/universal/.cursor/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.cursor/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.cursor/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +30 -10
- package/dist/universal/.cursor/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.cursor/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.cursor/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.cursor/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.cursor/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.cursor/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.cursor/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.cursor/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.cursor/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.cursor/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.cursor/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.cursor/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.cursor/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.cursor/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.cursor/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.cursor/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.cursor/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.cursor/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.cursor/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.cursor/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.cursor/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.gemini/skills/citable/SKILL.md +12 -1
- package/dist/universal/.gemini/skills/citable/VERSION +1 -1
- package/dist/universal/.gemini/skills/citable/commands/README.md +2 -1
- package/dist/universal/.gemini/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.gemini/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.gemini/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +30 -10
- package/dist/universal/.gemini/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.gemini/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.gemini/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.gemini/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.gemini/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.gemini/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.gemini/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.gemini/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.gemini/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.gemini/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.gemini/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.gemini/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.gemini/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.gemini/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.gemini/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.gemini/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.gemini/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.gemini/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.gemini/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.gemini/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.gemini/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.github/skills/citable/SKILL.md +12 -1
- package/dist/universal/.github/skills/citable/VERSION +1 -1
- package/dist/universal/.github/skills/citable/commands/README.md +2 -1
- package/dist/universal/.github/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.github/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.github/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.github/skills/citable/manifest.json +30 -10
- package/dist/universal/.github/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.github/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.github/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.github/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.github/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.github/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.github/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.github/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.github/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.github/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.github/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.github/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.github/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.github/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.github/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.github/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.github/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.github/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.github/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.github/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.github/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.kiro/skills/citable/SKILL.md +12 -1
- package/dist/universal/.kiro/skills/citable/VERSION +1 -1
- package/dist/universal/.kiro/skills/citable/commands/README.md +2 -1
- package/dist/universal/.kiro/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.kiro/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.kiro/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +30 -10
- package/dist/universal/.kiro/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.kiro/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.kiro/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.kiro/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.kiro/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.kiro/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.kiro/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.kiro/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.kiro/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.kiro/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.kiro/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.kiro/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.kiro/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.kiro/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.kiro/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.kiro/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.kiro/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.kiro/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.kiro/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.kiro/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.kiro/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.opencode/skills/citable/SKILL.md +12 -1
- package/dist/universal/.opencode/skills/citable/VERSION +1 -1
- package/dist/universal/.opencode/skills/citable/commands/README.md +2 -1
- package/dist/universal/.opencode/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.opencode/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.opencode/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +30 -10
- package/dist/universal/.opencode/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.opencode/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.opencode/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.opencode/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.opencode/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.opencode/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.opencode/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.opencode/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.opencode/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.opencode/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.opencode/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.opencode/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.opencode/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.opencode/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.opencode/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.opencode/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.opencode/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.opencode/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.opencode/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.opencode/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.opencode/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.pi/agent/skills/citable/SKILL.md +12 -1
- package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
- package/dist/universal/.pi/agent/skills/citable/commands/README.md +2 -1
- package/dist/universal/.pi/agent/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.pi/agent/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.pi/agent/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +30 -10
- package/dist/universal/.pi/agent/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.pi/agent/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.pi/agent/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.qoder/skills/citable/SKILL.md +12 -1
- package/dist/universal/.qoder/skills/citable/VERSION +1 -1
- package/dist/universal/.qoder/skills/citable/commands/README.md +2 -1
- package/dist/universal/.qoder/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.qoder/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.qoder/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +30 -10
- package/dist/universal/.qoder/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.qoder/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.qoder/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.qoder/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.qoder/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.qoder/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.qoder/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.qoder/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.qoder/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.qoder/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.qoder/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.qoder/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.qoder/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.qoder/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.qoder/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.qoder/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.qoder/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.qoder/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.qoder/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.qoder/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.qoder/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.rovodev/skills/citable/SKILL.md +12 -1
- package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
- package/dist/universal/.rovodev/skills/citable/commands/README.md +2 -1
- package/dist/universal/.rovodev/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.rovodev/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.rovodev/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +30 -10
- package/dist/universal/.rovodev/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.rovodev/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.rovodev/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.rovodev/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.rovodev/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.rovodev/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.rovodev/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.rovodev/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.rovodev/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.rovodev/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.rovodev/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.rovodev/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.rovodev/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.rovodev/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.rovodev/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.rovodev/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.rovodev/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.rovodev/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.rovodev/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.rovodev/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.rovodev/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.trae/skills/citable/SKILL.md +12 -1
- package/dist/universal/.trae/skills/citable/VERSION +1 -1
- package/dist/universal/.trae/skills/citable/commands/README.md +2 -1
- package/dist/universal/.trae/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.trae/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.trae/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.trae/skills/citable/manifest.json +30 -10
- package/dist/universal/.trae/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.trae/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.trae/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.trae/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.trae/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.trae/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.trae/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.trae/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.trae/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.trae/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.trae/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.trae/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.trae/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.trae/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.trae/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.trae/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.trae/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.trae/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.trae/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.trae/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.trae/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/.trae-cn/skills/citable/SKILL.md +12 -1
- package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
- package/dist/universal/.trae-cn/skills/citable/commands/README.md +2 -1
- package/dist/universal/.trae-cn/skills/citable/commands/artifact-interchange.md +28 -0
- package/dist/universal/.trae-cn/skills/citable/commands/field-validation.md +71 -0
- package/dist/universal/.trae-cn/skills/citable/commands/observe-and-act.md +5 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +30 -10
- package/dist/universal/.trae-cn/skills/citable/references/aeo-geo-validation.md +1 -1
- package/dist/universal/.trae-cn/skills/citable/references/capability-boundaries.md +1 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/artifact-interchange.schema.json +58 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/assumption.schema.json +119 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/customer-outcome.schema.json +119 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/decision.schema.json +154 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/deployment-receipt.schema.json +51 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/initiative.schema.json +185 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/kpi.schema.json +108 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.trae-cn/skills/citable/schemas/release-manifest.schema.json +74 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/release-state.schema.json +40 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/risk.schema.json +172 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/scenario.schema.json +165 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/variance.schema.json +112 -0
- package/dist/universal/manifest.json +363 -123
- package/package.json +4 -1
- package/release/surfaces.json +21 -0
- package/schemas/acceptance-corpus.schema.json +168 -0
- package/schemas/acceptance-run-context.schema.json +17 -0
- package/schemas/acceptance-run-receipt.schema.json +88 -0
- package/schemas/artifact-interchange.schema.json +58 -0
- package/schemas/assumption.schema.json +119 -0
- package/schemas/browser-evidence-plan.schema.json +76 -0
- package/schemas/corpus-publication-receipt.schema.json +24 -0
- package/schemas/customer-outcome.schema.json +119 -0
- package/schemas/decision.schema.json +154 -0
- package/schemas/deployment-receipt.schema.json +51 -0
- package/schemas/field-validation-metrics.schema.json +15 -0
- package/schemas/initiative.schema.json +185 -0
- package/schemas/kpi.schema.json +108 -0
- package/schemas/observation.schema.json +1 -1
- package/schemas/release-manifest.schema.json +74 -0
- package/schemas/release-state.schema.json +40 -0
- package/schemas/risk.schema.json +172 -0
- package/schemas/scenario.schema.json +165 -0
- package/schemas/variance.schema.json +112 -0
- package/scripts/release-governance.js +123 -0
- package/skill/SKILL.md +12 -1
- package/skill/commands/README.md +2 -1
- package/skill/commands/artifact-interchange.md +28 -0
- package/skill/commands/field-validation.md +71 -0
- package/skill/commands/observe-and-act.md +5 -0
- package/skill/references/aeo-geo-validation.md +1 -1
- package/skill/references/capability-boundaries.md +1 -0
- package/src/acceptance/reproducibility.js +180 -0
- package/src/artifacts/interchange.js +179 -0
- package/src/cli/index.js +143 -4
- package/src/commands/assumptionAudit.js +111 -0
- package/src/commands/audit.js +6 -0
- package/src/commands/boardReport.js +251 -0
- package/src/commands/competitiveIntel.js +124 -0
- package/src/commands/corpus.js +322 -0
- package/src/commands/decisionMemo.js +202 -0
- package/src/commands/executive.js +167 -0
- package/src/commands/executiveReview.js +206 -0
- package/src/commands/init.js +14 -1
- package/src/commands/kpi.js +86 -0
- package/src/commands/monitor.js +9 -0
- package/src/commands/observe.js +84 -2
- package/src/commands/outcomes.js +113 -0
- package/src/commands/prioritize.js +108 -0
- package/src/commands/risk.js +104 -0
- package/src/commands/scenario.js +98 -0
- package/src/commands/variance.js +102 -0
- package/src/detectors/framework.js +37 -0
- package/src/detectors/page.js +10 -10
- package/src/detectors/tech.js +5 -3
- package/src/extractor/site.js +21 -6
- package/src/observations/browserJourney.js +167 -0
- package/src/observations/media.js +8 -1
- package/src/registries/index.js +107 -6
- package/src/release/governance.js +331 -0
- package/src/shared/asOf.js +18 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* outcomes command — Customer Outcomes registry
|
|
3
|
+
*
|
|
4
|
+
* Enforces the finding_produced → causal_relationship_established
|
|
5
|
+
* progression and refuses to conflate activity with validated impact.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* citable outcomes list [--stage <stage>]
|
|
9
|
+
* citable outcomes show <outcome_id>
|
|
10
|
+
* citable outcomes validate
|
|
11
|
+
* citable outcomes summary — stage distribution summary
|
|
12
|
+
*/
|
|
13
|
+
import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
|
|
14
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export const OUTCOME_STAGES = [
|
|
19
|
+
'finding_produced',
|
|
20
|
+
'finding_accepted',
|
|
21
|
+
'finding_remediated',
|
|
22
|
+
'remediation_validated',
|
|
23
|
+
'search_result_changed',
|
|
24
|
+
'answer_engine_changed',
|
|
25
|
+
'commercial_outcome_changed',
|
|
26
|
+
'causal_relationship_established',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export async function outcomesCommand(args, root = process.cwd()) {
|
|
30
|
+
const [subcommand, ...rest] = args;
|
|
31
|
+
const file = path.join(contextDir(root), 'customer-outcomes.yaml');
|
|
32
|
+
|
|
33
|
+
switch (subcommand) {
|
|
34
|
+
case 'show': return outcomeShow(file, rest[0]);
|
|
35
|
+
case 'validate': return outcomeValidate(file);
|
|
36
|
+
case 'summary': return outcomeSummary(file);
|
|
37
|
+
default: return outcomeList(file, rest);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function load(file) {
|
|
42
|
+
return loadRegistryFile(file, 'customer-outcomes');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function outcomeList(file, args) {
|
|
46
|
+
const data = load(file);
|
|
47
|
+
const stageFilter = args.find((_, i, a) => a[i-1] === '--stage');
|
|
48
|
+
let entries = stageFilter
|
|
49
|
+
? data.entries.filter(e => e.outcome_stage === stageFilter)
|
|
50
|
+
: data.entries;
|
|
51
|
+
return {
|
|
52
|
+
outcomes: entries.map(e => ({
|
|
53
|
+
outcome_id: e.outcome_id,
|
|
54
|
+
customer: e.customer,
|
|
55
|
+
property: e.property,
|
|
56
|
+
outcome_stage: e.outcome_stage,
|
|
57
|
+
causal_confidence: e.causal_confidence,
|
|
58
|
+
customer_confirmed: e.customer_confirmed,
|
|
59
|
+
independently_verified: e.independently_verified ?? false,
|
|
60
|
+
})),
|
|
61
|
+
total: entries.length,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function outcomeShow(file, id) {
|
|
66
|
+
if (!id) return { error: 'outcome_id required' };
|
|
67
|
+
const data = load(file);
|
|
68
|
+
const o = data.entries.find(e => e.outcome_id === id);
|
|
69
|
+
if (!o) return { error: `Outcome not found: ${id}` };
|
|
70
|
+
return { outcome: o };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function outcomeSummary(file) {
|
|
74
|
+
const data = load(file);
|
|
75
|
+
const dist = {};
|
|
76
|
+
for (const s of OUTCOME_STAGES) dist[s] = 0;
|
|
77
|
+
for (const e of data.entries) dist[e.outcome_stage] = (dist[e.outcome_stage] ?? 0) + 1;
|
|
78
|
+
const verified = data.entries.filter(e => e.independently_verified).length;
|
|
79
|
+
const confirmed = data.entries.filter(e => e.customer_confirmed).length;
|
|
80
|
+
return {
|
|
81
|
+
stage_distribution: dist,
|
|
82
|
+
customer_confirmed: confirmed,
|
|
83
|
+
independently_verified: verified,
|
|
84
|
+
total: data.entries.length,
|
|
85
|
+
warning: dist.finding_produced > 0 && dist.causal_relationship_established === 0
|
|
86
|
+
? 'All outcomes at finding_produced stage — no causal relationships established yet'
|
|
87
|
+
: null,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function outcomeValidate(file) {
|
|
92
|
+
const data = load(file);
|
|
93
|
+
const problems = [...registryLoadProblems(data)];
|
|
94
|
+
const { valid, errors } = validateAgainst('customer-outcome.schema.json', data);
|
|
95
|
+
if (!valid) problems.push(...errors);
|
|
96
|
+
|
|
97
|
+
for (const o of data.entries) {
|
|
98
|
+
// Cannot claim causal confidence without evidence
|
|
99
|
+
if (['strong','verified'].includes(o.causal_confidence) && (!o.evidence_package || o.evidence_package.length === 0))
|
|
100
|
+
problems.push(`${o.outcome_id}: causal_confidence "${o.causal_confidence}" requires evidence_package`);
|
|
101
|
+
// Cannot mark independently_verified without customer_confirmed first
|
|
102
|
+
if (o.independently_verified && !o.customer_confirmed)
|
|
103
|
+
problems.push(`${o.outcome_id}: independently_verified=true but customer_confirmed=false`);
|
|
104
|
+
// Commercial value requires validated stage
|
|
105
|
+
if (o.commercial_value && !['commercial_outcome_changed','causal_relationship_established'].includes(o.outcome_stage))
|
|
106
|
+
problems.push(`${o.outcome_id}: commercial_value set but outcome_stage is "${o.outcome_stage}" — commercial value requires commercial_outcome_changed or causal_relationship_established`);
|
|
107
|
+
// Publication requires confirmation
|
|
108
|
+
if (o.publication_permission && !o.customer_confirmed)
|
|
109
|
+
problems.push(`${o.outcome_id}: publication_permission=true but customer_confirmed=false`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { valid: problems.length === 0, problems, checked: data.entries.length };
|
|
113
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prioritize command — Initiative Prioritization
|
|
3
|
+
*
|
|
4
|
+
* Ranks roadmap and investment choices. Weights must be visible when
|
|
5
|
+
* weighted scoring is used — no opaque scores.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* citable prioritize [--status proposed|approved]
|
|
9
|
+
* citable prioritize show <initiative_id>
|
|
10
|
+
* citable prioritize validate
|
|
11
|
+
* citable prioritize rank — ranked list with explicit criteria
|
|
12
|
+
*/
|
|
13
|
+
import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
|
|
14
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
const SCALE = { none: 0, low: 1, medium: 2, high: 3, critical: 4, validated: 4, transformative: 4, trivial: 0, very_high: 4, negligible: 0, 'n/a': 0 };
|
|
19
|
+
|
|
20
|
+
export async function prioritizeCommand(args, root = process.cwd()) {
|
|
21
|
+
const [subcommand, ...rest] = args;
|
|
22
|
+
const file = path.join(contextDir(root), 'initiatives.yaml');
|
|
23
|
+
|
|
24
|
+
switch (subcommand) {
|
|
25
|
+
case 'show': return initiativeShow(file, rest[0]);
|
|
26
|
+
case 'validate': return initiativeValidate(file);
|
|
27
|
+
case 'rank': return initiativeRank(file);
|
|
28
|
+
case 'list':
|
|
29
|
+
default: {
|
|
30
|
+
const statusFilter = rest[rest.indexOf('--status') + 1] ?? null;
|
|
31
|
+
return initiativeList(file, statusFilter);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function load(file) {
|
|
37
|
+
return loadRegistryFile(file, 'initiatives');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function initiativeList(file, statusFilter) {
|
|
41
|
+
const data = load(file);
|
|
42
|
+
let entries = statusFilter ? data.entries.filter(i => i.status === statusFilter) : data.entries;
|
|
43
|
+
return {
|
|
44
|
+
initiatives: entries.map(i => ({
|
|
45
|
+
initiative_id: i.initiative_id,
|
|
46
|
+
title: i.title,
|
|
47
|
+
customer_demand: i.customer_demand,
|
|
48
|
+
revenue_potential: i.revenue_potential,
|
|
49
|
+
strategic_differentiation: i.strategic_differentiation,
|
|
50
|
+
evidence_strength: i.evidence_strength,
|
|
51
|
+
engineering_cost: i.engineering_cost,
|
|
52
|
+
reversibility: i.reversibility,
|
|
53
|
+
status: i.status,
|
|
54
|
+
owner: i.owner,
|
|
55
|
+
})),
|
|
56
|
+
total: entries.length,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function initiativeShow(file, id) {
|
|
61
|
+
if (!id) return { error: 'initiative_id required' };
|
|
62
|
+
const data = load(file);
|
|
63
|
+
const i = data.entries.find(e => e.initiative_id === id);
|
|
64
|
+
if (!i) return { error: `Initiative not found: ${id}` };
|
|
65
|
+
return { initiative: i };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function initiativeRank(file) {
|
|
69
|
+
const data = load(file);
|
|
70
|
+
const scorable = data.entries.filter(i => ['proposed','approved'].includes(i.status));
|
|
71
|
+
|
|
72
|
+
// Transparent scoring: benefit - cost, with evidence strength as multiplier
|
|
73
|
+
const scored = scorable.map(i => {
|
|
74
|
+
const benefit = (SCALE[i.customer_demand] ?? 0) + (SCALE[i.revenue_potential] ?? 0) + (SCALE[i.strategic_differentiation] ?? 0);
|
|
75
|
+
const cost = (SCALE[i.engineering_cost] ?? 0) + (SCALE[i.operating_cost ?? 'none'] ?? 0) + (SCALE[i.legal_risk ?? 'none'] ?? 0);
|
|
76
|
+
const evidenceMultiplier = { assumption: 0.5, anecdote: 0.6, proxy: 0.7, validated: 0.9, verified: 1.0 }[i.evidence_strength] ?? 0.5;
|
|
77
|
+
const score = (benefit - cost) * evidenceMultiplier;
|
|
78
|
+
return { initiative_id: i.initiative_id, title: i.title, score: Math.round(score * 10) / 10, benefit, cost, evidence_strength: i.evidence_strength, reversibility: i.reversibility, evidence_multiplier: evidenceMultiplier };
|
|
79
|
+
}).sort((a, b) => b.score - a.score);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
ranked: scored,
|
|
83
|
+
scoring_method: 'transparent: (customer_demand + revenue_potential + strategic_differentiation - engineering_cost - operating_cost - legal_risk) × evidence_multiplier',
|
|
84
|
+
weights: 'equal weights — override with scoring_weights field per initiative if asymmetric weighting is required',
|
|
85
|
+
total: scored.length,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function initiativeValidate(file) {
|
|
90
|
+
const data = load(file);
|
|
91
|
+
const problems = [...registryLoadProblems(data)];
|
|
92
|
+
const { valid, errors } = validateAgainst('initiative.schema.json', data);
|
|
93
|
+
if (!valid) problems.push(...errors);
|
|
94
|
+
|
|
95
|
+
for (const i of data.entries) {
|
|
96
|
+
// Evidence strength required
|
|
97
|
+
if (i.evidence_strength === 'assumption' && i.revenue_potential === 'transformative')
|
|
98
|
+
problems.push(`${i.initiative_id}: revenue_potential=transformative with evidence_strength=assumption — requires at least "proxy" evidence`);
|
|
99
|
+
// One-way decisions need justification
|
|
100
|
+
if (i.reversibility === 'effectively_one_way' && !i.opportunity_cost)
|
|
101
|
+
problems.push(`${i.initiative_id}: effectively_one_way initiatives require opportunity_cost`);
|
|
102
|
+
// Platform dependency documented for platform-dependent initiatives
|
|
103
|
+
if (!i.platform_dependency && /search.console|bing|openai|google|cloudflare/i.test(i.title))
|
|
104
|
+
problems.push(`${i.initiative_id}: platform_dependency should be documented for platform-dependent initiatives`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { valid: problems.length === 0, problems, checked: data.entries.length };
|
|
108
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* risk command — Risk Register
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* citable risk list [--board] List all risks (--board: board-visible only)
|
|
6
|
+
* citable risk show <risk_id>
|
|
7
|
+
* citable risk validate
|
|
8
|
+
* citable risk top Top risks by residual_exposure
|
|
9
|
+
*/
|
|
10
|
+
import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
|
|
11
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
|
|
14
|
+
import { dateOnly, parseAsOf } from '../shared/asOf.js';
|
|
15
|
+
|
|
16
|
+
const EXPOSURE_ORDER = ['low','medium','high','critical'];
|
|
17
|
+
|
|
18
|
+
export async function riskCommand(args, root = process.cwd()) {
|
|
19
|
+
const [subcommand, ...rest] = args;
|
|
20
|
+
const file = path.join(contextDir(root), 'risks.yaml');
|
|
21
|
+
|
|
22
|
+
switch (subcommand) {
|
|
23
|
+
case 'show': return riskShow(file, rest[0]);
|
|
24
|
+
case 'validate': return riskValidate(file, parseAsOf(args));
|
|
25
|
+
case 'top': return riskTop(file);
|
|
26
|
+
case 'list':
|
|
27
|
+
default:
|
|
28
|
+
return riskList(file, { boardOnly: rest.includes('--board') });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function load(file) {
|
|
33
|
+
return loadRegistryFile(file, 'risks');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function riskList(file, { boardOnly = false } = {}) {
|
|
37
|
+
const data = load(file);
|
|
38
|
+
let entries = boardOnly ? data.entries.filter(r => r.board_visibility) : data.entries;
|
|
39
|
+
return {
|
|
40
|
+
risks: entries.map(r => ({
|
|
41
|
+
risk_id: r.risk_id,
|
|
42
|
+
title: r.title,
|
|
43
|
+
category: r.category,
|
|
44
|
+
gross_exposure: r.gross_exposure,
|
|
45
|
+
residual_exposure:r.residual_exposure,
|
|
46
|
+
trend: r.trend,
|
|
47
|
+
review_date: r.review_date,
|
|
48
|
+
board_visibility: r.board_visibility,
|
|
49
|
+
})),
|
|
50
|
+
total: entries.length,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function riskShow(file, id) {
|
|
55
|
+
if (!id) return { error: 'risk_id required' };
|
|
56
|
+
const data = load(file);
|
|
57
|
+
const r = data.entries.find(e => e.risk_id === id);
|
|
58
|
+
if (!r) return { error: `Risk not found: ${id}` };
|
|
59
|
+
return { risk: r };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function riskTop(file) {
|
|
63
|
+
const data = load(file);
|
|
64
|
+
const sorted = [...data.entries].sort((a, b) =>
|
|
65
|
+
EXPOSURE_ORDER.indexOf(b.residual_exposure) - EXPOSURE_ORDER.indexOf(a.residual_exposure)
|
|
66
|
+
);
|
|
67
|
+
return {
|
|
68
|
+
top_risks: sorted.slice(0, 10).map(r => ({
|
|
69
|
+
risk_id: r.risk_id,
|
|
70
|
+
title: r.title,
|
|
71
|
+
category: r.category,
|
|
72
|
+
residual_exposure: r.residual_exposure,
|
|
73
|
+
trend: r.trend,
|
|
74
|
+
control_effectiveness: r.control_effectiveness,
|
|
75
|
+
trigger_threshold: r.trigger_threshold,
|
|
76
|
+
response_owner: r.response_owner,
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function riskValidate(file, asOf) {
|
|
82
|
+
const data = load(file);
|
|
83
|
+
const problems = [...registryLoadProblems(data)];
|
|
84
|
+
const { valid, errors } = validateAgainst('risk.schema.json', data);
|
|
85
|
+
if (!valid) problems.push(...errors);
|
|
86
|
+
|
|
87
|
+
for (const r of data.entries) {
|
|
88
|
+
// KRIs required for critical/high risks
|
|
89
|
+
if (['high','critical'].includes(r.residual_exposure) && (!r.key_risk_indicators || r.key_risk_indicators.length === 0))
|
|
90
|
+
problems.push(`${r.risk_id}: high/critical residual_exposure requires key_risk_indicators`);
|
|
91
|
+
// Trigger threshold required for board-visible risks
|
|
92
|
+
if (r.board_visibility && !r.trigger_threshold)
|
|
93
|
+
problems.push(`${r.risk_id}: board_visibility=true requires trigger_threshold`);
|
|
94
|
+
// Stale review dates
|
|
95
|
+
const reviewDate = r.review_date ? new Date(r.review_date) : null;
|
|
96
|
+
if (reviewDate && reviewDate < asOf)
|
|
97
|
+
problems.push(`${r.risk_id}: review_date ${r.review_date} is in the past — risk review overdue`);
|
|
98
|
+
// Controls effectiveness vs gross/residual mismatch
|
|
99
|
+
if (r.gross_exposure === 'critical' && r.control_effectiveness === 'none' && r.residual_exposure !== 'critical')
|
|
100
|
+
problems.push(`${r.risk_id}: control_effectiveness=none but residual_exposure < gross_exposure — inconsistent`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { valid: problems.length === 0, problems, checked: data.entries.length, as_of: dateOnly(asOf) };
|
|
104
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scenario command — Scenario War Room
|
|
3
|
+
*
|
|
4
|
+
* Models compound risks with cascade analysis and early-warning triggers.
|
|
5
|
+
* Maximum 3 variables per scenario. Requires explicit hedges with cost,
|
|
6
|
+
* impact, owner, and deadline — not just worst-case narratives.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* citable scenario list
|
|
10
|
+
* citable scenario show <scenario_id>
|
|
11
|
+
* citable scenario validate
|
|
12
|
+
* citable scenario triggers — early-warning trigger summary
|
|
13
|
+
*/
|
|
14
|
+
import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
|
|
15
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export async function scenarioCommand(args, root = process.cwd()) {
|
|
20
|
+
const [subcommand, ...rest] = args;
|
|
21
|
+
const file = path.join(contextDir(root), 'scenarios.yaml');
|
|
22
|
+
|
|
23
|
+
switch (subcommand) {
|
|
24
|
+
case 'show': return scenarioShow(file, rest[0]);
|
|
25
|
+
case 'validate': return scenarioValidate(file);
|
|
26
|
+
case 'triggers': return scenarioTriggers(file);
|
|
27
|
+
default: return scenarioList(file);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function load(file) {
|
|
32
|
+
return loadRegistryFile(file, 'scenarios');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function scenarioList(file) {
|
|
36
|
+
const data = load(file);
|
|
37
|
+
return {
|
|
38
|
+
scenarios: data.entries.map(s => ({
|
|
39
|
+
scenario_id: s.scenario_id,
|
|
40
|
+
title: s.title,
|
|
41
|
+
variables: (s.variables ?? []).length,
|
|
42
|
+
cascade_steps: (s.cascade_analysis ?? []).length,
|
|
43
|
+
hedges: (s.hedges ?? []).length,
|
|
44
|
+
early_warnings: (s.early_warning_triggers ?? []).length,
|
|
45
|
+
owner: s.owner,
|
|
46
|
+
})),
|
|
47
|
+
total: data.entries.length,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function scenarioShow(file, id) {
|
|
52
|
+
if (!id) return { error: 'scenario_id required' };
|
|
53
|
+
const data = load(file);
|
|
54
|
+
const s = data.entries.find(e => e.scenario_id === id);
|
|
55
|
+
if (!s) return { error: `Scenario not found: ${id}` };
|
|
56
|
+
return { scenario: s };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function scenarioTriggers(file) {
|
|
60
|
+
const data = load(file);
|
|
61
|
+
return {
|
|
62
|
+
triggers: data.entries.flatMap(s =>
|
|
63
|
+
(s.early_warning_triggers ?? []).map(t => ({
|
|
64
|
+
scenario_id: s.scenario_id, title: s.title, trigger: t,
|
|
65
|
+
}))
|
|
66
|
+
),
|
|
67
|
+
total_scenarios: data.entries.length,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function scenarioValidate(file) {
|
|
72
|
+
const data = load(file);
|
|
73
|
+
const problems = [...registryLoadProblems(data)];
|
|
74
|
+
const { valid, errors } = validateAgainst('scenario.schema.json', data);
|
|
75
|
+
if (!valid) problems.push(...errors);
|
|
76
|
+
|
|
77
|
+
for (const s of data.entries) {
|
|
78
|
+
// Variables capped at 3
|
|
79
|
+
if ((s.variables ?? []).length > 3)
|
|
80
|
+
problems.push(`${s.scenario_id}: maximum 3 variables per scenario — combine compound drivers into a single variable`);
|
|
81
|
+
// Cascade analysis required (not just isolated risk statements)
|
|
82
|
+
if (!s.cascade_analysis || s.cascade_analysis.length === 0)
|
|
83
|
+
problems.push(`${s.scenario_id}: cascade_analysis required — scenarios must show cascading effects, not isolated risks`);
|
|
84
|
+
// All three states required
|
|
85
|
+
if (!s.states?.base || !s.states?.stress || !s.states?.severe)
|
|
86
|
+
problems.push(`${s.scenario_id}: all three states (base, stress, severe) required`);
|
|
87
|
+
// Hedges must have all required fields
|
|
88
|
+
for (const h of s.hedges ?? []) {
|
|
89
|
+
if (!h.cost || !h.impact || !h.owner || !h.deadline)
|
|
90
|
+
problems.push(`${s.scenario_id} hedge "${h.action}": cost, impact, owner, and deadline all required`);
|
|
91
|
+
}
|
|
92
|
+
// Early-warning triggers required
|
|
93
|
+
if (!s.early_warning_triggers || s.early_warning_triggers.length === 0)
|
|
94
|
+
problems.push(`${s.scenario_id}: early_warning_triggers required — scenario without triggers is a narrative, not a management tool`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { valid: problems.length === 0, problems, checked: data.entries.length };
|
|
98
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* variance command — Variance analysis registry
|
|
3
|
+
*
|
|
4
|
+
* Rejects non-causes (market conditions, timing, customer behaviour)
|
|
5
|
+
* unless decomposed into specific observed mechanisms.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* citable variance list [--period <period>]
|
|
9
|
+
* citable variance show <variance_id>
|
|
10
|
+
* citable variance validate
|
|
11
|
+
* citable variance material — list material/critical variances only
|
|
12
|
+
*/
|
|
13
|
+
import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
|
|
14
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// Vague causes that must be decomposed before acceptance
|
|
19
|
+
const REJECTED_CAUSE_PATTERNS = [
|
|
20
|
+
/^market conditions?$/i,
|
|
21
|
+
/^timing$/i,
|
|
22
|
+
/^customer behaviour?$/i,
|
|
23
|
+
/^execution issues?$/i,
|
|
24
|
+
/^macro(economic)?$/i,
|
|
25
|
+
/^seasonality$/i,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export async function varianceCommand(args, root = process.cwd()) {
|
|
29
|
+
const [subcommand, ...rest] = args;
|
|
30
|
+
const file = path.join(contextDir(root), 'variances.yaml');
|
|
31
|
+
|
|
32
|
+
switch (subcommand) {
|
|
33
|
+
case 'show': return varianceShow(file, rest[0]);
|
|
34
|
+
case 'validate': return varianceValidate(file);
|
|
35
|
+
case 'material': return varianceList(file, { materialOnly: true });
|
|
36
|
+
default: {
|
|
37
|
+
const i = rest.indexOf('--period');
|
|
38
|
+
return varianceList(file, { period: i >= 0 ? rest[i + 1] : null });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function load(file) {
|
|
44
|
+
return loadRegistryFile(file, 'variances');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function varianceList(file, { materialOnly = false, period = null } = {}) {
|
|
48
|
+
const data = load(file);
|
|
49
|
+
let entries = data.entries;
|
|
50
|
+
if (materialOnly) entries = entries.filter(v => ['material','critical'].includes(v.materiality));
|
|
51
|
+
if (period) entries = entries.filter(v => v.period === period);
|
|
52
|
+
return {
|
|
53
|
+
variances: entries.map(v => ({
|
|
54
|
+
variance_id: v.variance_id,
|
|
55
|
+
metric_id: v.metric_id,
|
|
56
|
+
period: v.period,
|
|
57
|
+
variance_pct: v.variance_pct,
|
|
58
|
+
materiality: v.materiality,
|
|
59
|
+
primary_driver: v.primary_driver,
|
|
60
|
+
controllable: v.controllable,
|
|
61
|
+
confidence: v.confidence,
|
|
62
|
+
})),
|
|
63
|
+
total: entries.length,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function varianceShow(file, id) {
|
|
68
|
+
if (!id) return { error: 'variance_id required' };
|
|
69
|
+
const data = load(file);
|
|
70
|
+
const v = data.entries.find(e => e.variance_id === id);
|
|
71
|
+
if (!v) return { error: `Variance not found: ${id}` };
|
|
72
|
+
return { variance: v };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function varianceValidate(file) {
|
|
76
|
+
const data = load(file);
|
|
77
|
+
const problems = [...registryLoadProblems(data)];
|
|
78
|
+
const { valid, errors } = validateAgainst('variance.schema.json', data);
|
|
79
|
+
if (!valid) problems.push(...errors);
|
|
80
|
+
|
|
81
|
+
for (const v of data.entries) {
|
|
82
|
+
// Reject vague causes
|
|
83
|
+
for (const pattern of REJECTED_CAUSE_PATTERNS) {
|
|
84
|
+
if (pattern.test((v.primary_driver ?? '').trim())) {
|
|
85
|
+
problems.push(`${v.variance_id}: primary_driver "${v.primary_driver}" is a non-cause — decompose into a specific observed mechanism`);
|
|
86
|
+
}
|
|
87
|
+
for (const d of v.secondary_drivers ?? []) {
|
|
88
|
+
if (pattern.test(d.trim())) {
|
|
89
|
+
problems.push(`${v.variance_id}: secondary_driver "${d}" is a non-cause — decompose into a specific observed mechanism`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Material variances need management response
|
|
94
|
+
if (['material','critical'].includes(v.materiality) && !v.management_response)
|
|
95
|
+
problems.push(`${v.variance_id}: material variance requires management_response`);
|
|
96
|
+
// Evidence required
|
|
97
|
+
if (!v.evidence || v.evidence.length === 0)
|
|
98
|
+
problems.push(`${v.variance_id}: evidence array must not be empty`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { valid: problems.length === 0, problems, checked: data.entries.length };
|
|
102
|
+
}
|
|
@@ -100,12 +100,49 @@ export function runDetectors(detectors, ctx) {
|
|
|
100
100
|
/** Pages whose declared or default intent is to be indexed. */
|
|
101
101
|
export function indexTargets(ctx) {
|
|
102
102
|
return ctx.site.pages.filter((p) => {
|
|
103
|
+
if (isProviderUtilityUrl(p.url)) return false;
|
|
103
104
|
const reg = registryPageFor(ctx, p);
|
|
104
105
|
if (reg?.indexing_intent === 'noindex') return false;
|
|
105
106
|
return true;
|
|
106
107
|
});
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
/** Index targets whose response is an HTML document. */
|
|
111
|
+
export function htmlIndexTargets(ctx) {
|
|
112
|
+
return indexTargets(ctx).filter(isHtmlDocument);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function isHtmlDocument(page) {
|
|
116
|
+
const type = String(page?.contentType || '').toLowerCase();
|
|
117
|
+
return !type || type.includes('text/html') || type.includes('application/xhtml+xml');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** URLs that conventionally identify HTML documents rather than media/data resources. */
|
|
121
|
+
export function isHtmlDocumentUrl(url) {
|
|
122
|
+
try {
|
|
123
|
+
const pathname = new URL(url).pathname;
|
|
124
|
+
const name = pathname.split('/').pop() || '';
|
|
125
|
+
const match = name.match(/\.([a-z0-9]+)$/i);
|
|
126
|
+
return Boolean(match) && ['html', 'htm', 'xhtml'].includes(match[1].toLowerCase());
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function hasHtmlDocumentMarkup(page) {
|
|
133
|
+
return /^\s*(?:<!doctype\s+html\b|<html\b)/i.test(String(page?.rawHtml || ''));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Provider-owned utility routes are link evidence, not default content pages. */
|
|
137
|
+
export function isProviderUtilityUrl(url) {
|
|
138
|
+
try {
|
|
139
|
+
const { pathname } = new URL(url);
|
|
140
|
+
return pathname === '/cdn-cgi' || pathname.startsWith('/cdn-cgi/');
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
109
146
|
/** Match a live page to its registry entry by URL path. */
|
|
110
147
|
export function registryPageFor(ctx, page) {
|
|
111
148
|
const entries = ctx.registries?.pages?.entries || [];
|
package/src/detectors/page.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineDetector,
|
|
1
|
+
import { defineDetector, htmlIndexTargets, pageSubject } from './framework.js';
|
|
2
2
|
|
|
3
3
|
const D = [];
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ D.push(defineDetector({
|
|
|
11
11
|
remediation: 'Add a concise title identifying the page subject and distinguishing it from other pages.',
|
|
12
12
|
verification: 'Confirm a non-empty <title> in rendered HTML.',
|
|
13
13
|
check(ctx) {
|
|
14
|
-
return
|
|
14
|
+
return htmlIndexTargets(ctx).filter((p) => p.status === 200 && !p.title).map((p) => ({
|
|
15
15
|
subject: pageSubject(p), summary: 'Page has no title element', evidence: ['<title> absent or empty'],
|
|
16
16
|
}));
|
|
17
17
|
},
|
|
@@ -27,7 +27,7 @@ D.push(defineDetector({
|
|
|
27
27
|
verification: 'Confirm title uniqueness across index targets.',
|
|
28
28
|
check(ctx) {
|
|
29
29
|
const byTitle = new Map();
|
|
30
|
-
for (const p of
|
|
30
|
+
for (const p of htmlIndexTargets(ctx)) {
|
|
31
31
|
if (!p.title || p.status !== 200) continue;
|
|
32
32
|
if (!byTitle.has(p.title)) byTitle.set(p.title, []);
|
|
33
33
|
byTitle.get(p.title).push(p);
|
|
@@ -49,7 +49,7 @@ D.push(defineDetector({
|
|
|
49
49
|
remediation: 'Add an accurate, page-specific description stating the expected value.',
|
|
50
50
|
verification: 'Confirm meta[name=description] present and non-empty.',
|
|
51
51
|
check(ctx) {
|
|
52
|
-
return
|
|
52
|
+
return htmlIndexTargets(ctx).filter((p) => p.status === 200 && !p.metaDescription).map((p) => ({
|
|
53
53
|
subject: pageSubject(p), summary: 'Page has no meta description', evidence: ['meta[name=description] absent'],
|
|
54
54
|
}));
|
|
55
55
|
},
|
|
@@ -65,7 +65,7 @@ D.push(defineDetector({
|
|
|
65
65
|
verification: 'Confirm description uniqueness.',
|
|
66
66
|
check(ctx) {
|
|
67
67
|
const byDesc = new Map();
|
|
68
|
-
for (const p of
|
|
68
|
+
for (const p of htmlIndexTargets(ctx)) {
|
|
69
69
|
if (!p.metaDescription || p.status !== 200) continue;
|
|
70
70
|
if (!byDesc.has(p.metaDescription)) byDesc.set(p.metaDescription, []);
|
|
71
71
|
byDesc.get(p.metaDescription).push(p);
|
|
@@ -87,7 +87,7 @@ D.push(defineDetector({
|
|
|
87
87
|
remediation: 'Use exactly one H1 that identifies the page purpose.',
|
|
88
88
|
verification: 'Count H1 elements.',
|
|
89
89
|
check(ctx) {
|
|
90
|
-
return
|
|
90
|
+
return htmlIndexTargets(ctx).filter((p) => p.status === 200 && p.h1s.length !== 1).map((p) => ({
|
|
91
91
|
subject: pageSubject(p),
|
|
92
92
|
summary: p.h1s.length === 0 ? 'Page has no H1' : `Page has ${p.h1s.length} H1 elements`,
|
|
93
93
|
evidence: p.h1s.length ? p.h1s.map((h) => `H1: ${h.text}`) : ['no <h1> found'],
|
|
@@ -106,7 +106,7 @@ D.push(defineDetector({
|
|
|
106
106
|
verification: 'Walk heading sequence and confirm no level is skipped.',
|
|
107
107
|
check(ctx) {
|
|
108
108
|
const hits = [];
|
|
109
|
-
for (const p of
|
|
109
|
+
for (const p of htmlIndexTargets(ctx)) {
|
|
110
110
|
if (p.status !== 200) continue;
|
|
111
111
|
let prev = 0;
|
|
112
112
|
for (const h of p.headings) {
|
|
@@ -134,7 +134,7 @@ D.push(defineDetector({
|
|
|
134
134
|
remediation: 'Add descriptive alt text (or empty alt for purely decorative images, reviewed case by case).',
|
|
135
135
|
verification: 'Confirm every <img> has an alt attribute.',
|
|
136
136
|
check(ctx) {
|
|
137
|
-
return
|
|
137
|
+
return htmlIndexTargets(ctx)
|
|
138
138
|
.map((p) => ({ p, missing: p.images.filter((i) => i.alt === undefined || i.alt === null) }))
|
|
139
139
|
.filter(({ p, missing }) => p.status === 200 && missing.length > 0)
|
|
140
140
|
.map(({ p, missing }) => ({
|
|
@@ -156,7 +156,7 @@ D.push(defineDetector({
|
|
|
156
156
|
verification: 'Re-measure extracted word count after revision.',
|
|
157
157
|
check(ctx) {
|
|
158
158
|
const min = ctx.config?.audit?.thin_content_words ?? 120;
|
|
159
|
-
return
|
|
159
|
+
return htmlIndexTargets(ctx)
|
|
160
160
|
.filter((p) => p.status === 200 && p.wordCount > 0 && p.wordCount < min)
|
|
161
161
|
.map((p) => ({
|
|
162
162
|
subject: pageSubject(p),
|
|
@@ -178,7 +178,7 @@ D.push(defineDetector({
|
|
|
178
178
|
verification: 'Re-measure dominant-term density.',
|
|
179
179
|
check(ctx) {
|
|
180
180
|
const hits = [];
|
|
181
|
-
for (const p of
|
|
181
|
+
for (const p of htmlIndexTargets(ctx)) {
|
|
182
182
|
if (p.status !== 200 || p.wordCount < 80) continue;
|
|
183
183
|
const words = p.text.toLowerCase().match(/[a-z][a-z-]{3,}/g) || [];
|
|
184
184
|
const freq = new Map();
|