evidential-protocol 2.0.0 → 3.0.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.
Files changed (49) hide show
  1. package/dist/attestation.d.ts +80 -0
  2. package/dist/attestation.d.ts.map +1 -0
  3. package/dist/attestation.js +115 -0
  4. package/dist/attestation.js.map +1 -0
  5. package/dist/audit-ledger.d.ts +96 -0
  6. package/dist/audit-ledger.d.ts.map +1 -0
  7. package/dist/audit-ledger.js +152 -0
  8. package/dist/audit-ledger.js.map +1 -0
  9. package/dist/dormant.d.ts +59 -0
  10. package/dist/dormant.d.ts.map +1 -0
  11. package/dist/dormant.js +256 -0
  12. package/dist/dormant.js.map +1 -0
  13. package/dist/ergative.d.ts +75 -0
  14. package/dist/ergative.d.ts.map +1 -0
  15. package/dist/ergative.js +203 -0
  16. package/dist/ergative.js.map +1 -0
  17. package/dist/fingerprint.d.ts +126 -0
  18. package/dist/fingerprint.d.ts.map +1 -0
  19. package/dist/fingerprint.js +315 -0
  20. package/dist/fingerprint.js.map +1 -0
  21. package/dist/index.d.ts +14 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +24 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/provenance.d.ts +101 -0
  26. package/dist/provenance.d.ts.map +1 -0
  27. package/dist/provenance.js +197 -0
  28. package/dist/provenance.js.map +1 -0
  29. package/dist/purity.d.ts +85 -0
  30. package/dist/purity.d.ts.map +1 -0
  31. package/dist/purity.js +124 -0
  32. package/dist/purity.js.map +1 -0
  33. package/dist/resilience.d.ts +63 -0
  34. package/dist/resilience.d.ts.map +1 -0
  35. package/dist/resilience.js +241 -0
  36. package/dist/resilience.js.map +1 -0
  37. package/dist/scoring.d.ts +87 -0
  38. package/dist/scoring.d.ts.map +1 -0
  39. package/dist/scoring.js +202 -0
  40. package/dist/scoring.js.map +1 -0
  41. package/dist/self-describing.d.ts +71 -0
  42. package/dist/self-describing.d.ts.map +1 -0
  43. package/dist/self-describing.js +153 -0
  44. package/dist/self-describing.js.map +1 -0
  45. package/dist/tests/kusunda.test.d.ts +2 -0
  46. package/dist/tests/kusunda.test.d.ts.map +1 -0
  47. package/dist/tests/kusunda.test.js +342 -0
  48. package/dist/tests/kusunda.test.js.map +1 -0
  49. package/package.json +49 -3
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Resilience Module — Bus Factor / SPOF Detection
3
+ *
4
+ * Inspired by the Kusunda last-speaker problem: when knowledge
5
+ * lives in a single person, language death is one heartbeat away.
6
+ * This module identifies single points of failure across any system.
7
+ */
8
+ /** Documentation level numeric mapping for scoring. */
9
+ const DOC_SCORES = {
10
+ none: 0,
11
+ minimal: 0.25,
12
+ adequate: 0.6,
13
+ comprehensive: 1.0,
14
+ };
15
+ /** Criticality numeric mapping for weighting. */
16
+ const CRITICALITY_WEIGHTS = {
17
+ low: 1,
18
+ medium: 2,
19
+ high: 3,
20
+ critical: 4,
21
+ };
22
+ /**
23
+ * Analyzes a collection of system components for single points of failure,
24
+ * documentation gaps, and manual-restart risks.
25
+ */
26
+ export class ResilienceAnalyzer {
27
+ components = new Map();
28
+ /** Register a component for analysis. */
29
+ addComponent(component) {
30
+ this.components.set(component.id, component);
31
+ }
32
+ /** Get the bus factor (number of operators) for a component. */
33
+ getBusFactor(componentId) {
34
+ const component = this.components.get(componentId);
35
+ if (!component)
36
+ return 0;
37
+ return component.operators.length;
38
+ }
39
+ /** Return all components with no documentation. */
40
+ getUndocumented() {
41
+ return [...this.components.values()].filter((c) => c.documentation_level === "none");
42
+ }
43
+ /** Return all components requiring manual restart. */
44
+ getManualRestarts() {
45
+ return [...this.components.values()].filter((c) => c.restart_method === "manual");
46
+ }
47
+ /** Return critical components with only one operator (bus factor = 1). */
48
+ getCriticalSpofs() {
49
+ return [...this.components.values()].filter((c) => c.criticality === "critical" && c.operators.length === 1);
50
+ }
51
+ /** Run the full resilience analysis. */
52
+ analyze() {
53
+ const all = [...this.components.values()];
54
+ const total = all.length;
55
+ if (total === 0) {
56
+ return {
57
+ total_components: 0,
58
+ spof_count: 0,
59
+ at_risk_count: 0,
60
+ healthy_count: 0,
61
+ overall_score: 1,
62
+ spofs: [],
63
+ recommendations: [],
64
+ };
65
+ }
66
+ const spofs = all.filter((c) => c.operators.length === 1);
67
+ const atRisk = all.filter((c) => c.operators.length === 2);
68
+ const healthy = all.filter((c) => c.operators.length > 2);
69
+ const score = this.computeOverallScore(all);
70
+ const recommendations = this.buildRecommendations(all, spofs);
71
+ return {
72
+ total_components: total,
73
+ spof_count: spofs.length,
74
+ at_risk_count: atRisk.length,
75
+ healthy_count: healthy.length,
76
+ overall_score: score,
77
+ spofs,
78
+ recommendations,
79
+ };
80
+ }
81
+ /**
82
+ * Generate a continuity document in Markdown covering every SPOF
83
+ * and concrete remediation steps.
84
+ */
85
+ generateContinuityDoc() {
86
+ const report = this.analyze();
87
+ const lines = [];
88
+ lines.push("# System Continuity Document");
89
+ lines.push("");
90
+ lines.push(`Generated: ${new Date().toISOString()}`);
91
+ lines.push("");
92
+ lines.push("## Summary");
93
+ lines.push("");
94
+ lines.push(`| Metric | Value |`);
95
+ lines.push(`|--------|-------|`);
96
+ lines.push(`| Total Components | ${report.total_components} |`);
97
+ lines.push(`| SPOFs (bus factor = 1) | ${report.spof_count} |`);
98
+ lines.push(`| At Risk (bus factor <= 2) | ${report.at_risk_count} |`);
99
+ lines.push(`| Healthy (bus factor > 2) | ${report.healthy_count} |`);
100
+ lines.push(`| Overall Score | ${(report.overall_score * 100).toFixed(1)}% |`);
101
+ lines.push("");
102
+ if (report.spofs.length > 0) {
103
+ lines.push("## Single Points of Failure");
104
+ lines.push("");
105
+ for (const spof of report.spofs) {
106
+ lines.push(`### ${spof.name}`);
107
+ lines.push("");
108
+ lines.push(`- **ID:** ${spof.id}`);
109
+ lines.push(`- **Category:** ${spof.category}`);
110
+ lines.push(`- **Criticality:** ${spof.criticality}`);
111
+ lines.push(`- **Sole Operator:** ${spof.operators[0] ?? "unknown"}`);
112
+ lines.push(`- **Documentation:** ${spof.documentation_level}`);
113
+ lines.push(`- **Restart Method:** ${spof.restart_method ?? "unknown"}`);
114
+ if (spof.last_verified) {
115
+ lines.push(`- **Last Verified:** ${spof.last_verified}`);
116
+ }
117
+ lines.push("");
118
+ lines.push("**Remediation:**");
119
+ lines.push("");
120
+ lines.push(this.remediationFor(spof));
121
+ lines.push("");
122
+ }
123
+ }
124
+ const undocumented = this.getUndocumented();
125
+ if (undocumented.length > 0) {
126
+ lines.push("## Undocumented Components");
127
+ lines.push("");
128
+ for (const c of undocumented) {
129
+ lines.push(`- **${c.name}** (${c.id}) — ${c.category}, criticality: ${c.criticality}`);
130
+ }
131
+ lines.push("");
132
+ }
133
+ const manualRestarts = this.getManualRestarts();
134
+ if (manualRestarts.length > 0) {
135
+ lines.push("## Manual Restart Required");
136
+ lines.push("");
137
+ for (const c of manualRestarts) {
138
+ lines.push(`- **${c.name}** (${c.id}) — operators: ${c.operators.join(", ")}`);
139
+ }
140
+ lines.push("");
141
+ }
142
+ if (report.recommendations.length > 0) {
143
+ lines.push("## Recommendations");
144
+ lines.push("");
145
+ for (const rec of report.recommendations) {
146
+ lines.push(`- ${rec}`);
147
+ }
148
+ lines.push("");
149
+ }
150
+ return lines.join("\n");
151
+ }
152
+ /**
153
+ * Compute an overall resilience score from 0 (fragile) to 1 (robust).
154
+ * Weights each component by criticality, penalizes low bus factor
155
+ * and poor documentation.
156
+ */
157
+ computeOverallScore(components) {
158
+ if (components.length === 0)
159
+ return 1;
160
+ let totalWeight = 0;
161
+ let weightedScore = 0;
162
+ for (const c of components) {
163
+ const weight = CRITICALITY_WEIGHTS[c.criticality];
164
+ totalWeight += weight;
165
+ // Bus factor score: 0 ops = 0, 1 = 0.2, 2 = 0.6, 3+ = 1.0
166
+ const ops = c.operators.length;
167
+ const busScore = ops === 0 ? 0 : ops === 1 ? 0.2 : ops === 2 ? 0.6 : 1.0;
168
+ // Documentation score
169
+ const docScore = DOC_SCORES[c.documentation_level];
170
+ // Restart automation score
171
+ const restartScore = c.restart_method === "automatic" ? 1.0 :
172
+ c.restart_method === "manual" ? 0.3 :
173
+ 0.1;
174
+ // Component resilience is weighted average of factors
175
+ const componentScore = busScore * 0.5 + docScore * 0.3 + restartScore * 0.2;
176
+ weightedScore += componentScore * weight;
177
+ }
178
+ return Math.round((weightedScore / totalWeight) * 1000) / 1000;
179
+ }
180
+ /** Build actionable recommendations from the analysis. */
181
+ buildRecommendations(all, spofs) {
182
+ const recs = [];
183
+ const criticalSpofs = spofs.filter((c) => c.criticality === "critical");
184
+ if (criticalSpofs.length > 0) {
185
+ recs.push(`URGENT: ${criticalSpofs.length} critical component(s) have bus factor of 1. ` +
186
+ `Cross-train immediately: ${criticalSpofs.map((c) => c.name).join(", ")}.`);
187
+ }
188
+ const highSpofs = spofs.filter((c) => c.criticality === "high");
189
+ if (highSpofs.length > 0) {
190
+ recs.push(`HIGH: ${highSpofs.length} high-criticality SPOF(s) need additional operators: ` +
191
+ `${highSpofs.map((c) => c.name).join(", ")}.`);
192
+ }
193
+ const undocumented = all.filter((c) => c.documentation_level === "none");
194
+ if (undocumented.length > 0) {
195
+ recs.push(`Document ${undocumented.length} component(s) with no documentation: ` +
196
+ `${undocumented.map((c) => c.name).join(", ")}.`);
197
+ }
198
+ const manualCritical = all.filter((c) => c.restart_method === "manual" && (c.criticality === "critical" || c.criticality === "high"));
199
+ if (manualCritical.length > 0) {
200
+ recs.push(`Automate restart for ${manualCritical.length} high/critical component(s) ` +
201
+ `still requiring manual intervention: ${manualCritical.map((c) => c.name).join(", ")}.`);
202
+ }
203
+ const unknownRestart = all.filter((c) => c.restart_method === "unknown");
204
+ if (unknownRestart.length > 0) {
205
+ recs.push(`Determine restart method for ${unknownRestart.length} component(s) with unknown procedures: ` +
206
+ `${unknownRestart.map((c) => c.name).join(", ")}.`);
207
+ }
208
+ const stale = all.filter((c) => {
209
+ if (!c.last_verified)
210
+ return true;
211
+ const verified = new Date(c.last_verified).getTime();
212
+ const ninetyDays = 90 * 24 * 60 * 60 * 1000;
213
+ return Date.now() - verified > ninetyDays;
214
+ });
215
+ if (stale.length > 0) {
216
+ recs.push(`Verify ${stale.length} component(s) not checked in 90+ days or never verified.`);
217
+ }
218
+ return recs;
219
+ }
220
+ /** Generate remediation advice for a single SPOF. */
221
+ remediationFor(component) {
222
+ const steps = [];
223
+ const operator = component.operators[0] ?? "the sole operator";
224
+ steps.push(`1. Cross-train at least one additional person on ${component.name}.`);
225
+ if (component.documentation_level === "none" || component.documentation_level === "minimal") {
226
+ steps.push(`2. Create comprehensive documentation. Current level: ${component.documentation_level}.`);
227
+ }
228
+ if (component.restart_method === "manual" || component.restart_method === "unknown") {
229
+ steps.push(`3. Automate the restart procedure (currently: ${component.restart_method ?? "unknown"}).`);
230
+ }
231
+ if (component.category === "credential") {
232
+ steps.push(`4. Store credentials in a shared vault accessible to the team, not just ${operator}.`);
233
+ }
234
+ if (component.category === "knowledge") {
235
+ steps.push(`4. Record a knowledge transfer session with ${operator}. ` +
236
+ `This is the most fragile SPOF type — undocumented knowledge disappears instantly.`);
237
+ }
238
+ return steps.join("\n");
239
+ }
240
+ }
241
+ //# sourceMappingURL=resilience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.js","sourceRoot":"","sources":["../src/resilience.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Continuous Scoring / Bias-Free Classification — Kusunda No-Gender
3
+ *
4
+ * Kusunda has no grammatical gender — it doesn't force nouns into
5
+ * arbitrary masculine/feminine buckets. This module follows the same
6
+ * philosophy: no forced binary categories. Everything is a spectrum,
7
+ * scored across continuous multi-axis dimensions.
8
+ */
9
+ import type { EvidenceClass } from "./types.js";
10
+ /** A single scoring dimension with weight and value. */
11
+ export interface ScoringAxis {
12
+ name: string;
13
+ weight: number;
14
+ value: number;
15
+ evidence_class?: EvidenceClass;
16
+ source?: string;
17
+ }
18
+ /** A multi-axis continuous score for an entity. */
19
+ export interface ContinuousScore {
20
+ entity_id: string;
21
+ axes: ScoringAxis[];
22
+ composite_score: number;
23
+ confidence: number;
24
+ assessed_at: string;
25
+ }
26
+ /** Axis-by-axis comparison between two scored entities. */
27
+ export interface AxisComparison {
28
+ axis: string;
29
+ entity_a_value: number;
30
+ entity_b_value: number;
31
+ delta: number;
32
+ }
33
+ /** Result of comparing two entities. */
34
+ export interface ComparisonResult {
35
+ entity_a: string;
36
+ entity_b: string;
37
+ comparisons: AxisComparison[];
38
+ composite_delta: number;
39
+ }
40
+ /** A cluster of similar entities. */
41
+ export interface Cluster {
42
+ centroid: number;
43
+ members: ContinuousScore[];
44
+ }
45
+ /**
46
+ * Scores entities across user-defined continuous axes.
47
+ * No forced categories — only weighted spectra.
48
+ */
49
+ export declare class ScoringEngine {
50
+ private axisDefinitions;
51
+ private scores;
52
+ /** Define the scoring axes. Weights are normalized internally. */
53
+ defineAxes(axes: Array<{
54
+ name: string;
55
+ weight: number;
56
+ }>): void;
57
+ /**
58
+ * Score an entity across the defined axes.
59
+ * Values should be keyed by axis name, each in range 0-1.
60
+ */
61
+ score(entityId: string, values: Record<string, number>): ContinuousScore;
62
+ /** Compare two previously scored entities axis by axis. */
63
+ compare(entityA: string, entityB: string): ComparisonResult;
64
+ /** Rank entities by composite score, highest first. */
65
+ rank(entities: ContinuousScore[]): ContinuousScore[];
66
+ /**
67
+ * Simple k-means clustering by composite score.
68
+ * Groups entities into k clusters based on score similarity.
69
+ */
70
+ cluster(entities: ContinuousScore[], k: number): Cluster[];
71
+ /**
72
+ * Identify entities whose composite score deviates significantly
73
+ * from the mean. Default threshold: 1.5 standard deviations.
74
+ */
75
+ getOutliers(entities: ContinuousScore[], threshold?: number): ContinuousScore[];
76
+ /**
77
+ * Compute the weighted composite score.
78
+ * Uses normalized weights so they sum to 1.
79
+ */
80
+ private computeComposite;
81
+ /**
82
+ * Estimate confidence based on how many axes have explicit values.
83
+ * Missing axes (defaulting to 0) reduce confidence.
84
+ */
85
+ private computeConfidence;
86
+ }
87
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qCAAqC;AACrC,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,MAAM,CAA2C;IAEzD,kEAAkE;IAClE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAO/D;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,eAAe;IA0BxE,2DAA2D;IAC3D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB;IA0B3D,uDAAuD;IACvD,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE;IAIpD;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE;IAsE1D;;;OAGG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,SAAS,SAAM,GAAG,eAAe,EAAE;IAiB5E;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAqB1B"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Continuous Scoring / Bias-Free Classification — Kusunda No-Gender
3
+ *
4
+ * Kusunda has no grammatical gender — it doesn't force nouns into
5
+ * arbitrary masculine/feminine buckets. This module follows the same
6
+ * philosophy: no forced binary categories. Everything is a spectrum,
7
+ * scored across continuous multi-axis dimensions.
8
+ */
9
+ /**
10
+ * Scores entities across user-defined continuous axes.
11
+ * No forced categories — only weighted spectra.
12
+ */
13
+ export class ScoringEngine {
14
+ axisDefinitions = [];
15
+ scores = new Map();
16
+ /** Define the scoring axes. Weights are normalized internally. */
17
+ defineAxes(axes) {
18
+ this.axisDefinitions = axes.map((a) => ({
19
+ name: a.name,
20
+ weight: clamp(a.weight, 0, 1),
21
+ }));
22
+ }
23
+ /**
24
+ * Score an entity across the defined axes.
25
+ * Values should be keyed by axis name, each in range 0-1.
26
+ */
27
+ score(entityId, values) {
28
+ if (this.axisDefinitions.length === 0) {
29
+ throw new Error("No axes defined. Call defineAxes() first.");
30
+ }
31
+ const axes = this.axisDefinitions.map((def) => ({
32
+ name: def.name,
33
+ weight: def.weight,
34
+ value: clamp(values[def.name] ?? 0, 0, 1),
35
+ }));
36
+ const composite = this.computeComposite(axes);
37
+ const confidence = this.computeConfidence(axes, values);
38
+ const result = {
39
+ entity_id: entityId,
40
+ axes,
41
+ composite_score: round4(composite),
42
+ confidence: round4(confidence),
43
+ assessed_at: new Date().toISOString(),
44
+ };
45
+ this.scores.set(entityId, result);
46
+ return result;
47
+ }
48
+ /** Compare two previously scored entities axis by axis. */
49
+ compare(entityA, entityB) {
50
+ const a = this.scores.get(entityA);
51
+ const b = this.scores.get(entityB);
52
+ if (!a)
53
+ throw new Error(`Entity "${entityA}" has not been scored.`);
54
+ if (!b)
55
+ throw new Error(`Entity "${entityB}" has not been scored.`);
56
+ const comparisons = a.axes.map((axisA) => {
57
+ const axisB = b.axes.find((ab) => ab.name === axisA.name);
58
+ const bVal = axisB?.value ?? 0;
59
+ return {
60
+ axis: axisA.name,
61
+ entity_a_value: axisA.value,
62
+ entity_b_value: bVal,
63
+ delta: round4(axisA.value - bVal),
64
+ };
65
+ });
66
+ return {
67
+ entity_a: entityA,
68
+ entity_b: entityB,
69
+ comparisons,
70
+ composite_delta: round4(a.composite_score - b.composite_score),
71
+ };
72
+ }
73
+ /** Rank entities by composite score, highest first. */
74
+ rank(entities) {
75
+ return [...entities].sort((a, b) => b.composite_score - a.composite_score);
76
+ }
77
+ /**
78
+ * Simple k-means clustering by composite score.
79
+ * Groups entities into k clusters based on score similarity.
80
+ */
81
+ cluster(entities, k) {
82
+ if (entities.length === 0)
83
+ return [];
84
+ if (k <= 0)
85
+ throw new Error("k must be positive.");
86
+ if (k >= entities.length) {
87
+ // Each entity is its own cluster
88
+ return entities.map((e) => ({
89
+ centroid: e.composite_score,
90
+ members: [e],
91
+ }));
92
+ }
93
+ // Initialize centroids evenly spaced
94
+ let centroids = [];
95
+ for (let i = 0; i < k; i++) {
96
+ centroids.push((i + 0.5) / k);
97
+ }
98
+ const maxIterations = 50;
99
+ let assignments = new Array(entities.length).fill(0);
100
+ for (let iter = 0; iter < maxIterations; iter++) {
101
+ // Assign each entity to nearest centroid
102
+ const newAssignments = entities.map((e) => {
103
+ let bestIdx = 0;
104
+ let bestDist = Infinity;
105
+ for (let c = 0; c < centroids.length; c++) {
106
+ const dist = Math.abs(e.composite_score - centroids[c]);
107
+ if (dist < bestDist) {
108
+ bestDist = dist;
109
+ bestIdx = c;
110
+ }
111
+ }
112
+ return bestIdx;
113
+ });
114
+ // Check convergence
115
+ const converged = newAssignments.every((a, i) => a === assignments[i]);
116
+ assignments = newAssignments;
117
+ // Update centroids
118
+ const newCentroids = centroids.map((_, c) => {
119
+ const members = entities.filter((_, i) => assignments[i] === c);
120
+ if (members.length === 0)
121
+ return centroids[c];
122
+ return members.reduce((sum, m) => sum + m.composite_score, 0) / members.length;
123
+ });
124
+ centroids = newCentroids;
125
+ if (converged)
126
+ break;
127
+ }
128
+ // Build cluster results
129
+ const clusterMap = new Map();
130
+ for (let i = 0; i < entities.length; i++) {
131
+ const c = assignments[i];
132
+ if (!clusterMap.has(c))
133
+ clusterMap.set(c, []);
134
+ clusterMap.get(c).push(entities[i]);
135
+ }
136
+ const results = [];
137
+ for (const [c, members] of clusterMap) {
138
+ results.push({
139
+ centroid: round4(centroids[c]),
140
+ members,
141
+ });
142
+ }
143
+ return results.sort((a, b) => b.centroid - a.centroid);
144
+ }
145
+ /**
146
+ * Identify entities whose composite score deviates significantly
147
+ * from the mean. Default threshold: 1.5 standard deviations.
148
+ */
149
+ getOutliers(entities, threshold = 1.5) {
150
+ if (entities.length < 2)
151
+ return [];
152
+ const scores = entities.map((e) => e.composite_score);
153
+ const mean = scores.reduce((a, b) => a + b, 0) / scores.length;
154
+ const variance = scores.reduce((sum, s) => sum + (s - mean) ** 2, 0) / scores.length;
155
+ const stddev = Math.sqrt(variance);
156
+ if (stddev === 0)
157
+ return [];
158
+ return entities.filter((e) => {
159
+ const zScore = Math.abs(e.composite_score - mean) / stddev;
160
+ return zScore > threshold;
161
+ });
162
+ }
163
+ /**
164
+ * Compute the weighted composite score.
165
+ * Uses normalized weights so they sum to 1.
166
+ */
167
+ computeComposite(axes) {
168
+ const totalWeight = axes.reduce((sum, a) => sum + a.weight, 0);
169
+ if (totalWeight === 0)
170
+ return 0;
171
+ return axes.reduce((sum, a) => sum + (a.value * a.weight) / totalWeight, 0);
172
+ }
173
+ /**
174
+ * Estimate confidence based on how many axes have explicit values.
175
+ * Missing axes (defaulting to 0) reduce confidence.
176
+ */
177
+ computeConfidence(axes, providedValues) {
178
+ if (axes.length === 0)
179
+ return 0;
180
+ let provided = 0;
181
+ for (const axis of axes) {
182
+ if (axis.name in providedValues) {
183
+ provided++;
184
+ }
185
+ }
186
+ // Base confidence from coverage
187
+ const coverage = provided / axes.length;
188
+ // Penalize heavily if fewer than half the axes are provided
189
+ if (coverage < 0.5)
190
+ return coverage * 0.6;
191
+ return 0.3 + coverage * 0.7;
192
+ }
193
+ }
194
+ /** Clamp a number between min and max. */
195
+ function clamp(n, min, max) {
196
+ return Math.max(min, Math.min(max, n));
197
+ }
198
+ /** Round to 4 decimal places. */
199
+ function round4(n) {
200
+ return Math.round(n * 10000) / 10000;
201
+ }
202
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Self-Describing Payloads — Kusunda Verb Morphology
3
+ *
4
+ * In Kusunda, verbs carry so much morphological information that
5
+ * a single verb can function as a complete sentence. Every payload
6
+ * in this module carries everything needed to understand it:
7
+ * who produced it, what schema it follows, what permissions it
8
+ * requires, and when it expires.
9
+ */
10
+ import type { EvidenceClass } from "./types.js";
11
+ /** Metadata envelope for a self-describing payload. */
12
+ export interface PayloadMeta {
13
+ producer: string;
14
+ tool: string;
15
+ schema_id: string;
16
+ version: string;
17
+ permissions_required: string[];
18
+ evidence_class: EvidenceClass;
19
+ timestamp: string;
20
+ ttl?: number;
21
+ }
22
+ /** A payload that carries its own context — no external lookup needed. */
23
+ export interface SelfDescribingPayload<T> {
24
+ meta: PayloadMeta;
25
+ data: T;
26
+ description: string;
27
+ validate?: () => boolean;
28
+ }
29
+ /**
30
+ * Fluent builder for constructing self-describing payloads.
31
+ * Enforces that required fields are set before building.
32
+ */
33
+ export declare class PayloadBuilder {
34
+ private producer;
35
+ private tool;
36
+ private schemaId;
37
+ private version;
38
+ private permissions;
39
+ private evidenceClass;
40
+ private desc;
41
+ private ttl;
42
+ constructor(producer: string, tool: string);
43
+ /** Set the schema identifier and version. */
44
+ setSchema(schemaId: string, version: string): PayloadBuilder;
45
+ /** Declare permissions required to consume this payload. */
46
+ setPermissions(perms: string[]): PayloadBuilder;
47
+ /** Set the evidence class for this payload's data. */
48
+ setEvidence(cls: EvidenceClass): PayloadBuilder;
49
+ /** Set a human-readable description of what this payload contains. */
50
+ setDescription(desc: string): PayloadBuilder;
51
+ /** Set the time-to-live in seconds. After expiry the payload is stale. */
52
+ setTtl(seconds: number): PayloadBuilder;
53
+ /**
54
+ * Build the self-describing payload.
55
+ * Attaches a validate function that checks required fields at runtime.
56
+ */
57
+ build<T>(data: T): SelfDescribingPayload<T>;
58
+ }
59
+ /**
60
+ * Check whether a payload has expired based on its TTL.
61
+ * Returns false if no TTL is set (never expires).
62
+ */
63
+ export declare function isExpired(payload: SelfDescribingPayload<unknown>): boolean;
64
+ /** Generate a human-readable summary of a payload. */
65
+ export declare function describe(payload: SelfDescribingPayload<unknown>): string;
66
+ /**
67
+ * Validate that a payload has all required fields populated.
68
+ * Returns true if valid, false if any required field is missing or empty.
69
+ */
70
+ export declare function validate(payload: SelfDescribingPayload<unknown>): boolean;
71
+ //# sourceMappingURL=self-describing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-describing.d.ts","sourceRoot":"","sources":["../src/self-describing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,cAAc,EAAE,aAAa,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,CAAC,CAAC;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,GAAG,CAAqB;gBAEpB,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAK1C,6CAA6C;IAC7C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc;IAM5D,4DAA4D;IAC5D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc;IAK/C,sDAAsD;IACtD,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc;IAK/C,sEAAsE;IACtE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc;IAK5C,0EAA0E;IAC1E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc;IAKvC;;;OAGG;IACH,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC;CAqB5C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,OAAO,CAQ1E;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,MAAM,CA0BxE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,OAAO,CAEzE"}