@zanii/decisions 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -43,6 +43,8 @@ ruleConsistency(payloads); // rulebook windows + the interleaving red flag
43
43
  Reference kinds: `dispatch`, `rank`, `payout` — any string works.
44
44
 
45
45
  ## Changelog
46
+
47
+ - **0.1.3** — `adverseActionNotice` (principal reasons), `disparityReport` (selection rates and impact ratios; groups stay off the ledger), human-review requests with `reviewStatus`, `payBreakdown` that must add up, `appealPack`, `counterfactuals`, rule-change notices with `noticeCompliance`, `collectiveAudit`, and `creditDecision` / `tenantScreeningDecision` with notices when declined. Metrics flag where to look; they do not rule on fairness.
46
48
  - **0.1.2** — now depends on `@zanii/core` 0.5 (protocol 1.2), so it shares one core with `@zanii/sdk` 0.5 instead of pulling in a second, older copy. No API change.
47
49
  - **0.1.0** — initial release: `buildDecisionReceipt`, `verifyDecision`, `ruleConsistency`.
48
50
 
@@ -0,0 +1,176 @@
1
+ import { type DecisionInput } from './index.js';
2
+ type Payload = Record<string, unknown>;
3
+ /** An adverse-action notice: the decision, its rulebook and the principal reasons (at most four, most important first). */
4
+ export declare function adverseActionNotice(decision: Payload, input: {
5
+ reasons: string[];
6
+ decidedBy: string;
7
+ rights: string;
8
+ }): {
9
+ decision: string;
10
+ kind: unknown;
11
+ rulebook: unknown;
12
+ decided_by: string;
13
+ principal_reasons: string[];
14
+ rights: string;
15
+ ts: unknown;
16
+ };
17
+ /**
18
+ * Selection rate per group and the impact ratio against the most-selected group. Groups
19
+ * are supplied by the auditor (they never go on the ledger). A ratio under 0.8 is flagged,
20
+ * the threshold bias audits commonly use.
21
+ */
22
+ export declare function disparityReport(outcomes: Array<{
23
+ group: string;
24
+ selected: boolean;
25
+ }>, threshold?: number): {
26
+ impactRatio: number | null;
27
+ flagged: boolean;
28
+ group: string;
29
+ n: number;
30
+ rate: number;
31
+ }[];
32
+ /** A person asks for a human to review an automated decision. */
33
+ export declare function humanReviewRequest(input: {
34
+ decision: string;
35
+ subjectTag: string;
36
+ reason: string;
37
+ ts: string;
38
+ slaDays: number;
39
+ }): {
40
+ target: string;
41
+ subjectTag: string;
42
+ payload: {
43
+ _zr_kind: string;
44
+ v: number;
45
+ decision: string;
46
+ reason: string;
47
+ ts: string;
48
+ due: string;
49
+ };
50
+ };
51
+ /** Which review requests are answered, pending or overdue. */
52
+ export declare function reviewStatus(requests: Payload[], resolutions: Array<{
53
+ decision: string;
54
+ ts: string;
55
+ outcome: 'upheld' | 'changed';
56
+ }>, now: string): {
57
+ decision: unknown;
58
+ status: string;
59
+ outcome: "upheld" | "changed" | null;
60
+ }[];
61
+ /** How a worker's pay for a period was computed, line by line, and whether it adds up to what was paid. Integer minor units. */
62
+ export declare function payBreakdown(lines: Array<{
63
+ task: string;
64
+ base_minor: number;
65
+ adjustments: Array<{
66
+ reason: string;
67
+ amount_minor: number;
68
+ }>;
69
+ }>, paid_minor: number): {
70
+ items: {
71
+ task: string;
72
+ base_minor: number;
73
+ adjustments: {
74
+ reason: string;
75
+ amount_minor: number;
76
+ }[];
77
+ total_minor: number;
78
+ }[];
79
+ computed_minor: number;
80
+ paid_minor: number;
81
+ matches: boolean;
82
+ difference_minor: number;
83
+ };
84
+ /** Everything a worker needs to contest a deactivation or a sanction. */
85
+ export declare function appealPack(decision: Payload, statement: string, factors?: {
86
+ nonce: string;
87
+ disclosed?: Record<string, unknown>;
88
+ }): {
89
+ decision: string;
90
+ kind: unknown;
91
+ outcome: unknown;
92
+ rulebook: unknown;
93
+ ts: unknown;
94
+ factors_commitment: {} | null;
95
+ factors: Record<string, unknown> | null;
96
+ factors_nonce: string | null;
97
+ statement: string;
98
+ };
99
+ /**
100
+ * Which single-factor changes would have flipped the outcome, using the (committed) model
101
+ * you supply. Each candidate value is tried on its own.
102
+ */
103
+ export declare function counterfactuals<F extends Record<string, unknown>>(model: (factors: F) => boolean, factors: F, candidates: Partial<Record<keyof F, unknown[]>>): {
104
+ outcome: boolean;
105
+ flips: {
106
+ factor: keyof F;
107
+ from: unknown;
108
+ to: unknown;
109
+ }[];
110
+ };
111
+ /** Advance notice that a rulebook will change. */
112
+ export declare function ruleChangeNotice(input: {
113
+ from: string;
114
+ to: string;
115
+ effectiveFrom: string;
116
+ summary: string;
117
+ ts: string;
118
+ }): {
119
+ target: string;
120
+ payload: {
121
+ from: string;
122
+ to: string;
123
+ effectiveFrom: string;
124
+ summary: string;
125
+ ts: string;
126
+ _zr_kind: string;
127
+ v: number;
128
+ };
129
+ };
130
+ /** Did the platform give at least `minDays` notice, and did the new rulebook only appear after it took effect? */
131
+ export declare function noticeCompliance(notice: Payload, decisions: Payload[], minDays: number): {
132
+ ok: boolean;
133
+ noticeDays: number;
134
+ usedEarly: number;
135
+ };
136
+ /** A union or advocate pools members' decision records: rule consistency plus outcomes per kind. */
137
+ export declare function collectiveAudit(memberDecisions: Payload[][]): {
138
+ members: number;
139
+ decisions: number;
140
+ consistency: import("./index.js").ConsistencyReport;
141
+ byKind: Record<string, number>;
142
+ };
143
+ /** A credit decision: rulebook, committed factors and principal reasons. */
144
+ export declare function creditDecision(input: Omit<DecisionInput, 'kind'> & {
145
+ approved: boolean;
146
+ reasons?: string[];
147
+ }): {
148
+ receipt: import("./index.js").DecisionReceipt;
149
+ notice: {
150
+ decision: string;
151
+ kind: unknown;
152
+ rulebook: unknown;
153
+ decided_by: string;
154
+ principal_reasons: string[];
155
+ rights: string;
156
+ ts: unknown;
157
+ } | null;
158
+ };
159
+ /** A tenant-screening decision, recorded the same way. */
160
+ export declare function tenantScreeningDecision(input: Omit<DecisionInput, 'kind'> & {
161
+ accepted: boolean;
162
+ reasons?: string[];
163
+ }): {
164
+ receipt: import("./index.js").DecisionReceipt;
165
+ notice: {
166
+ decision: string;
167
+ kind: unknown;
168
+ rulebook: unknown;
169
+ decided_by: string;
170
+ principal_reasons: string[];
171
+ rights: string;
172
+ ts: unknown;
173
+ } | null;
174
+ };
175
+ export {};
176
+ //# sourceMappingURL=fairness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fairness.d.ts","sourceRoot":"","sources":["../src/fairness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * What people and auditors need around algorithmic decisions: adverse-action notices,
3
+ * selection-rate disparity (the impact ratio bias audits use), human-review requests with
4
+ * deadlines, pay breakdowns, appeal packs, counterfactuals, advance notice of rule changes,
5
+ * collective audits, and credit and tenant-screening decisions.
6
+ *
7
+ * Fairness metrics here are arithmetic on outcomes. They flag where to look; they do not
8
+ * decide whether a system is lawful or fair.
9
+ */
10
+ import { jcsHash } from '@zanii/core';
11
+ import { buildDecisionReceipt, ruleConsistency } from './index.js';
12
+ /** An adverse-action notice: the decision, its rulebook and the principal reasons (at most four, most important first). */
13
+ export function adverseActionNotice(decision, input) {
14
+ if (!input.reasons.length)
15
+ throw new Error('decisions: an adverse action needs at least one principal reason');
16
+ return {
17
+ decision: jcsHash(decision), kind: decision.kind, rulebook: decision.manifest_hash, decided_by: input.decidedBy,
18
+ principal_reasons: input.reasons.slice(0, 4), rights: input.rights, ts: decision.ts,
19
+ };
20
+ }
21
+ /**
22
+ * Selection rate per group and the impact ratio against the most-selected group. Groups
23
+ * are supplied by the auditor (they never go on the ledger). A ratio under 0.8 is flagged,
24
+ * the threshold bias audits commonly use.
25
+ */
26
+ export function disparityReport(outcomes, threshold = 0.8) {
27
+ const groups = new Map();
28
+ for (const o of outcomes) {
29
+ const g = groups.get(o.group) ?? { n: 0, selected: 0 };
30
+ g.n++;
31
+ if (o.selected)
32
+ g.selected++;
33
+ groups.set(o.group, g);
34
+ }
35
+ const rates = [...groups].map(([group, g]) => ({ group, n: g.n, rate: g.n ? g.selected / g.n : 0 }));
36
+ const best = Math.max(...rates.map((r) => r.rate), 0);
37
+ return rates.map((r) => ({ ...r, impactRatio: best ? Math.round((r.rate / best) * 1000) / 1000 : null, flagged: best > 0 && r.rate / best < threshold }));
38
+ }
39
+ /** A person asks for a human to review an automated decision. */
40
+ export function humanReviewRequest(input) {
41
+ return { target: 'decision.review.request', subjectTag: input.subjectTag, payload: { _zr_kind: 'decision.review', v: 1, decision: input.decision, reason: input.reason, ts: input.ts, due: new Date(Date.parse(input.ts) + input.slaDays * 86_400_000).toISOString() } };
42
+ }
43
+ /** Which review requests are answered, pending or overdue. */
44
+ export function reviewStatus(requests, resolutions, now) {
45
+ return requests.map((r) => {
46
+ const done = resolutions.find((x) => x.decision === r.decision && x.ts >= String(r.ts));
47
+ return { decision: r.decision, status: done ? (done.ts <= String(r.due) ? 'answered' : 'answered-late') : now > String(r.due) ? 'overdue' : 'pending', outcome: done?.outcome ?? null };
48
+ });
49
+ }
50
+ /** How a worker's pay for a period was computed, line by line, and whether it adds up to what was paid. Integer minor units. */
51
+ export function payBreakdown(lines, paid_minor) {
52
+ const items = lines.map((l) => ({ task: l.task, base_minor: l.base_minor, adjustments: l.adjustments, total_minor: l.base_minor + l.adjustments.reduce((s, a) => s + a.amount_minor, 0) }));
53
+ const computed = items.reduce((s, i) => s + i.total_minor, 0);
54
+ return { items, computed_minor: computed, paid_minor, matches: computed === paid_minor, difference_minor: paid_minor - computed };
55
+ }
56
+ /** Everything a worker needs to contest a deactivation or a sanction. */
57
+ export function appealPack(decision, statement, factors) {
58
+ return {
59
+ decision: jcsHash(decision), kind: decision.kind, outcome: decision.outcome, rulebook: decision.manifest_hash, ts: decision.ts,
60
+ factors_commitment: decision.factors_commitment ?? null, factors: factors?.disclosed ?? null, factors_nonce: factors?.nonce ?? null, statement,
61
+ };
62
+ }
63
+ /**
64
+ * Which single-factor changes would have flipped the outcome, using the (committed) model
65
+ * you supply. Each candidate value is tried on its own.
66
+ */
67
+ export function counterfactuals(model, factors, candidates) {
68
+ const base = model(factors);
69
+ const flips = [];
70
+ for (const [k, values] of Object.entries(candidates)) {
71
+ for (const v of values)
72
+ if (model({ ...factors, [k]: v }) !== base)
73
+ flips.push({ factor: k, from: factors[k], to: v });
74
+ }
75
+ return { outcome: base, flips };
76
+ }
77
+ /** Advance notice that a rulebook will change. */
78
+ export function ruleChangeNotice(input) {
79
+ return { target: 'decision.rulebook.notice', payload: { _zr_kind: 'decision.notice', v: 1, ...input } };
80
+ }
81
+ /** Did the platform give at least `minDays` notice, and did the new rulebook only appear after it took effect? */
82
+ export function noticeCompliance(notice, decisions, minDays) {
83
+ const gap = (Date.parse(String(notice.effectiveFrom)) - Date.parse(String(notice.ts))) / 86_400_000;
84
+ const early = decisions.filter((d) => d.manifest_hash === notice.to && String(d.ts) < String(notice.effectiveFrom));
85
+ return { ok: gap >= minDays && early.length === 0, noticeDays: Math.floor(gap), usedEarly: early.length };
86
+ }
87
+ /** A union or advocate pools members' decision records: rule consistency plus outcomes per kind. */
88
+ export function collectiveAudit(memberDecisions) {
89
+ const all = memberDecisions.flat();
90
+ const outcomes = {};
91
+ for (const d of all)
92
+ outcomes[String(d.kind)] = (outcomes[String(d.kind)] ?? 0) + 1;
93
+ return { members: memberDecisions.length, decisions: all.length, consistency: ruleConsistency(all), byKind: outcomes };
94
+ }
95
+ /** A credit decision: rulebook, committed factors and principal reasons. */
96
+ export function creditDecision(input) {
97
+ const { approved, reasons, ...rest } = input;
98
+ const receipt = buildDecisionReceipt({ ...rest, kind: 'credit', outcome: { approved, ...(input.outcome ?? {}) } });
99
+ return { receipt, notice: approved ? null : adverseActionNotice(receipt.payload, { reasons: reasons ?? ['(state the principal reasons)'], decidedBy: 'automated system', rights: 'You may request the reasons and a human review.' }) };
100
+ }
101
+ /** A tenant-screening decision, recorded the same way. */
102
+ export function tenantScreeningDecision(input) {
103
+ const { accepted, reasons, ...rest } = input;
104
+ const receipt = buildDecisionReceipt({ ...rest, kind: 'tenant-screening', outcome: { accepted, ...(input.outcome ?? {}) } });
105
+ return { receipt, notice: accepted ? null : adverseActionNotice(receipt.payload, { reasons: reasons ?? ['(state the principal reasons)'], decidedBy: 'automated system', rights: 'You may request a copy of the report used.' }) };
106
+ }
107
+ //# sourceMappingURL=fairness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fairness.js","sourceRoot":"","sources":["../src/fairness.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -53,4 +53,5 @@ export interface ConsistencyReport {
53
53
  * interleaved window is the red flag a regulator looks for.
54
54
  */
55
55
  export declare function ruleConsistency(payloads: Array<Record<string, unknown>>): ConsistencyReport;
56
+ export * from './fairness.js';
56
57
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,yCAAyC;AACzC,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAkB1E;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,aAAa,CAQ1F;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,iGAAiG;IACjG,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,iBAAiB,CA2B3F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,yCAAyC;AACzC,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAkB1E;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,aAAa,CAQ1F;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,iGAAiG;IACjG,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,iBAAiB,CA2B3F;AACD,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -93,4 +93,5 @@ export function ruleConsistency(payloads) {
93
93
  }
94
94
  return { rulebooks, consistent: reasons.length === 0, reasons };
95
95
  }
96
+ export * from './fairness.js';
96
97
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAiC5C,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB,CAAC,KAAoB;IACvD,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,+FAA+F,CAAC,CAAC;IAC1I,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAClF,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS;QACzD,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3C,MAAM,OAAO,GAA4B;QACvC,QAAQ,EAAE,UAAU;QACpB,CAAC,EAAE,CAAC;QACJ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,aAAa,EAAE,KAAK,CAAC,YAAY;QACjC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,EAAE,EAAE,KAAK,CAAC,EAAE;KACb,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,YAAY,KAAK,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC;AACjH,CAAC;AAOD,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,OAA4C;IACzE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,CAAC,GAAG,OAAO,IAAI,EAAE,CAAC;IACxB,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACxF,IAAI,CAAC,CAAC,CAAC,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAC3H,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACnG,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC;AAiBD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAwC;IACtE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAClD,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,qBAAqB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9D,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,aAAuB,CAAC;QACpC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAY,CAAC;QAC1B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YACb,CAAC,CAAC,OAAO,GAAG,EAAE,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7F,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAI,SAAS,CAAC,CAAC,CAAE,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,OAAO,EAAE,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,aAAa,SAAS,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,aAAa,QAAQ,SAAS,CAAC,CAAC,CAAE,CAAC,aAAa,8DAA8D,CAAC,CAAC;QAC9J,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zanii/decisions",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Gig/creator algorithmic fairness: decision receipts a worker can audit — completeness (every decision about me, tamper-evident), rule-consistency (the same rulebook decided everyone, via manifest_hash), and committed factors (no post-hoc rationalization). Never claims 'the algorithm is fair'.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ledger.zanii.agency",
@@ -31,8 +31,8 @@
31
31
  "vitest": "^3.0.9"
32
32
  },
33
33
  "dependencies": {
34
- "@zanii/subject": "^0.1.2",
35
- "@zanii/core": "^0.5.2"
34
+ "@zanii/core": "^0.5.4",
35
+ "@zanii/subject": "^0.1.2"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc -p tsconfig.build.json",
@@ -0,0 +1,115 @@
1
+ /**
2
+ * What people and auditors need around algorithmic decisions: adverse-action notices,
3
+ * selection-rate disparity (the impact ratio bias audits use), human-review requests with
4
+ * deadlines, pay breakdowns, appeal packs, counterfactuals, advance notice of rule changes,
5
+ * collective audits, and credit and tenant-screening decisions.
6
+ *
7
+ * Fairness metrics here are arithmetic on outcomes. They flag where to look; they do not
8
+ * decide whether a system is lawful or fair.
9
+ */
10
+ import { jcsHash } from '@zanii/core';
11
+ import { buildDecisionReceipt, ruleConsistency, type DecisionInput } from './index.js';
12
+
13
+ type Payload = Record<string, unknown>;
14
+
15
+ /** An adverse-action notice: the decision, its rulebook and the principal reasons (at most four, most important first). */
16
+ export function adverseActionNotice(decision: Payload, input: { reasons: string[]; decidedBy: string; rights: string }) {
17
+ if (!input.reasons.length) throw new Error('decisions: an adverse action needs at least one principal reason');
18
+ return {
19
+ decision: jcsHash(decision), kind: decision.kind, rulebook: decision.manifest_hash, decided_by: input.decidedBy,
20
+ principal_reasons: input.reasons.slice(0, 4), rights: input.rights, ts: decision.ts,
21
+ };
22
+ }
23
+
24
+ /**
25
+ * Selection rate per group and the impact ratio against the most-selected group. Groups
26
+ * are supplied by the auditor (they never go on the ledger). A ratio under 0.8 is flagged,
27
+ * the threshold bias audits commonly use.
28
+ */
29
+ export function disparityReport(outcomes: Array<{ group: string; selected: boolean }>, threshold = 0.8) {
30
+ const groups = new Map<string, { n: number; selected: number }>();
31
+ for (const o of outcomes) {
32
+ const g = groups.get(o.group) ?? { n: 0, selected: 0 };
33
+ g.n++;
34
+ if (o.selected) g.selected++;
35
+ groups.set(o.group, g);
36
+ }
37
+ const rates = [...groups].map(([group, g]) => ({ group, n: g.n, rate: g.n ? g.selected / g.n : 0 }));
38
+ const best = Math.max(...rates.map((r) => r.rate), 0);
39
+ return rates.map((r) => ({ ...r, impactRatio: best ? Math.round((r.rate / best) * 1000) / 1000 : null, flagged: best > 0 && r.rate / best < threshold }));
40
+ }
41
+
42
+ /** A person asks for a human to review an automated decision. */
43
+ export function humanReviewRequest(input: { decision: string; subjectTag: string; reason: string; ts: string; slaDays: number }) {
44
+ return { target: 'decision.review.request', subjectTag: input.subjectTag, payload: { _zr_kind: 'decision.review', v: 1, decision: input.decision, reason: input.reason, ts: input.ts, due: new Date(Date.parse(input.ts) + input.slaDays * 86_400_000).toISOString() } };
45
+ }
46
+
47
+ /** Which review requests are answered, pending or overdue. */
48
+ export function reviewStatus(requests: Payload[], resolutions: Array<{ decision: string; ts: string; outcome: 'upheld' | 'changed' }>, now: string) {
49
+ return requests.map((r) => {
50
+ const done = resolutions.find((x) => x.decision === r.decision && x.ts >= String(r.ts));
51
+ return { decision: r.decision, status: done ? (done.ts <= String(r.due) ? 'answered' : 'answered-late') : now > String(r.due) ? 'overdue' : 'pending', outcome: done?.outcome ?? null };
52
+ });
53
+ }
54
+
55
+ /** How a worker's pay for a period was computed, line by line, and whether it adds up to what was paid. Integer minor units. */
56
+ export function payBreakdown(lines: Array<{ task: string; base_minor: number; adjustments: Array<{ reason: string; amount_minor: number }> }>, paid_minor: number) {
57
+ const items = lines.map((l) => ({ task: l.task, base_minor: l.base_minor, adjustments: l.adjustments, total_minor: l.base_minor + l.adjustments.reduce((s, a) => s + a.amount_minor, 0) }));
58
+ const computed = items.reduce((s, i) => s + i.total_minor, 0);
59
+ return { items, computed_minor: computed, paid_minor, matches: computed === paid_minor, difference_minor: paid_minor - computed };
60
+ }
61
+
62
+ /** Everything a worker needs to contest a deactivation or a sanction. */
63
+ export function appealPack(decision: Payload, statement: string, factors?: { nonce: string; disclosed?: Record<string, unknown> }) {
64
+ return {
65
+ decision: jcsHash(decision), kind: decision.kind, outcome: decision.outcome, rulebook: decision.manifest_hash, ts: decision.ts,
66
+ factors_commitment: decision.factors_commitment ?? null, factors: factors?.disclosed ?? null, factors_nonce: factors?.nonce ?? null, statement,
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Which single-factor changes would have flipped the outcome, using the (committed) model
72
+ * you supply. Each candidate value is tried on its own.
73
+ */
74
+ export function counterfactuals<F extends Record<string, unknown>>(model: (factors: F) => boolean, factors: F, candidates: Partial<Record<keyof F, unknown[]>>) {
75
+ const base = model(factors);
76
+ const flips: Array<{ factor: keyof F; from: unknown; to: unknown }> = [];
77
+ for (const [k, values] of Object.entries(candidates) as Array<[keyof F, unknown[]]>) {
78
+ for (const v of values) if (model({ ...factors, [k]: v }) !== base) flips.push({ factor: k, from: factors[k], to: v });
79
+ }
80
+ return { outcome: base, flips };
81
+ }
82
+
83
+ /** Advance notice that a rulebook will change. */
84
+ export function ruleChangeNotice(input: { from: string; to: string; effectiveFrom: string; summary: string; ts: string }) {
85
+ return { target: 'decision.rulebook.notice', payload: { _zr_kind: 'decision.notice', v: 1, ...input } };
86
+ }
87
+
88
+ /** Did the platform give at least `minDays` notice, and did the new rulebook only appear after it took effect? */
89
+ export function noticeCompliance(notice: Payload, decisions: Payload[], minDays: number) {
90
+ const gap = (Date.parse(String(notice.effectiveFrom)) - Date.parse(String(notice.ts))) / 86_400_000;
91
+ const early = decisions.filter((d) => d.manifest_hash === notice.to && String(d.ts) < String(notice.effectiveFrom));
92
+ return { ok: gap >= minDays && early.length === 0, noticeDays: Math.floor(gap), usedEarly: early.length };
93
+ }
94
+
95
+ /** A union or advocate pools members' decision records: rule consistency plus outcomes per kind. */
96
+ export function collectiveAudit(memberDecisions: Payload[][]) {
97
+ const all = memberDecisions.flat();
98
+ const outcomes: Record<string, number> = {};
99
+ for (const d of all) outcomes[String(d.kind)] = (outcomes[String(d.kind)] ?? 0) + 1;
100
+ return { members: memberDecisions.length, decisions: all.length, consistency: ruleConsistency(all), byKind: outcomes };
101
+ }
102
+
103
+ /** A credit decision: rulebook, committed factors and principal reasons. */
104
+ export function creditDecision(input: Omit<DecisionInput, 'kind'> & { approved: boolean; reasons?: string[] }) {
105
+ const { approved, reasons, ...rest } = input;
106
+ const receipt = buildDecisionReceipt({ ...rest, kind: 'credit', outcome: { approved, ...(input.outcome ?? {}) } });
107
+ return { receipt, notice: approved ? null : adverseActionNotice(receipt.payload, { reasons: reasons ?? ['(state the principal reasons)'], decidedBy: 'automated system', rights: 'You may request the reasons and a human review.' }) };
108
+ }
109
+
110
+ /** A tenant-screening decision, recorded the same way. */
111
+ export function tenantScreeningDecision(input: Omit<DecisionInput, 'kind'> & { accepted: boolean; reasons?: string[] }) {
112
+ const { accepted, reasons, ...rest } = input;
113
+ const receipt = buildDecisionReceipt({ ...rest, kind: 'tenant-screening', outcome: { accepted, ...(input.outcome ?? {}) } });
114
+ return { receipt, notice: accepted ? null : adverseActionNotice(receipt.payload, { reasons: reasons ?? ['(state the principal reasons)'], decidedBy: 'automated system', rights: 'You may request a copy of the report used.' }) };
115
+ }
package/src/index.ts CHANGED
@@ -139,3 +139,4 @@ export function ruleConsistency(payloads: Array<Record<string, unknown>>): Consi
139
139
  }
140
140
  return { rulebooks, consistent: reasons.length === 0, reasons };
141
141
  }
142
+ export * from './fairness.js';