@nebulacomponents/citable 1.11.0 → 1.13.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 +151 -0
- package/README.md +29 -2
- package/dist/universal/.agents/skills/citable/SKILL.md +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +14 -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 +13 -1
- 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 +3 -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 +12 -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 +14 -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 +13 -1
- package/skill/references/aeo-geo-validation.md +1 -1
- package/skill/references/capability-boundaries.md +3 -0
- package/src/acceptance/reproducibility.js +180 -0
- package/src/artifacts/interchange.js +179 -0
- package/src/cli/index.js +149 -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 +202 -30
- 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
package/src/registries/index.js
CHANGED
|
@@ -23,6 +23,16 @@ export const REGISTRY_SPECS = [
|
|
|
23
23
|
{ file: 'review-items.yaml', kind: 'review_items', schema: 'review-item.schema.json', idField: 'review_item_id' },
|
|
24
24
|
{ file: 'sampling-plans.yaml', kind: 'sampling_plans', schema: 'sampling-plan.schema.json', idField: 'sampling_plan_id' },
|
|
25
25
|
{ file: 'schedules.yaml', kind: 'schedules', schema: 'schedule.schema.json', idField: 'schedule_id' },
|
|
26
|
+
// Executive reporting suite — governed inputs (Phase 1)
|
|
27
|
+
{ file: 'kpis.yaml', kind: 'kpis', schema: 'kpi.schema.json', idField: 'metric_id' },
|
|
28
|
+
{ file: 'variances.yaml', kind: 'variances', schema: 'variance.schema.json', idField: 'variance_id' },
|
|
29
|
+
{ file: 'customer-outcomes.yaml', kind: 'customer-outcomes', schema: 'customer-outcome.schema.json', idField: 'outcome_id' },
|
|
30
|
+
{ file: 'risks.yaml', kind: 'risks', schema: 'risk.schema.json', idField: 'risk_id' },
|
|
31
|
+
// Executive reporting suite — decision support (Phase 2)
|
|
32
|
+
{ file: 'decisions.yaml', kind: 'decisions', schema: 'decision.schema.json', idField: 'decision_id' },
|
|
33
|
+
{ file: 'assumptions.yaml', kind: 'assumptions', schema: 'assumption.schema.json', idField: 'assumption_id' },
|
|
34
|
+
{ file: 'scenarios.yaml', kind: 'scenarios', schema: 'scenario.schema.json', idField: 'scenario_id' },
|
|
35
|
+
{ file: 'initiatives.yaml', kind: 'initiatives', schema: 'initiative.schema.json', idField: 'initiative_id' },
|
|
26
36
|
];
|
|
27
37
|
|
|
28
38
|
export function contextDir(root) {
|
|
@@ -33,6 +43,31 @@ export function emptyRegistry(kind) {
|
|
|
33
43
|
return { version: 1, kind, updated: nowIso(), entries: [] };
|
|
34
44
|
}
|
|
35
45
|
|
|
46
|
+
const LOAD_PROBLEMS = Symbol('registryLoadProblems');
|
|
47
|
+
|
|
48
|
+
/** Read one registry without allowing malformed YAML to crash a command. */
|
|
49
|
+
export function loadRegistryFile(file, kind) {
|
|
50
|
+
let data = emptyRegistry(kind);
|
|
51
|
+
const problems = [];
|
|
52
|
+
if (fs.existsSync(file)) {
|
|
53
|
+
try {
|
|
54
|
+
data = readYaml(file) ?? emptyRegistry(kind);
|
|
55
|
+
if (typeof data !== 'object' || data === null || !Array.isArray(data.entries)) {
|
|
56
|
+
problems.push(`${path.basename(file)}: YAML does not match expected registry shape`);
|
|
57
|
+
data = emptyRegistry(kind);
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
problems.push(`${path.basename(file)}: YAML parse failure: ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
Object.defineProperty(data, LOAD_PROBLEMS, { value: problems, enumerable: false });
|
|
64
|
+
return data;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function registryLoadProblems(data) {
|
|
68
|
+
return data?.[LOAD_PROBLEMS] ?? [];
|
|
69
|
+
}
|
|
70
|
+
|
|
36
71
|
/** Load all registries under <root>/.citable. Missing files load as empty. */
|
|
37
72
|
export function loadRegistries(root) {
|
|
38
73
|
const dir = contextDir(root);
|
|
@@ -63,13 +98,21 @@ export function checkReferentialIntegrity(registries) {
|
|
|
63
98
|
const problems = [];
|
|
64
99
|
const ids = {};
|
|
65
100
|
for (const spec of REGISTRY_SPECS) {
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
101
|
+
const registry = registries[spec.kind] ?? emptyRegistry(spec.kind);
|
|
102
|
+
const schemaValid = (registry.entries || []).filter((entry) =>
|
|
103
|
+
validateAgainst(spec.schema, { ...registry, entries: [entry] }).valid);
|
|
104
|
+
const counts = new Map();
|
|
105
|
+
for (const entry of schemaValid) {
|
|
106
|
+
const id = entry[spec.idField];
|
|
107
|
+
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
72
108
|
}
|
|
109
|
+
for (const [id, count] of counts) {
|
|
110
|
+
if (count > 1) problems.push(`${spec.kind}/${id}: duplicate id ${id}`);
|
|
111
|
+
}
|
|
112
|
+
// Only schema-valid, unambiguous records may satisfy references.
|
|
113
|
+
ids[spec.kind] = new Set(schemaValid
|
|
114
|
+
.map((entry) => entry[spec.idField])
|
|
115
|
+
.filter((id) => counts.get(id) === 1));
|
|
73
116
|
}
|
|
74
117
|
const refChecks = [
|
|
75
118
|
['claims', 'evidence', 'evidence', 'claim_id'],
|
|
@@ -131,6 +174,64 @@ export function checkReferentialIntegrity(registries) {
|
|
|
131
174
|
}
|
|
132
175
|
const reviewItemIds = ids.review_items || new Set();
|
|
133
176
|
for (const plan of registries.sampling_plans?.entries || []) for (const ref of plan.selected_item_ids || []) if (!reviewItemIds.has(ref)) problems.push(`sampling_plans/${plan.sampling_plan_id}: references unknown review item id "${ref}"`);
|
|
177
|
+
|
|
178
|
+
// ── Executive reporting suite cross-registry checks ────────────────────────
|
|
179
|
+
const kpiIds = ids.kpis || new Set();
|
|
180
|
+
const outcomeIds = ids['customer-outcomes'] || new Set();
|
|
181
|
+
const decisionIds = ids.decisions || new Set();
|
|
182
|
+
const assumptionIds = ids.assumptions || new Set();
|
|
183
|
+
const riskIds = ids.risks || new Set();
|
|
184
|
+
const initiativeIds = ids.initiatives || new Set();
|
|
185
|
+
|
|
186
|
+
// variances must reference a known KPI metric_id
|
|
187
|
+
for (const v of registries.variances?.entries || []) {
|
|
188
|
+
if (v.metric_id && !kpiIds.has(v.metric_id))
|
|
189
|
+
problems.push(`variances/${v.variance_id}: metric_id "${v.metric_id}" references unknown kpi`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// decisions: supporting/contradicting evidence can reference outcome IDs
|
|
193
|
+
for (const d of registries.decisions?.entries || []) {
|
|
194
|
+
const prefix = `decisions/${d.decision_id}`;
|
|
195
|
+
for (const ref of d.supporting_evidence || []) {
|
|
196
|
+
if (typeof ref === 'string' && ref.startsWith('OUT-') && !outcomeIds.has(ref))
|
|
197
|
+
problems.push(`${prefix}: supporting_evidence references unknown customer-outcome "${ref}"`);
|
|
198
|
+
}
|
|
199
|
+
for (const ref of d.contradicting_evidence || []) {
|
|
200
|
+
if (typeof ref === 'string' && ref.startsWith('OUT-') && !outcomeIds.has(ref))
|
|
201
|
+
problems.push(`${prefix}: contradicting_evidence references unknown customer-outcome "${ref}"`);
|
|
202
|
+
}
|
|
203
|
+
for (const ref of d.assumptions || []) {
|
|
204
|
+
if (typeof ref === 'string' && ref.startsWith('ASMP-') && !assumptionIds.has(ref))
|
|
205
|
+
problems.push(`${prefix}: assumptions references unknown assumption "${ref}"`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// initiatives: linked_kpis, linked_outcomes, linked_risks, linked_decisions
|
|
210
|
+
for (const i of registries.initiatives?.entries || []) {
|
|
211
|
+
const prefix = `initiatives/${i.initiative_id}`;
|
|
212
|
+
for (const ref of i.linked_kpis || [])
|
|
213
|
+
if (!kpiIds.has(ref)) problems.push(`${prefix}: linked_kpis references unknown kpi "${ref}"`);
|
|
214
|
+
for (const ref of i.linked_outcomes || [])
|
|
215
|
+
if (!outcomeIds.has(ref)) problems.push(`${prefix}: linked_outcomes references unknown customer-outcome "${ref}"`);
|
|
216
|
+
for (const ref of i.linked_risks || [])
|
|
217
|
+
if (!riskIds.has(ref)) problems.push(`${prefix}: linked_risks references unknown risk "${ref}"`);
|
|
218
|
+
for (const ref of i.linked_decisions || [])
|
|
219
|
+
if (!decisionIds.has(ref)) problems.push(`${prefix}: linked_decisions references unknown decision "${ref}"`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// scenarios: variable_ids should reference known KPIs or risks
|
|
223
|
+
for (const s of registries.scenarios?.entries || []) {
|
|
224
|
+
const prefix = `scenarios/${s.scenario_id}`;
|
|
225
|
+
for (const v of s.variables || []) {
|
|
226
|
+
const ref = v.variable_id;
|
|
227
|
+
if (!ref) continue;
|
|
228
|
+
if (ref.startsWith('KPI-') && !kpiIds.has(ref))
|
|
229
|
+
problems.push(`${prefix}: variable "${ref}" references unknown kpi`);
|
|
230
|
+
if (ref.startsWith('RISK-') && !riskIds.has(ref))
|
|
231
|
+
problems.push(`${prefix}: variable "${ref}" references unknown risk`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
134
235
|
return problems;
|
|
135
236
|
}
|
|
136
237
|
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { ALL_DETECTORS, detectorsByNamespace } from '../detectors/index.js';
|
|
5
|
+
import { REGISTRY_SPECS } from '../registries/index.js';
|
|
6
|
+
import { PROVIDERS } from '../installer/providers.js';
|
|
7
|
+
import { sha256, writeJson } from '../shared/io.js';
|
|
8
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
9
|
+
|
|
10
|
+
const SOURCE_PROJECTIONS = [
|
|
11
|
+
['package-json', 'package.json'],
|
|
12
|
+
['package-lock', 'package-lock.json'],
|
|
13
|
+
['skill-metadata', 'skill/SKILL.md'],
|
|
14
|
+
['npm-readme', 'README.md'],
|
|
15
|
+
['changelog', 'CHANGELOG.md'],
|
|
16
|
+
['roadmap', 'docs/ROADMAP.md'],
|
|
17
|
+
['controlled-surfaces', 'release/surfaces.json'],
|
|
18
|
+
['distribution-manifest', 'dist/universal/manifest.json'],
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function canonicalJson(value) {
|
|
22
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
|
|
23
|
+
if (value && typeof value === 'object') {
|
|
24
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
|
|
25
|
+
}
|
|
26
|
+
return JSON.stringify(value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function manifestHash(manifest) {
|
|
30
|
+
const { manifest_hash: ignored, ...unsigned } = manifest;
|
|
31
|
+
return sha256(canonicalJson(unsigned));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function projection(id, relativePath, content) {
|
|
35
|
+
const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
36
|
+
return { projection_id: id, path: relativePath, sha256: sha256(buffer), bytes: buffer.length, authority: 'control_plane' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function currentCommit(root) {
|
|
40
|
+
return execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function verifyRepositoryBinding(root, commit) {
|
|
44
|
+
try {
|
|
45
|
+
const head = currentCommit(root);
|
|
46
|
+
const trackedChanges = execFileSync('git', ['status', '--porcelain', '--untracked-files=no'], { cwd: root, encoding: 'utf8' }).trim();
|
|
47
|
+
const failures = [];
|
|
48
|
+
if (head !== commit) failures.push(`manifest commit ${commit} differs from HEAD ${head}`);
|
|
49
|
+
if (trackedChanges) failures.push('tracked working tree is not clean');
|
|
50
|
+
return { ok: failures.length === 0, failures };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return { ok: false, failures: [`repository binding unavailable: ${error.message}`] };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function distributionFileCount(root) {
|
|
57
|
+
const manifestFile = path.join(root, 'dist', 'universal', 'manifest.json');
|
|
58
|
+
if (!fs.existsSync(manifestFile)) return 0;
|
|
59
|
+
const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
|
|
60
|
+
const first = Object.values(manifest.providers || {})[0];
|
|
61
|
+
if (Array.isArray(first)) return first.length;
|
|
62
|
+
if (Array.isArray(first?.files)) return first.files.length;
|
|
63
|
+
if (Number.isInteger(first?.files) && first.files >= 0) return first.files;
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function releaseFacts(root) {
|
|
68
|
+
return {
|
|
69
|
+
detectors: ALL_DETECTORS.length,
|
|
70
|
+
namespaces: Object.keys(detectorsByNamespace()).length,
|
|
71
|
+
registries: REGISTRY_SPECS.length,
|
|
72
|
+
providers: Object.keys(PROVIDERS).length,
|
|
73
|
+
distribution_files_per_provider: distributionFileCount(root),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function resourceProjection(version, facts, commit) {
|
|
78
|
+
return {
|
|
79
|
+
schema_version: 1,
|
|
80
|
+
product: 'Citable',
|
|
81
|
+
version,
|
|
82
|
+
commit,
|
|
83
|
+
facts,
|
|
84
|
+
boundary: 'Citable does not guarantee crawling, indexing, ranking, citation, recommendation, or conversion.',
|
|
85
|
+
canonical_repository: 'https://github.com/mikeholownych/citable',
|
|
86
|
+
npm_package: 'https://www.npmjs.com/package/@nebulacomponents/citable',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function llmsProjection(version, facts, commit) {
|
|
91
|
+
return `# Citable\n\nCitable is the evidence and change-control layer for defensible search and AI citation readiness.\n\n- Version: ${version}\n- Release commit: ${commit}\n- Detectors: ${facts.detectors} across ${facts.namespaces} namespaces\n- Schema-validated registries: ${facts.registries}\n- Agent providers: ${facts.providers}\n- Canonical repository: https://github.com/mikeholownych/citable\n- npm: https://www.npmjs.com/package/@nebulacomponents/citable\n\nCitable does not guarantee crawling, indexing, ranking, citation, recommendation, or conversion.\n`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function generateReleaseManifest(root, { commit = currentCommit(root), generatedAt = new Date().toISOString(), outputDir } = {}) {
|
|
95
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
96
|
+
const version = packageJson.version;
|
|
97
|
+
const facts = releaseFacts(root);
|
|
98
|
+
const generated = {
|
|
99
|
+
'release/resource-data.json': `${JSON.stringify(resourceProjection(version, facts, commit), null, 2)}\n`,
|
|
100
|
+
'release/llms.txt': llmsProjection(version, facts, commit),
|
|
101
|
+
};
|
|
102
|
+
const projections = SOURCE_PROJECTIONS.map(([id, relativePath]) => {
|
|
103
|
+
const file = path.join(root, relativePath);
|
|
104
|
+
if (!fs.existsSync(file)) throw new Error(`required release projection is missing: ${relativePath}`);
|
|
105
|
+
return projection(id, relativePath, fs.readFileSync(file));
|
|
106
|
+
});
|
|
107
|
+
projections.push(projection('resource-data', 'release/resource-data.json', generated['release/resource-data.json']));
|
|
108
|
+
projections.push(projection('llms-txt', 'release/llms.txt', generated['release/llms.txt']));
|
|
109
|
+
const surfaceConfig = JSON.parse(fs.readFileSync(path.join(root, 'release', 'surfaces.json'), 'utf8'));
|
|
110
|
+
const manifest = {
|
|
111
|
+
schema_version: 1,
|
|
112
|
+
release_id: `RELEASE-v${version}`,
|
|
113
|
+
version,
|
|
114
|
+
commit,
|
|
115
|
+
generated_at: generatedAt,
|
|
116
|
+
toolchain: { node: process.version, citable: version },
|
|
117
|
+
facts,
|
|
118
|
+
projections,
|
|
119
|
+
controlled_surfaces: surfaceConfig.controlled_surfaces,
|
|
120
|
+
};
|
|
121
|
+
manifest.manifest_hash = manifestHash(manifest);
|
|
122
|
+
const check = validateAgainst('release-manifest.schema.json', manifest);
|
|
123
|
+
if (!check.valid) throw new Error(`release manifest violates contract: ${check.errors.join('; ')}`);
|
|
124
|
+
if (outputDir) {
|
|
125
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
126
|
+
for (const [relativePath, content] of Object.entries(generated)) {
|
|
127
|
+
const file = path.join(outputDir, path.basename(relativePath));
|
|
128
|
+
fs.writeFileSync(file, content);
|
|
129
|
+
}
|
|
130
|
+
writeJson(path.join(outputDir, 'release-manifest.json'), manifest);
|
|
131
|
+
}
|
|
132
|
+
return { manifest, generated };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function assertedCount(text, pattern, label) {
|
|
136
|
+
const match = pattern.exec(text);
|
|
137
|
+
return match ? { label, value: Number(match[1]) } : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function validateReleaseManifest(root, manifest, generated = {}) {
|
|
141
|
+
const failures = [];
|
|
142
|
+
const check = validateAgainst('release-manifest.schema.json', manifest);
|
|
143
|
+
if (!check.valid) return { ok: false, failures: check.errors };
|
|
144
|
+
if (manifest.manifest_hash !== manifestHash(manifest)) failures.push('manifest hash is inconsistent');
|
|
145
|
+
const actual = generateReleaseManifest(root, { commit: manifest.commit, generatedAt: manifest.generated_at });
|
|
146
|
+
if (canonicalJson(actual.manifest.facts) !== canonicalJson(manifest.facts)) failures.push('release facts differ from executable sources');
|
|
147
|
+
const actualProjections = new Map(actual.manifest.projections.map((item) => [item.projection_id, item]));
|
|
148
|
+
for (const expected of manifest.projections) {
|
|
149
|
+
const observed = actualProjections.get(expected.projection_id);
|
|
150
|
+
if (!observed) failures.push(`${expected.projection_id}: projection is missing`);
|
|
151
|
+
else if (observed.sha256 !== expected.sha256 || observed.bytes !== expected.bytes) failures.push(`${expected.projection_id}: projection checksum differs`);
|
|
152
|
+
}
|
|
153
|
+
for (const [relativePath, content] of Object.entries(actual.generated)) {
|
|
154
|
+
if (generated[relativePath] != null && generated[relativePath] !== content) failures.push(`${relativePath}: generated projection differs`);
|
|
155
|
+
}
|
|
156
|
+
const readme = fs.readFileSync(path.join(root, 'README.md'), 'utf8');
|
|
157
|
+
const roadmap = fs.readFileSync(path.join(root, 'docs', 'ROADMAP.md'), 'utf8');
|
|
158
|
+
const assertions = [
|
|
159
|
+
assertedCount(readme, /\*\*(\d+) detectors\*\*/, 'README detector count'),
|
|
160
|
+
assertedCount(readme, /across (\d+) namespaces/, 'README namespace count'),
|
|
161
|
+
assertedCount(roadmap, /\| Detectors \| (\d+) across/, 'roadmap detector count'),
|
|
162
|
+
assertedCount(roadmap, /\| Registries \| (\d+) schema-validated/, 'roadmap registry count'),
|
|
163
|
+
assertedCount(roadmap, /\| Distribution \| (\d+) packaged files per provider/, 'roadmap distribution count'),
|
|
164
|
+
].filter(Boolean);
|
|
165
|
+
const expected = { 'README detector count': manifest.facts.detectors, 'README namespace count': manifest.facts.namespaces, 'roadmap detector count': manifest.facts.detectors, 'roadmap registry count': manifest.facts.registries, 'roadmap distribution count': manifest.facts.distribution_files_per_provider };
|
|
166
|
+
for (const assertion of assertions) if (assertion.value !== expected[assertion.label]) failures.push(`${assertion.label} is ${assertion.value}; executable source is ${expected[assertion.label]}`);
|
|
167
|
+
return { ok: failures.length === 0, failures };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function verifyManifestIntegrity(manifest) {
|
|
171
|
+
const failures = [];
|
|
172
|
+
const check = validateAgainst('release-manifest.schema.json', manifest);
|
|
173
|
+
if (!check.valid) failures.push(...check.errors);
|
|
174
|
+
if (manifest.manifest_hash !== manifestHash(manifest)) failures.push('manifest hash is inconsistent');
|
|
175
|
+
return { ok: failures.length === 0, failures };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function createDeploymentReceipt(manifest, input) {
|
|
179
|
+
const surface = manifest.controlled_surfaces.find((item) => item.surface_id === input.surface_id);
|
|
180
|
+
if (!surface) throw new Error(`unknown controlled surface: ${input.surface_id}`);
|
|
181
|
+
if (input.url !== surface.url) throw new Error(`receipt URL does not match controlled surface ${surface.surface_id}`);
|
|
182
|
+
const expected = manifest.projections.find((item) => item.projection_id === surface.projection_id);
|
|
183
|
+
if (!expected) throw new Error(`manifest projection is missing for surface ${surface.surface_id}`);
|
|
184
|
+
const collectedAt = input.collected_at || new Date().toISOString();
|
|
185
|
+
const expiresAt = input.expires_at || new Date(new Date(collectedAt).getTime() + 24 * 60 * 60 * 1000).toISOString();
|
|
186
|
+
if (!(new Date(expiresAt) > new Date(collectedAt))) throw new Error('receipt expiry must be after collection');
|
|
187
|
+
const observedProjectionHash = surface.verification_method === 'exact_response_body'
|
|
188
|
+
? input.response_hash
|
|
189
|
+
: input.http.headers?.[surface.verification_header] || null;
|
|
190
|
+
if (input.observed_projection_hash && input.observed_projection_hash !== observedProjectionHash) {
|
|
191
|
+
throw new Error('supplied projection hash conflicts with the manifest-declared verification method');
|
|
192
|
+
}
|
|
193
|
+
let verificationStatus = 'verified';
|
|
194
|
+
if (input.http.status < 200 || input.http.status >= 300) verificationStatus = 'failed';
|
|
195
|
+
else if (!observedProjectionHash) verificationStatus = 'insufficient_evidence';
|
|
196
|
+
else if (observedProjectionHash !== expected.sha256) verificationStatus = 'contradictory';
|
|
197
|
+
const receipt = {
|
|
198
|
+
schema_version: 1,
|
|
199
|
+
receipt_id: `RECEIPT-${sha256(`${manifest.manifest_hash}:${surface.surface_id}:${collectedAt}`).slice(0, 20).toUpperCase()}`,
|
|
200
|
+
release_id: manifest.release_id,
|
|
201
|
+
manifest_hash: manifest.manifest_hash,
|
|
202
|
+
surface_id: surface.surface_id,
|
|
203
|
+
url: surface.url,
|
|
204
|
+
projection_id: expected.projection_id,
|
|
205
|
+
verification_method: surface.verification_method,
|
|
206
|
+
verification_header: surface.verification_header,
|
|
207
|
+
expected_projection_hash: expected.sha256,
|
|
208
|
+
observed_projection_hash: observedProjectionHash,
|
|
209
|
+
response_hash: input.response_hash,
|
|
210
|
+
http: input.http,
|
|
211
|
+
collector: input.collector,
|
|
212
|
+
collected_at: collectedAt,
|
|
213
|
+
expires_at: expiresAt,
|
|
214
|
+
authority: {
|
|
215
|
+
source_authority: 'owner_controlled',
|
|
216
|
+
collection_authority: 'synthetic_probe',
|
|
217
|
+
authenticity_status: 'checksum_protected_only',
|
|
218
|
+
representativeness: 'single_observation',
|
|
219
|
+
limitations: ['Publisher-collected execution evidence; not independent attestation.'],
|
|
220
|
+
},
|
|
221
|
+
verification_status: verificationStatus,
|
|
222
|
+
limitations: [...(input.limitations || []), 'Receipt verifies one publisher-controlled retrieval at one time and region.'],
|
|
223
|
+
};
|
|
224
|
+
receipt.receipt_hash = sha256(canonicalJson(receipt));
|
|
225
|
+
const check = validateAgainst('deployment-receipt.schema.json', receipt);
|
|
226
|
+
if (!check.valid) throw new Error(`deployment receipt violates contract: ${check.errors.join('; ')}`);
|
|
227
|
+
return receipt;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function verifyDeploymentReceipt(manifest, receipt, { at = new Date() } = {}) {
|
|
231
|
+
const failures = [];
|
|
232
|
+
const check = validateAgainst('deployment-receipt.schema.json', receipt);
|
|
233
|
+
if (!check.valid) failures.push(...check.errors);
|
|
234
|
+
const { receipt_hash: ignored, ...unsigned } = receipt;
|
|
235
|
+
if (receipt.receipt_hash !== sha256(canonicalJson(unsigned))) failures.push('receipt hash is inconsistent');
|
|
236
|
+
if (receipt.release_id !== manifest.release_id) failures.push('receipt release differs from manifest');
|
|
237
|
+
if (receipt.manifest_hash !== manifest.manifest_hash) failures.push('receipt manifest hash differs');
|
|
238
|
+
const surface = manifest.controlled_surfaces.find((item) => item.surface_id === receipt.surface_id);
|
|
239
|
+
if (!surface) failures.push('receipt surface is not controlled by the manifest');
|
|
240
|
+
else {
|
|
241
|
+
if (receipt.url !== surface.url) failures.push('receipt URL differs from controlled surface');
|
|
242
|
+
if (receipt.projection_id !== surface.projection_id) failures.push('receipt projection differs from controlled surface');
|
|
243
|
+
if (receipt.verification_method !== surface.verification_method || receipt.verification_header !== surface.verification_header) failures.push('receipt verification method differs from controlled surface');
|
|
244
|
+
}
|
|
245
|
+
const expected = manifest.projections.find((item) => item.projection_id === receipt.projection_id);
|
|
246
|
+
if (!expected || expected.sha256 !== receipt.expected_projection_hash) failures.push('receipt expected projection is inconsistent');
|
|
247
|
+
if (receipt.verification_status !== 'verified') failures.push(`receipt status is ${receipt.verification_status}`);
|
|
248
|
+
if (receipt.authority?.source_authority !== 'owner_controlled' || receipt.authority?.collection_authority !== 'synthetic_probe' || receipt.authority?.representativeness !== 'single_observation') failures.push('receipt authority is not publisher-controlled single-observation execution evidence');
|
|
249
|
+
if (new Date(receipt.expires_at) <= at) failures.push('receipt is expired');
|
|
250
|
+
return { ok: failures.length === 0, failures };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function stateHash(value) {
|
|
254
|
+
const { state_hash: ignored, ...unsigned } = value;
|
|
255
|
+
return sha256(canonicalJson(unsigned));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function assertState(value) {
|
|
259
|
+
const check = validateAgainst('release-state.schema.json', value);
|
|
260
|
+
if (!check.valid) throw new Error(`release state violates contract: ${check.errors.join('; ')}`);
|
|
261
|
+
if (value.state_hash !== stateHash(value)) throw new Error('release state hash is inconsistent');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function initializeReleaseState(manifest, { actor, at = new Date().toISOString(), maxDwellHours = 24, policyVersion = 'ADR-002' }) {
|
|
265
|
+
const integrity = verifyManifestIntegrity(manifest);
|
|
266
|
+
if (!integrity.ok) throw new Error(`cannot initialize state from invalid manifest: ${integrity.failures.join('; ')}`);
|
|
267
|
+
const state = {
|
|
268
|
+
schema_version: 1,
|
|
269
|
+
release_id: manifest.release_id,
|
|
270
|
+
manifest_hash: manifest.manifest_hash,
|
|
271
|
+
state: 'candidate',
|
|
272
|
+
max_dwell_hours: maxDwellHours,
|
|
273
|
+
created_at: at,
|
|
274
|
+
published_at: null,
|
|
275
|
+
finalized_at: null,
|
|
276
|
+
resolved_at: null,
|
|
277
|
+
resolution_reason: null,
|
|
278
|
+
superseding_release_id: null,
|
|
279
|
+
receipt_refs: [],
|
|
280
|
+
transitions: [{ from: null, to: 'candidate', actor, timestamp: at, reason: 'Release candidate created from validated manifest.', policy_version: policyVersion, evidence_refs: [manifest.manifest_hash] }],
|
|
281
|
+
};
|
|
282
|
+
state.state_hash = stateHash(state);
|
|
283
|
+
assertState(state);
|
|
284
|
+
return state;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function releaseDwellStatus(state, at = new Date()) {
|
|
288
|
+
if (state.state !== 'published_unfinalized') return { expired: false, deadline: null };
|
|
289
|
+
const deadline = new Date(new Date(state.published_at).getTime() + state.max_dwell_hours * 60 * 60 * 1000);
|
|
290
|
+
return { expired: at >= deadline, deadline: deadline.toISOString() };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function transitionRelease(state, to, { actor, reason, evidenceRefs = [], receipts = [], manifest, phaseOne, at = new Date().toISOString(), policyVersion = 'ADR-002', supersedingReleaseId = null } = {}) {
|
|
294
|
+
assertState(state);
|
|
295
|
+
if (['finalized', 'superseded', 'withdrawn'].includes(state.state)) throw new Error(`release state ${state.state} is terminal`);
|
|
296
|
+
const allowed = { candidate: ['published_unfinalized'], published_unfinalized: ['finalized', 'superseded', 'withdrawn'] };
|
|
297
|
+
if (!allowed[state.state]?.includes(to)) throw new Error(`invalid release transition: ${state.state} -> ${to}`);
|
|
298
|
+
if (!actor || !reason) throw new Error('release transition requires actor and reason');
|
|
299
|
+
if (state.state === 'candidate' && (!phaseOne?.ok || phaseOne.manifest_hash !== state.manifest_hash)) throw new Error('bound phase-one projection validation is required before publication');
|
|
300
|
+
const next = structuredClone(state);
|
|
301
|
+
if (to === 'published_unfinalized') next.published_at = at;
|
|
302
|
+
if (to === 'finalized') {
|
|
303
|
+
if (releaseDwellStatus(state, new Date(at)).expired) throw new Error('finalization deadline expired; resolve as withdrawn or superseded');
|
|
304
|
+
if (!manifest || manifest.manifest_hash !== state.manifest_hash) throw new Error('finalization requires the bound release manifest');
|
|
305
|
+
const required = manifest.controlled_surfaces.filter((surface) => surface.required_for_finalization);
|
|
306
|
+
const validReceiptIds = [];
|
|
307
|
+
for (const surface of required) {
|
|
308
|
+
const candidates = receipts.filter((receipt) => receipt.surface_id === surface.surface_id);
|
|
309
|
+
if (candidates.length !== 1) throw new Error(`${surface.surface_id}: exactly one required deployment receipt must be supplied`);
|
|
310
|
+
const result = verifyDeploymentReceipt(manifest, candidates[0], { at: new Date(at) });
|
|
311
|
+
if (!result.ok) throw new Error(`${surface.surface_id}: ${result.failures.join('; ')}`);
|
|
312
|
+
validReceiptIds.push(candidates[0].receipt_id);
|
|
313
|
+
}
|
|
314
|
+
next.receipt_refs = validReceiptIds;
|
|
315
|
+
next.finalized_at = at;
|
|
316
|
+
}
|
|
317
|
+
if (to === 'superseded' || to === 'withdrawn') {
|
|
318
|
+
if (!releaseDwellStatus(state, new Date(at)).expired) throw new Error(`${to} requires the published_unfinalized dwell deadline to expire`);
|
|
319
|
+
if (to === 'superseded' && !supersedingReleaseId) throw new Error('superseded resolution requires superseding release id');
|
|
320
|
+
next.resolved_at = at;
|
|
321
|
+
next.resolution_reason = reason;
|
|
322
|
+
next.superseding_release_id = supersedingReleaseId;
|
|
323
|
+
}
|
|
324
|
+
next.state = to;
|
|
325
|
+
next.transitions.push({ from: state.state, to, actor, timestamp: at, reason, policy_version: policyVersion, evidence_refs: [...evidenceRefs, ...next.receipt_refs] });
|
|
326
|
+
next.state_hash = stateHash(next);
|
|
327
|
+
assertState(next);
|
|
328
|
+
return next;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export { canonicalJson, manifestHash };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Strict, reproducible date parsing for temporal commands. */
|
|
2
|
+
export function parseAsOf(args, fallback = new Date()) {
|
|
3
|
+
const i = args.indexOf('--as-of');
|
|
4
|
+
if (i < 0) return fallback;
|
|
5
|
+
const value = args[i + 1];
|
|
6
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value ?? '')) {
|
|
7
|
+
throw new Error(`--as-of must be a valid YYYY-MM-DD date, got: ${value ?? ''}`);
|
|
8
|
+
}
|
|
9
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
10
|
+
if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== value) {
|
|
11
|
+
throw new Error(`--as-of must be a valid YYYY-MM-DD date, got: ${value}`);
|
|
12
|
+
}
|
|
13
|
+
return date;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function dateOnly(date) {
|
|
17
|
+
return date.toISOString().slice(0, 10);
|
|
18
|
+
}
|