@blamejs/blamejs-shop 0.1.35 → 0.1.37
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 +4 -0
- package/README.md +2 -0
- package/lib/asset-manifest.json +3 -3
- package/lib/currency-display.js +201 -4
- package/lib/storefront.js +612 -80
- package/lib/translations.js +203 -0
- package/lib/vendor/MANIFEST.json +2 -2
- package/lib/vendor/blamejs/CHANGELOG.md +4 -0
- package/lib/vendor/blamejs/README.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +10 -2
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +1 -0
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +180 -0
- package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +196 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.13.5.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.13.6.json +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-aedt-bias-audit.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-frontier-protocol.test.js +83 -0
- package/package.json +1 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.ai.frontierModelProtocol
|
|
4
|
+
* @nav Compliance
|
|
5
|
+
* @title Frontier AI Protocol
|
|
6
|
+
*
|
|
7
|
+
* @intro
|
|
8
|
+
* Assess a developer's obligations under California's Transparency in
|
|
9
|
+
* Frontier Artificial Intelligence Act — SB 53, Cal. Bus. & Prof. Code
|
|
10
|
+
* §22757.10 et seq., signed 2025-09-29 and effective 2026-01-01 — and build
|
|
11
|
+
* the critical-safety-incident report the law requires. SB 53 attaches
|
|
12
|
+
* obligations by two thresholds: a <em>frontier model</em> is one trained
|
|
13
|
+
* with more than 10<sup>26</sup> floating-point operations (including
|
|
14
|
+
* cumulative fine-tuning), and a <em>large frontier developer</em> is a
|
|
15
|
+
* frontier developer whose annual revenue, with affiliates, exceeded
|
|
16
|
+
* $500,000,000 in the prior calendar year. Frontier developers must report
|
|
17
|
+
* critical safety incidents; large frontier developers must additionally
|
|
18
|
+
* publish an annual frontier-AI safety framework.
|
|
19
|
+
*
|
|
20
|
+
* <code>frontierModelProtocol(opts)</code> takes the model's training compute
|
|
21
|
+
* and the developer's revenue and returns which thresholds are crossed and
|
|
22
|
+
* the resulting obligations, optionally checking that a supplied safety
|
|
23
|
+
* framework carries the elements the Act expects (risk identification,
|
|
24
|
+
* mitigation, governance, cybersecurity, and alignment with a recognized
|
|
25
|
+
* standard such as the NIST AI RMF or ISO/IEC 42001).
|
|
26
|
+
* <code>frontierModelProtocol.incidentReport(opts)</code> validates a
|
|
27
|
+
* critical-incident type against the Act's four definitions and computes the
|
|
28
|
+
* notification deadline: a routine report goes to the California Office of
|
|
29
|
+
* Emergency Services within 15 days of discovery; an imminent risk of death
|
|
30
|
+
* or serious physical injury is reported to an applicable authority within 24
|
|
31
|
+
* hours.
|
|
32
|
+
*
|
|
33
|
+
* @card
|
|
34
|
+
* California SB 53 frontier-AI protocol (`b.ai.frontierModelProtocol`) —
|
|
35
|
+
* classify frontier-model / large-developer thresholds (10²⁶ FLOPs, $500M
|
|
36
|
+
* revenue), enumerate obligations, and build the critical-safety-incident
|
|
37
|
+
* report with the 15-day / 24-hour OES notification deadline.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
var C = require("./constants");
|
|
41
|
+
var { defineClass } = require("./framework-error");
|
|
42
|
+
|
|
43
|
+
var FrontierProtocolError = defineClass("FrontierProtocolError", { alwaysPermanent: true });
|
|
44
|
+
|
|
45
|
+
// SB 53 thresholds.
|
|
46
|
+
var FRONTIER_FLOP_THRESHOLD = 1e26; // > 10^26 training FLOPs → frontier model
|
|
47
|
+
var LARGE_DEVELOPER_REVENUE_USD = 5e8; // > $500,000,000 prior-year revenue → large developer
|
|
48
|
+
var INCIDENT_DEADLINE_MS = C.TIME.days(15); // report to CA OES within 15 days of discovery
|
|
49
|
+
var IMMINENT_DEADLINE_MS = C.TIME.hours(24); // within 24 hours if imminent risk to life
|
|
50
|
+
|
|
51
|
+
// The four critical safety incident categories (Cal. Bus. & Prof. Code §22757.10).
|
|
52
|
+
var CRITICAL_INCIDENT_TYPES = {
|
|
53
|
+
"weights-exfiltration-harm": "Unauthorized access, modification, or exfiltration of frontier-model weights resulting in death or bodily injury",
|
|
54
|
+
"catastrophic-risk-materialization": "Harm resulting from the materialization of a catastrophic risk (including loss of life or property from a dangerous capability)",
|
|
55
|
+
"loss-of-control-harm": "Loss of control of a frontier model causing death or bodily injury",
|
|
56
|
+
"deceptive-control-subversion": "A frontier model using deceptive techniques to subvert developer controls, demonstrating materially increased catastrophic risk",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Elements a large frontier developer's published safety framework must address.
|
|
60
|
+
var REQUIRED_FRAMEWORK_ELEMENTS = ["riskIdentification", "riskMitigation", "governance", "cybersecurity", "standardsAlignment"];
|
|
61
|
+
|
|
62
|
+
function _posNum(v, label) {
|
|
63
|
+
if (typeof v !== "number" || !isFinite(v) || v < 0) throw new FrontierProtocolError("frontier/bad-value", "frontierModelProtocol: " + label + " must be a non-negative finite number");
|
|
64
|
+
return v;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @primitive b.ai.frontierModelProtocol
|
|
69
|
+
* @signature b.ai.frontierModelProtocol(opts)
|
|
70
|
+
* @since 0.13.6
|
|
71
|
+
* @status stable
|
|
72
|
+
* @compliance ca-tfaia, soc2
|
|
73
|
+
* @related b.ai.aedtBiasAudit, b.ai.disclosure.applyAll
|
|
74
|
+
*
|
|
75
|
+
* Determine SB 53 obligations from a model's training compute and the
|
|
76
|
+
* developer's revenue. Returns <code>isFrontierModel</code> (training FLOPs
|
|
77
|
+
* above 10<sup>26</sup>), <code>isLargeFrontierDeveloper</code> (a frontier
|
|
78
|
+
* developer with revenue above $500M), and the resulting
|
|
79
|
+
* <code>obligations</code>. When <code>framework</code> is supplied, its
|
|
80
|
+
* required elements are checked and reported in <code>frameworkGaps</code>.
|
|
81
|
+
* Throws <code>FrontierProtocolError</code> on malformed input.
|
|
82
|
+
*
|
|
83
|
+
* @opts
|
|
84
|
+
* trainingFlops: number, // total training FLOPs incl. fine-tuning (required)
|
|
85
|
+
* annualRevenueUsd: number, // developer prior-year revenue with affiliates (default: 0)
|
|
86
|
+
* framework: object, // optional safety framework to check for required elements
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* var p = b.ai.frontierModelProtocol({ trainingFlops: 5e26, annualRevenueUsd: 1e9 });
|
|
90
|
+
* p.isFrontierModel; // → true
|
|
91
|
+
* p.isLargeFrontierDeveloper; // → true
|
|
92
|
+
* p.obligations; // → ["report-critical-safety-incidents", "publish-annual-safety-framework", ...]
|
|
93
|
+
*/
|
|
94
|
+
function frontierModelProtocol(opts) {
|
|
95
|
+
opts = opts || {};
|
|
96
|
+
if (typeof opts !== "object") throw new FrontierProtocolError("frontier/bad-opts", "frontierModelProtocol: opts must be an object");
|
|
97
|
+
var allowed = { trainingFlops: 1, annualRevenueUsd: 1, framework: 1 };
|
|
98
|
+
Object.keys(opts).forEach(function (k) { if (!allowed[k]) throw new FrontierProtocolError("frontier/bad-opts", "frontierModelProtocol: unknown option '" + k + "'"); });
|
|
99
|
+
|
|
100
|
+
var flops = _posNum(opts.trainingFlops, "trainingFlops");
|
|
101
|
+
var revenue = opts.annualRevenueUsd != null ? _posNum(opts.annualRevenueUsd, "annualRevenueUsd") : 0;
|
|
102
|
+
|
|
103
|
+
var isFrontierModel = flops > FRONTIER_FLOP_THRESHOLD;
|
|
104
|
+
var isLargeFrontierDeveloper = isFrontierModel && revenue > LARGE_DEVELOPER_REVENUE_USD;
|
|
105
|
+
|
|
106
|
+
var obligations = [];
|
|
107
|
+
if (isFrontierModel) {
|
|
108
|
+
obligations.push("report-critical-safety-incidents");
|
|
109
|
+
obligations.push("publish-transparency-report");
|
|
110
|
+
}
|
|
111
|
+
if (isLargeFrontierDeveloper) {
|
|
112
|
+
obligations.push("publish-annual-safety-framework");
|
|
113
|
+
obligations.push("disclose-catastrophic-risk-assessment");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
var out = {
|
|
117
|
+
isFrontierModel: isFrontierModel,
|
|
118
|
+
isLargeFrontierDeveloper: isLargeFrontierDeveloper,
|
|
119
|
+
thresholds: { frontierFlops: FRONTIER_FLOP_THRESHOLD, largeDeveloperRevenueUsd: LARGE_DEVELOPER_REVENUE_USD },
|
|
120
|
+
obligations: obligations,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (opts.framework != null) {
|
|
124
|
+
if (typeof opts.framework !== "object") throw new FrontierProtocolError("frontier/bad-value", "frontierModelProtocol: framework must be an object");
|
|
125
|
+
var gaps = REQUIRED_FRAMEWORK_ELEMENTS.filter(function (el) { return !opts.framework[el]; });
|
|
126
|
+
out.frameworkGaps = gaps;
|
|
127
|
+
out.frameworkComplete = gaps.length === 0;
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @primitive b.ai.frontierModelProtocol.incidentReport
|
|
134
|
+
* @signature b.ai.frontierModelProtocol.incidentReport(opts)
|
|
135
|
+
* @since 0.13.6
|
|
136
|
+
* @status stable
|
|
137
|
+
* @compliance ca-tfaia, soc2
|
|
138
|
+
* @related b.ai.frontierModelProtocol, b.ai.aedtBiasAudit
|
|
139
|
+
*
|
|
140
|
+
* Build a critical-safety-incident report and compute its notification
|
|
141
|
+
* deadline to the California Office of Emergency Services. <code>type</code>
|
|
142
|
+
* must be one of the Act's four categories; <code>discoveredAt</code> is when
|
|
143
|
+
* the incident was discovered. The deadline is 15 days from discovery, or 24
|
|
144
|
+
* hours when <code>imminentRiskToLife</code> is set. Returns the structured
|
|
145
|
+
* report with <code>dueAt</code> and <code>deadlineHours</code>. Throws
|
|
146
|
+
* <code>FrontierProtocolError</code> on an unknown type or bad timestamp.
|
|
147
|
+
*
|
|
148
|
+
* @opts
|
|
149
|
+
* type: string, // one of b.ai.frontierModelProtocol.INCIDENT_TYPES (required)
|
|
150
|
+
* discoveredAt: Date, // discovery time (Date or epoch-ms; default: now)
|
|
151
|
+
* imminentRiskToLife: boolean, // true → 24-hour deadline (default: false → 15 days)
|
|
152
|
+
* description: string, // free-text incident description (optional)
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* var r = b.ai.frontierModelProtocol.incidentReport({
|
|
156
|
+
* type: "loss-of-control-harm", discoveredAt: new Date("2026-06-01T00:00:00Z"),
|
|
157
|
+
* });
|
|
158
|
+
* r.deadlineHours; // → 360 (15 days)
|
|
159
|
+
* r.recipient; // → "California Office of Emergency Services"
|
|
160
|
+
*/
|
|
161
|
+
function incidentReport(opts) {
|
|
162
|
+
opts = opts || {};
|
|
163
|
+
if (typeof opts !== "object") throw new FrontierProtocolError("frontier/bad-opts", "incidentReport: opts must be an object");
|
|
164
|
+
if (!CRITICAL_INCIDENT_TYPES[opts.type]) throw new FrontierProtocolError("frontier/bad-incident-type", "incidentReport: type must be one of " + Object.keys(CRITICAL_INCIDENT_TYPES).join(", "));
|
|
165
|
+
|
|
166
|
+
var discoveredMs;
|
|
167
|
+
if (opts.discoveredAt == null) discoveredMs = Date.now();
|
|
168
|
+
else if (opts.discoveredAt instanceof Date) discoveredMs = opts.discoveredAt.getTime();
|
|
169
|
+
else discoveredMs = Number(opts.discoveredAt);
|
|
170
|
+
if (!isFinite(discoveredMs) || discoveredMs < 0) throw new FrontierProtocolError("frontier/bad-value", "incidentReport: discoveredAt must be a Date or non-negative epoch-ms");
|
|
171
|
+
|
|
172
|
+
var imminent = opts.imminentRiskToLife === true;
|
|
173
|
+
var windowMs = imminent ? IMMINENT_DEADLINE_MS : INCIDENT_DEADLINE_MS;
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
type: opts.type,
|
|
177
|
+
typeDescription: CRITICAL_INCIDENT_TYPES[opts.type],
|
|
178
|
+
description: typeof opts.description === "string" ? opts.description : null,
|
|
179
|
+
imminentRiskToLife: imminent,
|
|
180
|
+
discoveredAt: new Date(discoveredMs).toISOString(),
|
|
181
|
+
dueAt: new Date(discoveredMs + windowMs).toISOString(),
|
|
182
|
+
deadlineHours: windowMs / C.TIME.hours(1),
|
|
183
|
+
// §22757.13: the routine report goes to OES within 15 days; an imminent
|
|
184
|
+
// risk of death or serious physical injury is reported to an applicable
|
|
185
|
+
// authority within 24 hours, which the operator selects for the incident.
|
|
186
|
+
recipient: imminent ? "An applicable authority with jurisdiction (e.g. law enforcement or a public-safety agency)" : "California Office of Emergency Services",
|
|
187
|
+
citation: "Cal. Bus. & Prof. Code §22757.13 (SB 53)",
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
frontierModelProtocol.incidentReport = incidentReport;
|
|
192
|
+
frontierModelProtocol.INCIDENT_TYPES = Object.keys(CRITICAL_INCIDENT_TYPES);
|
|
193
|
+
frontierModelProtocol.REQUIRED_FRAMEWORK_ELEMENTS = REQUIRED_FRAMEWORK_ELEMENTS;
|
|
194
|
+
frontierModelProtocol.FrontierProtocolError = FrontierProtocolError;
|
|
195
|
+
|
|
196
|
+
module.exports = frontierModelProtocol;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../scripts/release-notes-schema.json",
|
|
3
|
+
"version": "0.13.5",
|
|
4
|
+
"date": "2026-05-26",
|
|
5
|
+
"headline": "`b.ai.aedtBiasAudit` — NYC Local Law 144 bias audit",
|
|
6
|
+
"summary": "b.ai.aedtBiasAudit computes the bias-audit figures New York City Local Law 144 requires before an Automated Employment Decision Tool may screen candidates (NYC Admin. Code §20-870 et seq.; DCWP rules 6 RCNY §5-300). Given the per-category counts an independent auditor collected — selected/total for a pass-fail tool, or scored-above-the-overall-median/total for a continuous-score tool — it returns the selection (or scoring) rate, the impact ratio (each group's rate divided by the most-selected group's rate), and an adverse-impact flag (impact ratio below the EEOC four-fifths threshold of 0.8) for every group, across the sex, race/ethnicity, and intersectional dimensions, plus the most-selected group per dimension and an overall flag. Categories under 2% of the audited data are marked excluded per DCWP discretion. It is a pure calculation that produces exactly the figures the annual published summary must contain — the law mandates the calculation, not any particular remediation. The relevant compliance postures (nyc-ll144, and ca-tfaia for California SB 53) were already in the catalog.",
|
|
7
|
+
"sections": [
|
|
8
|
+
{
|
|
9
|
+
"heading": "Added",
|
|
10
|
+
"items": [
|
|
11
|
+
{
|
|
12
|
+
"title": "`b.ai.aedtBiasAudit` — Local Law 144 selection/scoring rates and four-fifths impact ratios",
|
|
13
|
+
"body": "`b.ai.aedtBiasAudit({ type, metadata, categories, minCategoryShare? })` where `type` is `\"selection\"` (group entries `{ selected, total }`) or `\"scoring\"` (`{ scoredAboveMedian, total }`). Returns per-group rate, impact ratio, and `adverseImpact` flag across the `sex`, `raceEthnicity`, and `intersectional` dimensions, plus the most-selected group per dimension and an `anyAdverseImpact` summary. Categories below `minCategoryShare` (2% default) are excluded from the impact-ratio basis. Throws `AedtBiasAuditError` on malformed input."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../scripts/release-notes-schema.json",
|
|
3
|
+
"version": "0.13.6",
|
|
4
|
+
"date": "2026-05-26",
|
|
5
|
+
"headline": "`b.ai.frontierModelProtocol` — California SB 53 frontier-AI obligations",
|
|
6
|
+
"summary": "b.ai.frontierModelProtocol assesses a developer's obligations under California's Transparency in Frontier Artificial Intelligence Act — SB 53, Cal. Bus. & Prof. Code §22757.10, effective 2026-01-01 — from a model's training compute and the developer's revenue. It reports whether the model crosses the frontier threshold (more than 10^26 training FLOPs), whether the developer is a large frontier developer (prior-year revenue, with affiliates, above $500M), and the resulting obligations: every frontier developer must report critical safety incidents and publish a transparency report, and a large frontier developer must additionally publish an annual safety framework and disclose its catastrophic-risk assessment. Passing a candidate safety framework reports which required elements (risk identification, mitigation, governance, cybersecurity, standards alignment) are missing. b.ai.frontierModelProtocol.incidentReport validates a critical-incident type against the Act's four categories and computes the notification deadline to the California Office of Emergency Services — 15 days from discovery, or 24 hours when there is an imminent risk of death or serious physical injury. The ca-tfaia compliance posture was already in the catalog.",
|
|
7
|
+
"sections": [
|
|
8
|
+
{
|
|
9
|
+
"heading": "Added",
|
|
10
|
+
"items": [
|
|
11
|
+
{
|
|
12
|
+
"title": "`b.ai.frontierModelProtocol` — SB 53 threshold classification, obligations, and incident reporting",
|
|
13
|
+
"body": "`b.ai.frontierModelProtocol({ trainingFlops, annualRevenueUsd, framework? })` returns `isFrontierModel`, `isLargeFrontierDeveloper`, the `obligations` list, and (when a framework is supplied) its `frameworkGaps`. `b.ai.frontierModelProtocol.incidentReport({ type, discoveredAt, imminentRiskToLife? })` builds a critical-safety-incident report with the California OES recipient and a `dueAt` / `deadlineHours` computed from the 15-day (or 24-hour imminent-risk) statutory window; `type` must be one of the four categories in `INCIDENT_TYPES`. Throws `FrontierProtocolError` on malformed input."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layer 0 — b.ai.aedtBiasAudit (NYC Local Law 144 AEDT bias audit).
|
|
4
|
+
*
|
|
5
|
+
* Oracle: the EEOC four-fifths rule and the DCWP §5-300 impact-ratio formula.
|
|
6
|
+
* The canonical worked example — a tool passing 60% of men and 42% of women —
|
|
7
|
+
* yields an impact ratio of 42/60 = 0.70 for women, below the 0.8 threshold.
|
|
8
|
+
* Boundary, scoring-rate, intersectional, sub-2% exclusion, and the
|
|
9
|
+
* most-selected basis are each asserted against the formula.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
var b = require("../../index");
|
|
13
|
+
var helpers = require("../helpers");
|
|
14
|
+
var check = helpers.check;
|
|
15
|
+
function code(fn) { try { fn(); return "NO-THROW"; } catch (e) { return e.code; } }
|
|
16
|
+
function row(report, dim, cat) { return report.results[dim].filter(function (r) { return r.category === cat; })[0]; }
|
|
17
|
+
|
|
18
|
+
var MD = { tool: "ResumeRanker v3", auditor: "Acme Audit LLC", auditDate: "2026-05-26" };
|
|
19
|
+
|
|
20
|
+
function testSurface() {
|
|
21
|
+
check("b.ai.aedtBiasAudit is a function", typeof b.ai.aedtBiasAudit === "function");
|
|
22
|
+
check("b.ai.aedtBiasAudit.FOUR_FIFTHS is 0.8", b.ai.aedtBiasAudit.FOUR_FIFTHS === 0.8);
|
|
23
|
+
check("b.ai.aedtBiasAudit.AedtBiasAuditError is a class", typeof b.ai.aedtBiasAudit.AedtBiasAuditError === "function");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function testFourFifthsWorkedExample() {
|
|
27
|
+
var r = b.ai.aedtBiasAudit({
|
|
28
|
+
type: "selection",
|
|
29
|
+
metadata: MD,
|
|
30
|
+
categories: { sex: { Male: { selected: 60, total: 100 }, Female: { selected: 42, total: 100 } } },
|
|
31
|
+
});
|
|
32
|
+
var f = row(r, "sex", "Female"), m = row(r, "sex", "Male");
|
|
33
|
+
check("Female selection rate 0.42", f.rate === 0.42);
|
|
34
|
+
check("Female impact ratio 0.70 (42/60)", Math.abs(f.impactRatio - 0.7) < 1e-9);
|
|
35
|
+
check("Female flagged adverse (< 0.8)", f.adverseImpact === true);
|
|
36
|
+
check("Male is the most-selected (ratio 1)", m.impactRatio === 1 && m.adverseImpact === false);
|
|
37
|
+
check("most-selected sex group is Male", r.summary.mostSelected.sex === "Male");
|
|
38
|
+
check("anyAdverseImpact true", r.summary.anyAdverseImpact === true);
|
|
39
|
+
check("adverseImpactGroups names Female", r.summary.adverseImpactGroups.length === 1 && r.summary.adverseImpactGroups[0].category === "Female");
|
|
40
|
+
check("metadata echoed", r.metadata.tool === MD.tool && r.metadata.auditor === MD.auditor && r.metadata.distributionDate === null);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function testFourFifthsBoundary() {
|
|
44
|
+
// Exactly 0.80 is NOT adverse (strictly-less-than threshold); 0.79 is.
|
|
45
|
+
var at = b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { X: { selected: 100, total: 100 }, Y: { selected: 80, total: 100 } } } });
|
|
46
|
+
check("impact ratio exactly 0.80 is not adverse", row(at, "sex", "Y").adverseImpact === false);
|
|
47
|
+
var below = b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { X: { selected: 100, total: 100 }, Y: { selected: 79, total: 100 } } } });
|
|
48
|
+
check("impact ratio 0.79 is adverse", row(below, "sex", "Y").adverseImpact === true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function testScoringRate() {
|
|
52
|
+
// Scoring tools: rate = scored-above-overall-median / total.
|
|
53
|
+
var r = b.ai.aedtBiasAudit({ type: "scoring", metadata: MD, categories: { sex: { M: { scoredAboveMedian: 50, total: 100 }, F: { scoredAboveMedian: 30, total: 100 } } } });
|
|
54
|
+
check("scoring rate F 0.30", row(r, "sex", "F").rate === 0.3);
|
|
55
|
+
check("scoring impact ratio F 0.60 (30/50)", Math.abs(row(r, "sex", "F").impactRatio - 0.6) < 1e-9);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function testIntersectionalAndRace() {
|
|
59
|
+
var r = b.ai.aedtBiasAudit({
|
|
60
|
+
type: "selection",
|
|
61
|
+
metadata: MD,
|
|
62
|
+
categories: {
|
|
63
|
+
raceEthnicity: { "White": { selected: 80, total: 100 }, "Black or African American": { selected: 48, total: 100 } },
|
|
64
|
+
intersectional: { "Male - White": { selected: 90, total: 100 }, "Female - Black or African American": { selected: 45, total: 100 } },
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
check("race dimension computed", row(r, "raceEthnicity", "Black or African American").impactRatio === 0.6);
|
|
68
|
+
check("intersectional dimension computed", row(r, "intersectional", "Female - Black or African American").impactRatio === 0.5);
|
|
69
|
+
check("intersectional adverse flagged", row(r, "intersectional", "Female - Black or African American").adverseImpact === true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function testSubTwoPercentExclusion() {
|
|
73
|
+
var r = b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { Big: { selected: 90, total: 1000 }, Tiny: { selected: 0, total: 10 } } } });
|
|
74
|
+
check("sub-2% category excluded", row(r, "sex", "Tiny").excluded === true);
|
|
75
|
+
check("excluded category has null impact ratio", row(r, "sex", "Tiny").impactRatio === null);
|
|
76
|
+
check("excluded category not flagged adverse", row(r, "sex", "Tiny").adverseImpact === false);
|
|
77
|
+
// A higher minCategoryShare excludes more.
|
|
78
|
+
var r2 = b.ai.aedtBiasAudit({ type: "selection", metadata: MD, minCategoryShare: 0, categories: { sex: { Big: { selected: 90, total: 1000 }, Tiny: { selected: 0, total: 10 } } } });
|
|
79
|
+
check("minCategoryShare 0 includes Tiny", row(r2, "sex", "Tiny").excluded === false);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function testErrors() {
|
|
83
|
+
check("bad type throws", code(function () { b.ai.aedtBiasAudit({ type: "x", metadata: MD, categories: { sex: { M: { selected: 1, total: 1 } } } }); }) === "aedt/bad-type");
|
|
84
|
+
check("missing metadata throws", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: {}, categories: { sex: { M: { selected: 1, total: 1 } } } }); }) === "aedt/bad-metadata");
|
|
85
|
+
check("no categories throws", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: {} }); }) === "aedt/no-categories");
|
|
86
|
+
check("selected > total throws", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { M: { selected: 5, total: 2 } } } }); }) === "aedt/bad-count");
|
|
87
|
+
check("negative count throws", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { M: { selected: -1, total: 2 } } } }); }) === "aedt/bad-count");
|
|
88
|
+
check("bad minCategoryShare throws", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, minCategoryShare: 1, categories: { sex: { M: { selected: 1, total: 1 } } } }); }) === "aedt/bad-share");
|
|
89
|
+
// A typoed/unknown option must surface as AedtBiasAuditError (not a generic
|
|
90
|
+
// Error from validateOpts), so e.code / instanceof handling is reliable.
|
|
91
|
+
check("unknown opt throws aedt/bad-opts", code(function () { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { M: { selected: 1, total: 1 } } }, minCategoryshare: 0.01 }); }) === "aedt/bad-opts");
|
|
92
|
+
var threw = null;
|
|
93
|
+
try { b.ai.aedtBiasAudit({ type: "selection", metadata: MD, categories: { sex: { M: { selected: 1, total: 1 } } }, bogus: 1 }); } catch (e) { threw = e; }
|
|
94
|
+
check("unknown opt error is an AedtBiasAuditError", threw instanceof b.ai.aedtBiasAudit.AedtBiasAuditError);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function run() {
|
|
98
|
+
testSurface();
|
|
99
|
+
testFourFifthsWorkedExample();
|
|
100
|
+
testFourFifthsBoundary();
|
|
101
|
+
testScoringRate();
|
|
102
|
+
testIntersectionalAndRace();
|
|
103
|
+
testSubTwoPercentExclusion();
|
|
104
|
+
testErrors();
|
|
105
|
+
}
|
|
106
|
+
module.exports = { run: run };
|
|
107
|
+
if (require.main === module) { run().then(function () { console.log("[ai-aedt-bias-audit] OK — " + helpers.getChecks() + " checks passed"); }, function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }); }
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layer 0 — b.ai.frontierModelProtocol (California SB 53, Transparency in
|
|
4
|
+
* Frontier AI Act).
|
|
5
|
+
*
|
|
6
|
+
* Oracle: the statute's thresholds and deadlines (Cal. Bus. & Prof. Code
|
|
7
|
+
* §22757.10) — a frontier model exceeds 10^26 training FLOPs, a large frontier
|
|
8
|
+
* developer exceeds $500M revenue, and a critical-incident report is due to the
|
|
9
|
+
* CA OES within 15 days of discovery (24 hours when there is imminent risk to
|
|
10
|
+
* life). The four incident categories are enumerated.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
var b = require("../../index");
|
|
14
|
+
var helpers = require("../helpers");
|
|
15
|
+
var check = helpers.check;
|
|
16
|
+
function code(fn) { try { fn(); return "NO-THROW"; } catch (e) { return e.code; } }
|
|
17
|
+
var fp = b.ai.frontierModelProtocol;
|
|
18
|
+
|
|
19
|
+
function testSurface() {
|
|
20
|
+
check("b.ai.frontierModelProtocol is a function", typeof fp === "function");
|
|
21
|
+
check("incidentReport is a function", typeof fp.incidentReport === "function");
|
|
22
|
+
check("INCIDENT_TYPES has the four categories", fp.INCIDENT_TYPES.length === 4);
|
|
23
|
+
check("REQUIRED_FRAMEWORK_ELEMENTS present", fp.REQUIRED_FRAMEWORK_ELEMENTS.length === 5);
|
|
24
|
+
check("FrontierProtocolError is a class", typeof fp.FrontierProtocolError === "function");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function testThresholds() {
|
|
28
|
+
var big = fp({ trainingFlops: 5e26, annualRevenueUsd: 1e9 });
|
|
29
|
+
check("above 10^26 FLOPs is a frontier model", big.isFrontierModel === true);
|
|
30
|
+
check("frontier + >$500M is a large frontier developer", big.isLargeFrontierDeveloper === true);
|
|
31
|
+
check("large developer gets all four obligations", big.obligations.length === 4 && big.obligations.indexOf("publish-annual-safety-framework") !== -1);
|
|
32
|
+
|
|
33
|
+
check("below 10^26 FLOPs is not a frontier model", fp({ trainingFlops: 1e25, annualRevenueUsd: 1e9 }).isFrontierModel === false);
|
|
34
|
+
check("exactly 10^26 FLOPs is not a frontier model (strict >)", fp({ trainingFlops: 1e26 }).isFrontierModel === false);
|
|
35
|
+
|
|
36
|
+
var smallCo = fp({ trainingFlops: 5e26, annualRevenueUsd: 1e8 });
|
|
37
|
+
check("frontier model at a small developer: frontier yes, large no", smallCo.isFrontierModel === true && smallCo.isLargeFrontierDeveloper === false);
|
|
38
|
+
check("small developer gets only the frontier obligations", smallCo.obligations.length === 2 && smallCo.obligations.indexOf("report-critical-safety-incidents") !== -1);
|
|
39
|
+
check("revenue defaults to 0 when omitted", fp({ trainingFlops: 5e26 }).isLargeFrontierDeveloper === false);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function testFrameworkCheck() {
|
|
43
|
+
var gaps = fp({ trainingFlops: 5e26, annualRevenueUsd: 1e9, framework: { riskIdentification: 1, governance: 1 } });
|
|
44
|
+
check("framework gaps detected", JSON.stringify(gaps.frameworkGaps) === JSON.stringify(["riskMitigation", "cybersecurity", "standardsAlignment"]));
|
|
45
|
+
check("frameworkComplete false with gaps", gaps.frameworkComplete === false);
|
|
46
|
+
var complete = fp({ trainingFlops: 5e26, annualRevenueUsd: 1e9, framework: { riskIdentification: 1, riskMitigation: 1, governance: 1, cybersecurity: 1, standardsAlignment: 1 } });
|
|
47
|
+
check("frameworkComplete true when all elements present", complete.frameworkComplete === true && complete.frameworkGaps.length === 0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function testIncidentReport() {
|
|
51
|
+
var r15 = fp.incidentReport({ type: "loss-of-control-harm", discoveredAt: new Date("2026-06-01T00:00:00Z") });
|
|
52
|
+
check("default deadline is 15 days (360h)", r15.deadlineHours === 360);
|
|
53
|
+
check("15-day dueAt computed", r15.dueAt === "2026-06-16T00:00:00.000Z");
|
|
54
|
+
check("routine report goes to CA OES", r15.recipient.indexOf("Office of Emergency Services") !== -1);
|
|
55
|
+
check("type description carried", r15.typeDescription.indexOf("Loss of control") !== -1);
|
|
56
|
+
|
|
57
|
+
var r24 = fp.incidentReport({ type: "weights-exfiltration-harm", discoveredAt: new Date("2026-06-01T00:00:00Z"), imminentRiskToLife: true });
|
|
58
|
+
check("imminent-risk deadline is 24 hours", r24.deadlineHours === 24);
|
|
59
|
+
check("24-hour dueAt computed", r24.dueAt === "2026-06-02T00:00:00.000Z");
|
|
60
|
+
// §22757.13: imminent risk routes to an applicable authority, not OES.
|
|
61
|
+
check("imminent-risk routes to an applicable authority, not OES", r24.recipient.indexOf("Office of Emergency Services") === -1 && r24.recipient.indexOf("applicable authority") !== -1);
|
|
62
|
+
// §22757.10(i): the weights category is death/bodily-injury only — no property.
|
|
63
|
+
check("weights-incident description excludes property", r24.typeDescription.toLowerCase().indexOf("property") === -1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function testErrors() {
|
|
67
|
+
check("unknown incident type throws", code(function () { fp.incidentReport({ type: "made-up" }); }) === "frontier/bad-incident-type");
|
|
68
|
+
check("bad discoveredAt throws", code(function () { fp.incidentReport({ type: "loss-of-control-harm", discoveredAt: -5 }); }) === "frontier/bad-value");
|
|
69
|
+
check("missing trainingFlops throws", code(function () { fp({}); }) === "frontier/bad-value");
|
|
70
|
+
check("negative trainingFlops throws", code(function () { fp({ trainingFlops: -1 }); }) === "frontier/bad-value");
|
|
71
|
+
check("unknown opt throws", code(function () { fp({ trainingFlops: 1e26, bogus: 1 }); }) === "frontier/bad-opts");
|
|
72
|
+
check("non-object framework throws", code(function () { fp({ trainingFlops: 5e26, framework: 7 }); }) === "frontier/bad-value");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function run() {
|
|
76
|
+
testSurface();
|
|
77
|
+
testThresholds();
|
|
78
|
+
testFrameworkCheck();
|
|
79
|
+
testIncidentReport();
|
|
80
|
+
testErrors();
|
|
81
|
+
}
|
|
82
|
+
module.exports = { run: run };
|
|
83
|
+
if (require.main === module) { run().then(function () { console.log("[ai-frontier-protocol] OK — " + helpers.getChecks() + " checks passed"); }, function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }); }
|
package/package.json
CHANGED