@euconform/core 1.4.0 → 1.6.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +46 -0
- package/dist/datasets/crows-pairs.d.ts +18 -0
- package/dist/datasets/crows-pairs.d.ts.map +1 -1
- package/dist/datasets/crows-pairs.js +58 -0
- package/dist/evidence/bias-comparison-markdown.d.ts +11 -0
- package/dist/evidence/bias-comparison-markdown.d.ts.map +1 -0
- package/dist/evidence/bias-comparison-markdown.js +120 -0
- package/dist/evidence/bias-comparison.d.ts +133 -0
- package/dist/evidence/bias-comparison.d.ts.map +1 -0
- package/dist/evidence/bias-comparison.js +274 -0
- package/dist/evidence/bias-statistics.d.ts +72 -0
- package/dist/evidence/bias-statistics.d.ts.map +1 -0
- package/dist/evidence/bias-statistics.js +122 -0
- package/dist/evidence/bias-v2-semantics.d.ts +19 -0
- package/dist/evidence/bias-v2-semantics.d.ts.map +1 -0
- package/dist/evidence/bias-v2-semantics.js +133 -0
- package/dist/evidence/browser.d.ts +18 -0
- package/dist/evidence/browser.d.ts.map +1 -0
- package/dist/evidence/browser.js +14 -0
- package/dist/evidence/bundle.d.ts +1 -0
- package/dist/evidence/bundle.d.ts.map +1 -1
- package/dist/evidence/bundle.js +2 -0
- package/dist/evidence/index.d.ts +9 -2
- package/dist/evidence/index.d.ts.map +1 -1
- package/dist/evidence/index.js +5 -1
- package/dist/evidence/output.d.ts.map +1 -1
- package/dist/evidence/output.js +1 -0
- package/dist/evidence/types.d.ts +183 -3
- package/dist/evidence/types.d.ts.map +1 -1
- package/dist/evidence/validate-bias-v2.d.ts +31 -0
- package/dist/evidence/validate-bias-v2.d.ts.map +1 -0
- package/dist/evidence/validate-bias-v2.js +40 -0
- package/dist/evidence/validate.d.ts +29 -2
- package/dist/evidence/validate.d.ts.map +1 -1
- package/dist/evidence/validate.js +96 -11
- package/dist/fairness-metrics.d.ts +15 -11
- package/dist/fairness-metrics.d.ts.map +1 -1
- package/dist/fairness-metrics.js +59 -183
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/inference/browser-inference.d.ts +6 -57
- package/dist/inference/browser-inference.d.ts.map +1 -1
- package/dist/inference/browser-inference.js +6 -219
- package/dist/inference/capability-detection.d.ts +9 -2
- package/dist/inference/capability-detection.d.ts.map +1 -1
- package/dist/inference/capability-detection.js +18 -16
- package/dist/inference/index.d.ts +15 -2
- package/dist/inference/index.d.ts.map +1 -1
- package/dist/inference/index.js +12 -3
- package/dist/inference/inference-factory.d.ts +6 -3
- package/dist/inference/inference-factory.d.ts.map +1 -1
- package/dist/inference/inference-factory.js +7 -26
- package/dist/inference/ollama-client.d.ts +29 -0
- package/dist/inference/ollama-client.d.ts.map +1 -1
- package/dist/inference/ollama-client.js +29 -0
- package/dist/inference/scored-log-prob-types.d.ts +64 -0
- package/dist/inference/scored-log-prob-types.d.ts.map +1 -0
- package/dist/inference/scored-log-prob-types.js +12 -0
- package/dist/inference/sequence-logprob.d.ts +34 -0
- package/dist/inference/sequence-logprob.d.ts.map +1 -0
- package/dist/inference/sequence-logprob.js +87 -0
- package/dist/inference/template-scoring.d.ts +124 -0
- package/dist/inference/template-scoring.d.ts.map +1 -0
- package/dist/inference/template-scoring.js +164 -0
- package/dist/inference/transformers-inference.d.ts +124 -0
- package/dist/inference/transformers-inference.d.ts.map +1 -0
- package/dist/inference/transformers-inference.js +392 -0
- package/dist/legal-checks/bias-metrics.d.ts +5 -7
- package/dist/legal-checks/bias-metrics.d.ts.map +1 -1
- package/dist/legal-checks/bias-metrics.js +8 -101
- package/dist/metrics/crows-pairs-bias.d.ts +17 -9
- package/dist/metrics/crows-pairs-bias.d.ts.map +1 -1
- package/dist/metrics/crows-pairs-bias.js +147 -59
- package/dist/metrics/stereotype-bias.d.ts +13 -5
- package/dist/metrics/stereotype-bias.d.ts.map +1 -1
- package/dist/metrics/stereotype-bias.js +16 -99
- package/dist/sbom/component-mapper.d.ts +26 -0
- package/dist/sbom/component-mapper.d.ts.map +1 -0
- package/dist/sbom/component-mapper.js +83 -0
- package/dist/sbom/cyclonedx-import.d.ts +34 -0
- package/dist/sbom/cyclonedx-import.d.ts.map +1 -0
- package/dist/sbom/cyclonedx-import.js +131 -0
- package/dist/sbom/index.d.ts +6 -0
- package/dist/sbom/index.d.ts.map +1 -0
- package/dist/sbom/index.js +4 -0
- package/dist/sbom/known-packages.d.ts +13 -0
- package/dist/sbom/known-packages.d.ts.map +1 -0
- package/dist/sbom/known-packages.js +129 -0
- package/dist/sbom/purl.d.ts +14 -0
- package/dist/sbom/purl.d.ts.map +1 -0
- package/dist/sbom/purl.js +56 -0
- package/dist/sbom/types.d.ts +39 -0
- package/dist/sbom/types.d.ts.map +1 -0
- package/dist/sbom/types.js +5 -0
- package/dist/scanner/detectors/ai-framework-detector.js +1 -1
- package/dist/scanner/detectors/local-inference-detector.d.ts.map +1 -1
- package/dist/scanner/detectors/local-inference-detector.js +1 -1
- package/dist/scanner/detectors/package-json-detector.d.ts.map +1 -1
- package/dist/scanner/detectors/package-json-detector.js +1 -0
- package/dist/types.d.ts +103 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +1 -0
- package/dist/validation/schema-validator.d.ts +18 -0
- package/dist/validation/schema-validator.d.ts.map +1 -0
- package/dist/validation/schema-validator.js +105 -0
- package/package.json +9 -3
- package/scripts/seed-logprob-fixture.mjs +179 -0
- package/scripts/ts-extensionless-resolve-hook.mjs +26 -0
- package/src/datasets/crows-pairs.ts +74 -0
- package/src/evidence/bias-comparison-markdown.ts +162 -0
- package/src/evidence/bias-comparison.ts +432 -0
- package/src/evidence/bias-statistics.ts +180 -0
- package/src/evidence/bias-v2-semantics.ts +214 -0
- package/src/evidence/browser.ts +35 -0
- package/src/evidence/bundle.ts +2 -0
- package/src/evidence/index.ts +31 -0
- package/src/evidence/output.ts +1 -0
- package/src/evidence/types.ts +213 -3
- package/src/evidence/validate-bias-v2.ts +47 -0
- package/src/evidence/validate.ts +151 -17
- package/src/fairness-metrics.ts +79 -222
- package/src/index.ts +7 -0
- package/src/inference/browser-inference.ts +14 -256
- package/src/inference/capability-detection.ts +32 -18
- package/src/inference/index.ts +33 -5
- package/src/inference/inference-factory.ts +9 -30
- package/src/inference/ollama-client.ts +29 -0
- package/src/inference/scored-log-prob-types.ts +66 -0
- package/src/inference/sequence-logprob.ts +136 -0
- package/src/inference/template-scoring.ts +248 -0
- package/src/inference/transformers-inference.ts +494 -0
- package/src/legal-checks/bias-metrics.ts +20 -118
- package/src/metrics/crows-pairs-bias.ts +180 -83
- package/src/metrics/stereotype-bias.ts +27 -119
- package/src/sbom/component-mapper.ts +107 -0
- package/src/sbom/cyclonedx-import.ts +198 -0
- package/src/sbom/index.ts +12 -0
- package/src/sbom/known-packages.ts +142 -0
- package/src/sbom/purl.ts +66 -0
- package/src/sbom/types.ts +34 -0
- package/src/scanner/detectors/ai-framework-detector.ts +1 -1
- package/src/scanner/detectors/local-inference-detector.ts +2 -1
- package/src/scanner/detectors/package-json-detector.ts +1 -0
- package/src/types.ts +108 -2
- package/src/validation/index.ts +7 -0
- package/src/validation/schema-validator.ts +147 -0
- package/tests/annex-iv-report.test.ts +1 -1
- package/tests/capability-detection.test.ts +57 -0
- package/tests/crows-pairs-bias.test.ts +286 -186
- package/tests/custom-dataset.test.ts +80 -0
- package/tests/evidence/bias-artifact-v2.test.ts +135 -0
- package/tests/evidence/bias-artifact.test.ts +78 -0
- package/tests/evidence/bias-comparison.test.ts +397 -0
- package/tests/evidence/bias-statistics.test.ts +191 -0
- package/tests/evidence/external-observation.test.ts +167 -0
- package/tests/evidence/spec-schemas.test.ts +35 -2
- package/tests/evidence/validate-bias-v2.test.ts +180 -0
- package/tests/fairness-metrics.test.ts +77 -1
- package/tests/fixtures/cyclonedx-minimal.json +13 -0
- package/tests/fixtures/cyclonedx-mixed.json +17 -0
- package/tests/fixtures/cyclonedx-ml-bom.json +25 -0
- package/tests/inference/browser-inference-scoring.test.ts +159 -0
- package/tests/inference/fixtures/logprob-golden.json +69 -0
- package/tests/inference/gemma-template.integration.test.ts +81 -0
- package/tests/inference/logprob-golden.integration.test.ts +128 -0
- package/tests/inference/synthetic-logits.test.ts +188 -0
- package/tests/inference/template-scoring.test.ts +249 -0
- package/tests/inference/transformers-inference-template-mode.test.ts +214 -0
- package/tests/integration/bias-calculation.integration.test.ts +119 -599
- package/tests/sbom/component-mapper.test.ts +258 -0
- package/tests/sbom/cyclonedx-import.test.ts +329 -0
- package/tests/sbom/purl.test.ts +102 -0
- package/tests/stilled-ollama-paths.test.ts +76 -0
- package/tests/validation/schema-validator.test.ts +219 -0
- package/src/inference/transformers.d.ts +0 -62
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import addFormats from "ajv-formats";
|
|
5
|
+
import Ajv2020 from "ajv/dist/2020";
|
|
6
|
+
|
|
7
|
+
export interface ValidationError {
|
|
8
|
+
path: string;
|
|
9
|
+
message: string;
|
|
10
|
+
keyword: string;
|
|
11
|
+
expected?: unknown;
|
|
12
|
+
received?: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SchemaType =
|
|
16
|
+
| "report.v1"
|
|
17
|
+
| "aibom.v1"
|
|
18
|
+
| "aibom.v1.1"
|
|
19
|
+
| "ci.v1"
|
|
20
|
+
| "bundle.v1"
|
|
21
|
+
| "bias.v1"
|
|
22
|
+
| "bias.v2"
|
|
23
|
+
| "external-observation.v1";
|
|
24
|
+
|
|
25
|
+
export interface ValidationResult {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
schemaType: SchemaType;
|
|
28
|
+
errors: ValidationError[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ValidateOptions {
|
|
32
|
+
strict?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Resolve schema directory relative to this file at runtime.
|
|
36
|
+
// When bundled into packages/cli/dist, schemas are copied to dist/schemas/.
|
|
37
|
+
// When running from source at packages/core/src/validation/, schemas are at ../../../../docs/spec/schemas.
|
|
38
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
39
|
+
const __dirname = dirname(__filename);
|
|
40
|
+
const _bundledSchemasDir = resolve(__dirname, "schemas");
|
|
41
|
+
const schemasDir = existsSync(_bundledSchemasDir)
|
|
42
|
+
? _bundledSchemasDir
|
|
43
|
+
: resolve(__dirname, "../../../../docs/spec/schemas");
|
|
44
|
+
|
|
45
|
+
function loadSchema(filename: string): object {
|
|
46
|
+
const content = readFileSync(resolve(schemasDir, filename), "utf-8");
|
|
47
|
+
return JSON.parse(content) as object;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const SCHEMA_MAP: Record<string, { schemaFile: string; type: SchemaType }> = {
|
|
51
|
+
"euconform.report.v1": { schemaFile: "report-v1.schema.json", type: "report.v1" },
|
|
52
|
+
"euconform.aibom.v1": { schemaFile: "aibom-v1.schema.json", type: "aibom.v1" },
|
|
53
|
+
"euconform.aibom.v1.1": { schemaFile: "aibom-v1.1.schema.json", type: "aibom.v1.1" },
|
|
54
|
+
"euconform.ci.v1": { schemaFile: "ci-v1.schema.json", type: "ci.v1" },
|
|
55
|
+
"euconform.bundle.v1": { schemaFile: "bundle-v1.schema.json", type: "bundle.v1" },
|
|
56
|
+
"euconform.bias.v1": { schemaFile: "bias-v1.schema.json", type: "bias.v1" },
|
|
57
|
+
"euconform.bias.v2": { schemaFile: "bias-v2.schema.json", type: "bias.v2" },
|
|
58
|
+
"euconform.external-observation.v1": {
|
|
59
|
+
schemaFile: "external-observation-v1.schema.json",
|
|
60
|
+
type: "external-observation.v1",
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
let ajvInstance: Ajv2020 | null = null;
|
|
65
|
+
|
|
66
|
+
function getAjv(): Ajv2020 {
|
|
67
|
+
if (!ajvInstance) {
|
|
68
|
+
ajvInstance = new Ajv2020({ allErrors: true, strict: false });
|
|
69
|
+
addFormats(ajvInstance);
|
|
70
|
+
}
|
|
71
|
+
return ajvInstance;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function validate(data: unknown, _options?: ValidateOptions): ValidationResult {
|
|
75
|
+
if (typeof data !== "object" || data === null) {
|
|
76
|
+
return {
|
|
77
|
+
valid: false,
|
|
78
|
+
schemaType: "report.v1",
|
|
79
|
+
errors: [
|
|
80
|
+
{
|
|
81
|
+
path: "",
|
|
82
|
+
message: "Input must be a JSON object",
|
|
83
|
+
keyword: "type",
|
|
84
|
+
expected: "object",
|
|
85
|
+
received: typeof data,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const record = data as Record<string, unknown>;
|
|
92
|
+
const schemaVersion = record.schemaVersion;
|
|
93
|
+
|
|
94
|
+
if (typeof schemaVersion !== "string") {
|
|
95
|
+
return {
|
|
96
|
+
valid: false,
|
|
97
|
+
schemaType: "report.v1",
|
|
98
|
+
errors: [
|
|
99
|
+
{
|
|
100
|
+
path: "",
|
|
101
|
+
message: `Missing or invalid schemaVersion field. Expected one of: ${Object.keys(SCHEMA_MAP).join(", ")}`,
|
|
102
|
+
keyword: "required",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const entry = SCHEMA_MAP[schemaVersion];
|
|
109
|
+
if (!entry) {
|
|
110
|
+
return {
|
|
111
|
+
valid: false,
|
|
112
|
+
schemaType: "report.v1",
|
|
113
|
+
errors: [
|
|
114
|
+
{
|
|
115
|
+
path: "/schemaVersion",
|
|
116
|
+
message: `Unknown schemaVersion "${schemaVersion}". Expected one of: ${Object.keys(SCHEMA_MAP).join(", ")}`,
|
|
117
|
+
keyword: "const",
|
|
118
|
+
expected: Object.keys(SCHEMA_MAP),
|
|
119
|
+
received: schemaVersion,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const ajv = getAjv();
|
|
126
|
+
let validateFn = ajv.getSchema(schemaVersion);
|
|
127
|
+
if (!validateFn) {
|
|
128
|
+
const schema = loadSchema(entry.schemaFile);
|
|
129
|
+
validateFn = ajv.compile({ ...schema, $id: schemaVersion });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const valid = validateFn(data) as boolean;
|
|
133
|
+
|
|
134
|
+
if (valid) {
|
|
135
|
+
return { valid: true, schemaType: entry.type, errors: [] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const errors: ValidationError[] = (validateFn.errors ?? []).map((err) => ({
|
|
139
|
+
path: err.instancePath ?? "",
|
|
140
|
+
message: err.message ?? "Validation error",
|
|
141
|
+
keyword: err.keyword ?? "unknown",
|
|
142
|
+
expected: err.params,
|
|
143
|
+
received: undefined,
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
return { valid: false, schemaType: entry.type, errors };
|
|
147
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DefaultCapabilityDetectionService,
|
|
4
|
+
EnhancedCapabilityDetectionService,
|
|
5
|
+
} from "../src/inference/capability-detection";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Browser/transformers.js capability entries are declared from a static model
|
|
9
|
+
* list — no model is actually loaded or tested to produce them. Reporting
|
|
10
|
+
* `status: "available"` with a fresh `lastTested` for that would claim a test
|
|
11
|
+
* ran when it didn't (see Messmotor-Sanierung Task 2). This pins the honest
|
|
12
|
+
* runtime values: `status: "unverified"` and no `lastTested`.
|
|
13
|
+
*/
|
|
14
|
+
describe("capability detection: browser/transformers entries are not overclaimed", () => {
|
|
15
|
+
it("DefaultCapabilityDetectionService.detectModelCapability reports 'unverified', not 'available', for browser", async () => {
|
|
16
|
+
const service = new DefaultCapabilityDetectionService();
|
|
17
|
+
const capability = await service.detectModelCapability("Xenova/distilgpt2", "browser");
|
|
18
|
+
|
|
19
|
+
expect(capability.status).toBe("unverified");
|
|
20
|
+
expect(capability.lastTested).toBeUndefined();
|
|
21
|
+
// The declared method may still be reported (renaming is Task 3's job) —
|
|
22
|
+
// it just must not be dressed up as measured.
|
|
23
|
+
expect(capability.method).toBe("logprobs_exact");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("EnhancedCapabilityDetectionService.detectModelCapability reports 'unverified', not 'available', for browser", async () => {
|
|
27
|
+
const service = new EnhancedCapabilityDetectionService();
|
|
28
|
+
const capability = await service.detectModelCapability("Xenova/distilgpt2", "browser");
|
|
29
|
+
|
|
30
|
+
expect(capability.status).toBe("unverified");
|
|
31
|
+
expect(capability.lastTested).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("'unverified' is not scored as 0 by the recommendation ranking (regression guard)", async () => {
|
|
35
|
+
// Exercise the same code path detectAllCapabilities uses, without touching
|
|
36
|
+
// the network (no live Ollama in CI): detect a single browser capability
|
|
37
|
+
// and confirm it sorts ahead of an explicitly zero-scored "error" entry.
|
|
38
|
+
const service = new DefaultCapabilityDetectionService();
|
|
39
|
+
const browserCapability = await service.detectModelCapability("Xenova/distilgpt2", "browser");
|
|
40
|
+
const errorCapability = {
|
|
41
|
+
modelId: "broken-model",
|
|
42
|
+
engine: "ollama" as const,
|
|
43
|
+
method: "logprobs_fallback_latency" as const,
|
|
44
|
+
status: "error" as const,
|
|
45
|
+
lastTested: new Date().toISOString(),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// sortByRecommendation is protected; reach it through the public
|
|
49
|
+
// detectAllCapabilities-equivalent ordering contract by calling the same
|
|
50
|
+
// scoring indirectly via Array#sort with the class's own comparator is not
|
|
51
|
+
// exposed, so assert the documented invariant directly instead: an
|
|
52
|
+
// "unverified" capability must score above a definitionally-zero one.
|
|
53
|
+
// biome-ignore lint/suspicious/noExplicitAny: reaching a protected method for a focused unit check
|
|
54
|
+
const score = (service as any).getRecommendationScore.bind(service);
|
|
55
|
+
expect(score(browserCapability)).toBeGreaterThan(score(errorCapability));
|
|
56
|
+
});
|
|
57
|
+
});
|