@skill-harness/adapters 0.17.0 → 0.18.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/dist/index.d.ts +0 -30
- package/dist/index.js +0 -30
- package/dist/pi.js +21 -133
- package/package.json +2 -3
- package/dist/archive-access.d.ts +0 -58
- package/dist/archive-access.js +0 -61
- package/dist/archive-checkpoint.d.ts +0 -47
- package/dist/archive-checkpoint.js +0 -116
- package/dist/archive-facts.d.ts +0 -19
- package/dist/archive-facts.js +0 -20
- package/dist/archive-observer.d.ts +0 -21
- package/dist/archive-observer.js +0 -79
- package/dist/archive-policy.d.ts +0 -107
- package/dist/archive-policy.js +0 -135
- package/dist/archive-read-capability.d.ts +0 -49
- package/dist/archive-read-capability.js +0 -45
- package/dist/archive-retention-policy.d.ts +0 -52
- package/dist/archive-retention-policy.js +0 -49
- package/dist/archived-work.d.ts +0 -45
- package/dist/archived-work.js +0 -78
- package/dist/blind-intervention.d.ts +0 -35
- package/dist/blind-intervention.js +0 -218
- package/dist/codex-diagnostic-model.d.ts +0 -14
- package/dist/codex-diagnostic-model.js +0 -39
- package/dist/codex-host-observer.d.ts +0 -111
- package/dist/codex-host-observer.js +0 -309
- package/dist/codex-https.d.ts +0 -7
- package/dist/codex-https.js +0 -221
- package/dist/codex-model-profile.d.ts +0 -38
- package/dist/codex-model-profile.js +0 -54
- package/dist/codex-producer-ipc.d.ts +0 -55
- package/dist/codex-producer-ipc.js +0 -67
- package/dist/codex-sdk-transport.d.ts +0 -50
- package/dist/codex-sdk-transport.js +0 -294
- package/dist/codex-subscription.d.ts +0 -114
- package/dist/codex-subscription.js +0 -268
- package/dist/evidence-archive.d.ts +0 -65
- package/dist/evidence-archive.js +0 -225
- package/dist/execution-projection-schema.d.ts +0 -10
- package/dist/execution-projection-schema.js +0 -30
- package/dist/execution-retention-archive.d.ts +0 -69
- package/dist/execution-retention-archive.js +0 -154
- package/dist/generated/retention-v2-contract.d.ts +0 -72
- package/dist/generated/retention-v2-contract.js +0 -105
- package/dist/generated/retention-v2-json.d.ts +0 -24
- package/dist/generated/retention-v2-json.js +0 -268
- package/dist/generated/retention-v2-native-json.d.ts +0 -2
- package/dist/generated/retention-v2-native-json.js +0 -33
- package/dist/generated/retention-v2-native.d.ts +0 -58
- package/dist/generated/retention-v2-native.js +0 -155
- package/dist/generated/retention-v2-pin.d.ts +0 -2
- package/dist/generated/retention-v2-pin.js +0 -4
- package/dist/generated/retention-v2-types.d.ts +0 -49
- package/dist/generated/retention-v2-types.js +0 -2
- package/dist/generated/retention-v2-work-types.d.ts +0 -260
- package/dist/generated/retention-v2-work-types.js +0 -13
- package/dist/generated/work-v4/execution-id.d.ts +0 -5
- package/dist/generated/work-v4/execution-id.js +0 -14
- package/dist/generated/work-v4/json.d.ts +0 -24
- package/dist/generated/work-v4/json.js +0 -268
- package/dist/generated/work-v4/occurrences.d.ts +0 -226
- package/dist/generated/work-v4/occurrences.js +0 -116
- package/dist/generated/work-v4/pin.d.ts +0 -1
- package/dist/generated/work-v4/pin.js +0 -3
- package/dist/generated/work-v4/projection.d.ts +0 -294
- package/dist/generated/work-v4/projection.js +0 -238
- package/dist/generated/work-v4/reader.d.ts +0 -24
- package/dist/generated/work-v4/reader.js +0 -109
- package/dist/generated/work-v4/snapshot.d.ts +0 -28
- package/dist/generated/work-v4/snapshot.js +0 -268
- package/dist/generated/work-v4/types.d.ts +0 -260
- package/dist/generated/work-v4/types.js +0 -13
- package/dist/generated/work-v4/validation.d.ts +0 -13
- package/dist/generated/work-v4/validation.js +0 -227
- package/dist/installed-review-session.d.ts +0 -28
- package/dist/installed-review-session.js +0 -166
- package/dist/intervention-run.d.ts +0 -403
- package/dist/intervention-run.js +0 -169
- package/dist/learning-case.d.ts +0 -12
- package/dist/learning-case.js +0 -15
- package/dist/learning-journal.d.ts +0 -18
- package/dist/learning-journal.js +0 -256
- package/dist/learning-lifecycle.d.ts +0 -28
- package/dist/learning-lifecycle.js +0 -66
- package/dist/learning-trust-setup.d.ts +0 -64
- package/dist/learning-trust-setup.js +0 -55
- package/dist/learning-workspace.d.ts +0 -1084
- package/dist/learning-workspace.js +0 -705
- package/dist/principal-payload-port.d.ts +0 -25
- package/dist/principal-payload-port.js +0 -40
- package/dist/producer-product.d.ts +0 -70
- package/dist/producer-product.js +0 -186
- package/dist/producer-review.d.ts +0 -53
- package/dist/producer-review.js +0 -207
- package/dist/prompt-capture-extension.d.ts +0 -10
- package/dist/prompt-capture-extension.js +0 -26
- package/dist/prompt-provenance.d.ts +0 -22
- package/dist/prompt-provenance.js +0 -146
- package/dist/reviewed-archive-export.d.ts +0 -42
- package/dist/reviewed-archive-export.js +0 -78
- package/dist/session-observation.d.ts +0 -50
- package/dist/session-observation.js +0 -186
- package/dist/session-retention.d.ts +0 -48
- package/dist/session-retention.js +0 -121
- package/dist/trust-lifecycle.d.ts +0 -152
- package/dist/trust-lifecycle.js +0 -209
- package/dist/weekly-investigation.d.ts +0 -237
- package/dist/weekly-investigation.js +0 -330
- package/dist/work-candidates.d.ts +0 -29
- package/dist/work-candidates.js +0 -78
- package/dist/work-case-archive.d.ts +0 -25
- package/dist/work-case-archive.js +0 -63
- package/dist/work-case-review.d.ts +0 -45
- package/dist/work-case-review.js +0 -220
- package/dist/work-signal-cases.d.ts +0 -15
- package/dist/work-signal-cases.js +0 -54
- package/dist/work-signal-observation.d.ts +0 -23
- package/dist/work-signal-observation.js +0 -89
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { learningFile, learningHash, learningCopy } from './learning-journal.js';
|
|
4
|
-
import { retainArchiveSource, readArchiveSource } from './evidence-archive.js';
|
|
5
|
-
import { observePiSession, observeSessionLedger, sessionText } from './session-observation.js';
|
|
6
|
-
const captured = new WeakMap();
|
|
7
|
-
const sha = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
8
|
-
function checkedSelections(input) {
|
|
9
|
-
if (!Array.isArray(input) || input.length < 1 || input.length > 16)
|
|
10
|
-
throw Error('select 1–16 explicit session sources');
|
|
11
|
-
const seen = new Set(), executions = new Set();
|
|
12
|
-
let parents = 0, ledgers = 0;
|
|
13
|
-
for (const s of input) {
|
|
14
|
-
if (!s || typeof s !== 'object' || Object.keys(s).some(k => !['kind', 'path', 'executionId'].includes(k)))
|
|
15
|
-
throw Error('closed source selection required');
|
|
16
|
-
if (!['parent', 'child', 'ledger', 'feedback', 'artifact'].includes(s.kind) || typeof s.path !== 'string' || resolve(s.path) !== s.path)
|
|
17
|
-
throw Error('explicit absolute source path required');
|
|
18
|
-
if (seen.has(s.path))
|
|
19
|
-
throw Error('duplicate session source');
|
|
20
|
-
seen.add(s.path);
|
|
21
|
-
if (s.kind === 'parent')
|
|
22
|
-
parents++;
|
|
23
|
-
if (s.kind === 'ledger')
|
|
24
|
-
ledgers++;
|
|
25
|
-
if (s.executionId !== undefined) {
|
|
26
|
-
if (s.kind !== 'child' || !/^exec:[0-9a-f-]{36}$/i.test(s.executionId) || executions.has(s.executionId))
|
|
27
|
-
throw Error('unique child execution id required');
|
|
28
|
-
executions.add(s.executionId);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (parents !== 1 || ledgers > 1)
|
|
32
|
-
throw Error('exactly one parent and at most one ledger required');
|
|
33
|
-
}
|
|
34
|
-
function projectSession(selections, buffers) {
|
|
35
|
-
const parent = observePiSession(buffers[selections.findIndex(s => s.kind === 'parent')]);
|
|
36
|
-
const children = selections.flatMap((s, i) => s.kind === 'child' ? [{ source: i, executionId: s.executionId ?? null, session: observePiSession(buffers[i]) }] : []);
|
|
37
|
-
if (new Set([parent.sessionId, ...children.map(c => c.session.sessionId)]).size !== children.length + 1)
|
|
38
|
-
throw Error('duplicate parent/child session id');
|
|
39
|
-
const ledger = selections.findIndex(s => s.kind === 'ledger'), attempts = ledger < 0 ? [] : observeSessionLedger(buffers[ledger]);
|
|
40
|
-
for (const child of children)
|
|
41
|
-
if (child.executionId && !attempts.some(a => a.executionId === child.executionId))
|
|
42
|
-
throw Error('selected child execution absent from ledger');
|
|
43
|
-
const gaps = [...parent.gaps, 'No quality, acceptance, calibrated learning or adoption is inferred from this import.'];
|
|
44
|
-
for (const child of children)
|
|
45
|
-
gaps.push(...child.session.gaps.map(g => 'Child source ' + (child.source + 1) + ' (' + child.session.sessionId + '): ' + g));
|
|
46
|
-
if (ledger < 0)
|
|
47
|
-
gaps.push('No delegation ledger selected.');
|
|
48
|
-
else
|
|
49
|
-
gaps.push('Ledger/session association is operator-selected, not authenticated; ledger may include other sessions.');
|
|
50
|
-
if (attempts.length > children.filter(c => c.executionId).length)
|
|
51
|
-
gaps.push('Child transcript coverage incomplete; no combined token total is claimed.');
|
|
52
|
-
if (children.length)
|
|
53
|
-
gaps.push('Child execution mappings are explicit operator declarations, not proof of parentage. Each transcript has separate usage.');
|
|
54
|
-
if (!selections.some(s => s.kind === 'feedback'))
|
|
55
|
-
gaps.push('External feedback not supplied; user messages remain available for review.');
|
|
56
|
-
if (!selections.some(s => s.kind === 'artifact'))
|
|
57
|
-
gaps.push('No final artifact or source snapshot supplied.');
|
|
58
|
-
return { parent, children, attempts, gaps };
|
|
59
|
-
}
|
|
60
|
-
/** Explicit local selection only. Does not scan session directories, follow links, or contact workers. */
|
|
61
|
-
export function prepareSessionImport(selections) {
|
|
62
|
-
checkedSelections(selections);
|
|
63
|
-
const buffers = selections.map(s => learningFile(s.path, 8 * 1024 * 1024));
|
|
64
|
-
if (buffers.reduce((n, b) => n + b.length, 0) > 32 * 1024 * 1024)
|
|
65
|
-
throw Error('session selection exceeds 32 MiB');
|
|
66
|
-
const sources = selections.map((s, i) => ({ ...s, executionId: s.executionId ?? null, sha256: sha(buffers[i]), bytes: buffers[i].length }));
|
|
67
|
-
const { parent, children, attempts, gaps } = projectSession(selections, buffers);
|
|
68
|
-
const digest = learningHash({ version: 'session-selection-v1', sources });
|
|
69
|
-
const preview = { version: 'session-import-preview-v1', digest, sources, parent, children, attempts, gaps, acceptance: 'not-assessed' };
|
|
70
|
-
captured.set(preview, { preview: learningCopy(preview), buffers });
|
|
71
|
-
return preview;
|
|
72
|
-
}
|
|
73
|
-
export function retainSessionImport(root, preview, expectedDigest) {
|
|
74
|
-
const c = captured.get(preview);
|
|
75
|
-
if (!c || learningHash(c.preview) !== learningHash(preview) || expectedDigest !== c.preview.digest)
|
|
76
|
-
throw Error('exact preview digest required; changed or forged session import');
|
|
77
|
-
for (const s of c.preview.sources)
|
|
78
|
-
if (sha(learningFile(s.path, 8 * 1024 * 1024)) !== s.sha256)
|
|
79
|
-
throw Error('session source changed since preview; prepare again');
|
|
80
|
-
const sources = c.preview.sources.map((s, i) => {
|
|
81
|
-
const parser = s.kind === 'parent' || s.kind === 'child' ? 'pi-session-jsonl' : s.kind === 'ledger' ? 'pi-daddy-session-ledger' : 'session-evidence';
|
|
82
|
-
const r = retainArchiveSource(root, { sourceId: 'session-' + s.sha256, parser: { id: parser, version: '1' }, retention: 'exact', bytes: c.buffers[i] });
|
|
83
|
-
return { ...s, manifestId: r.manifestId };
|
|
84
|
-
});
|
|
85
|
-
const record = { version: 'retrospective-session-v1', selectionDigest: preview.digest, sources };
|
|
86
|
-
return retainArchiveSource(root, { sourceId: 'retrospective-' + preview.digest, parser: { id: 'retrospective-session', version: '1' }, retention: 'exact', bytes: Buffer.from(JSON.stringify(record)) }).manifestId;
|
|
87
|
-
}
|
|
88
|
-
export function readRetainedSession(root, manifestId) {
|
|
89
|
-
const selected = readArchiveSource(root, manifestId);
|
|
90
|
-
if (selected.status !== 'available' || selected.reference.retention !== 'exact' || selected.reference.parser.id !== 'retrospective-session' || selected.reference.parser.version !== '1')
|
|
91
|
-
throw Error('retained session unavailable or unsupported');
|
|
92
|
-
const record = JSON.parse(sessionText(selected.bytes));
|
|
93
|
-
if (!record || record.version !== 'retrospective-session-v1' || Object.keys(record).sort().join() !== 'selectionDigest,sources,version' || !Array.isArray(record.sources))
|
|
94
|
-
throw Error('invalid retained session');
|
|
95
|
-
checkedSelections(record.sources.map(s => ({ kind: s.kind, path: s.path, ...(s.executionId === null ? {} : { executionId: s.executionId }) })));
|
|
96
|
-
const sources = record.sources.map(s => {
|
|
97
|
-
if (Object.keys(s).sort().join() !== 'bytes,executionId,kind,manifestId,path,sha256')
|
|
98
|
-
throw Error('invalid retained session source');
|
|
99
|
-
const r = readArchiveSource(root, s.manifestId);
|
|
100
|
-
if (r.status !== 'available' || r.reference.retention !== 'exact' || r.reference.sha256 !== s.sha256 || r.bytes.length !== s.bytes)
|
|
101
|
-
throw Error('retained session source missing or changed');
|
|
102
|
-
return { selection: s, bytes: r.bytes };
|
|
103
|
-
});
|
|
104
|
-
if (sources.reduce((n, s) => n + s.bytes.length, 0) > 32 * 1024 * 1024)
|
|
105
|
-
throw Error('session selection exceeds 32 MiB');
|
|
106
|
-
const plain = record.sources.map(({ manifestId, ...s }) => s);
|
|
107
|
-
if (learningHash({ version: 'session-selection-v1', sources: plain }) !== record.selectionDigest)
|
|
108
|
-
throw Error('retained session selection mismatch');
|
|
109
|
-
const projection = projectSession(record.sources.map(s => ({ kind: s.kind, path: s.path, ...(s.executionId === null ? {} : { executionId: s.executionId }) })), sources.map(s => s.bytes));
|
|
110
|
-
return { version: record.version, manifestId, selectionDigest: record.selectionDigest, sources: record.sources, ...projection, acceptance: 'not-assessed' };
|
|
111
|
-
}
|
|
112
|
-
export function readRetainedSessionSource(root, manifestId, index) {
|
|
113
|
-
const session = readRetainedSession(root, manifestId), source = session.sources[index];
|
|
114
|
-
if (!Number.isSafeInteger(index) || !source)
|
|
115
|
-
throw Error('select a listed session source');
|
|
116
|
-
const result = readArchiveSource(root, source.manifestId);
|
|
117
|
-
if (result.status !== 'available')
|
|
118
|
-
throw Error('session source unavailable');
|
|
119
|
-
return result.bytes;
|
|
120
|
-
}
|
|
121
|
-
//# sourceMappingURL=session-retention.js.map
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { type CalibrationComponent, type CalibrationPrediction, type ExposurePolicy } from '@skill-harness/core';
|
|
2
|
-
import { type LearningCaseReference } from './learning-case.js';
|
|
3
|
-
export interface TrustLifecycleInput {
|
|
4
|
-
archiveRoot: string;
|
|
5
|
-
component: CalibrationComponent;
|
|
6
|
-
seed: string;
|
|
7
|
-
maxUnflagged: number;
|
|
8
|
-
cohort: {
|
|
9
|
-
incidentId: string;
|
|
10
|
-
manifestId: string;
|
|
11
|
-
flagged: boolean;
|
|
12
|
-
split: 'calibration' | 'heldout' | 'tuning';
|
|
13
|
-
}[];
|
|
14
|
-
exposure: ExposurePolicy | null;
|
|
15
|
-
}
|
|
16
|
-
export interface TrustReferenceOutcome {
|
|
17
|
-
kind: 'prediction' | 'unflagged';
|
|
18
|
-
targetId: string;
|
|
19
|
-
value: boolean;
|
|
20
|
-
evidenceManifestId: string;
|
|
21
|
-
referenceId: string;
|
|
22
|
-
}
|
|
23
|
-
export declare const trustPolicyDigest: (input: TrustLifecycleInput) => string;
|
|
24
|
-
export declare const trustOutcomeDigest: (outcome: TrustReferenceOutcome) => string;
|
|
25
|
-
export declare function createTrustLifecycle(directory: string, input: TrustLifecycleInput, authorizedPolicyDigests: readonly string[]): {
|
|
26
|
-
inspect: (now: number) => {
|
|
27
|
-
policyId: string;
|
|
28
|
-
component: CalibrationComponent;
|
|
29
|
-
calibration: {
|
|
30
|
-
version: "factory-calibration-v1";
|
|
31
|
-
reports: import("@skill-harness/core").CalibrationReport[];
|
|
32
|
-
excludedTuning: number;
|
|
33
|
-
referenceBasis: "independently-supplied-host-context";
|
|
34
|
-
advisoryOnly: true;
|
|
35
|
-
};
|
|
36
|
-
sampledIncidentIds: string[];
|
|
37
|
-
unflagged: {
|
|
38
|
-
sampled: number;
|
|
39
|
-
resolved: number;
|
|
40
|
-
misses: number;
|
|
41
|
-
unresolved: number;
|
|
42
|
-
conflicted: number;
|
|
43
|
-
};
|
|
44
|
-
attentionUsed: number;
|
|
45
|
-
retired: boolean;
|
|
46
|
-
exposures: {
|
|
47
|
-
mode: "ask" | "silent" | "retire";
|
|
48
|
-
reason: string;
|
|
49
|
-
id: string;
|
|
50
|
-
}[];
|
|
51
|
-
tip: string;
|
|
52
|
-
grantExpansion: false;
|
|
53
|
-
};
|
|
54
|
-
configuration: () => TrustLifecycleInput;
|
|
55
|
-
previewExposure: (now: number) => {
|
|
56
|
-
mode: "silent" | "ask" | "retire";
|
|
57
|
-
reason: string;
|
|
58
|
-
advisoryOnly: true;
|
|
59
|
-
} | {
|
|
60
|
-
mode: "retire";
|
|
61
|
-
reason: string;
|
|
62
|
-
} | {
|
|
63
|
-
mode: "silent";
|
|
64
|
-
reason: string;
|
|
65
|
-
};
|
|
66
|
-
history: () => import("./learning-journal.js").LearningEvent[];
|
|
67
|
-
previewCaseOutcome: (predictionId: string, reference: LearningCaseReference) => {
|
|
68
|
-
outcome: TrustReferenceOutcome;
|
|
69
|
-
caseReference: LearningCaseReference;
|
|
70
|
-
digest: string;
|
|
71
|
-
tip: string;
|
|
72
|
-
};
|
|
73
|
-
linkCaseOutcome(predictionId: string, reference: LearningCaseReference, authorizedDigests: readonly string[], referenceAuthor?: string): void;
|
|
74
|
-
predict(p: CalibrationPrediction): void;
|
|
75
|
-
correct(prior: string, p: CalibrationPrediction, reason: string): void;
|
|
76
|
-
outcome(value: TrustReferenceOutcome, authorizedReferenceDigests: readonly string[], referenceAuthor?: string): void;
|
|
77
|
-
expose(id: string, now: number): {
|
|
78
|
-
replayed: boolean;
|
|
79
|
-
mode: "ask" | "silent" | "retire";
|
|
80
|
-
reason: string;
|
|
81
|
-
} | {
|
|
82
|
-
replayed: boolean;
|
|
83
|
-
mode: "silent" | "ask" | "retire";
|
|
84
|
-
reason: string;
|
|
85
|
-
advisoryOnly: true;
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
/** Existing calibration is recomputed from durable scoped predictions and independently permitted
|
|
89
|
-
* retained labels. Applied exposure is an attention reservation, not proof a human saw a question. */
|
|
90
|
-
export declare function openTrustLifecycle(directory: string): {
|
|
91
|
-
inspect: (now: number) => {
|
|
92
|
-
policyId: string;
|
|
93
|
-
component: CalibrationComponent;
|
|
94
|
-
calibration: {
|
|
95
|
-
version: "factory-calibration-v1";
|
|
96
|
-
reports: import("@skill-harness/core").CalibrationReport[];
|
|
97
|
-
excludedTuning: number;
|
|
98
|
-
referenceBasis: "independently-supplied-host-context";
|
|
99
|
-
advisoryOnly: true;
|
|
100
|
-
};
|
|
101
|
-
sampledIncidentIds: string[];
|
|
102
|
-
unflagged: {
|
|
103
|
-
sampled: number;
|
|
104
|
-
resolved: number;
|
|
105
|
-
misses: number;
|
|
106
|
-
unresolved: number;
|
|
107
|
-
conflicted: number;
|
|
108
|
-
};
|
|
109
|
-
attentionUsed: number;
|
|
110
|
-
retired: boolean;
|
|
111
|
-
exposures: {
|
|
112
|
-
mode: "ask" | "silent" | "retire";
|
|
113
|
-
reason: string;
|
|
114
|
-
id: string;
|
|
115
|
-
}[];
|
|
116
|
-
tip: string;
|
|
117
|
-
grantExpansion: false;
|
|
118
|
-
};
|
|
119
|
-
configuration: () => TrustLifecycleInput;
|
|
120
|
-
previewExposure: (now: number) => {
|
|
121
|
-
mode: "silent" | "ask" | "retire";
|
|
122
|
-
reason: string;
|
|
123
|
-
advisoryOnly: true;
|
|
124
|
-
} | {
|
|
125
|
-
mode: "retire";
|
|
126
|
-
reason: string;
|
|
127
|
-
} | {
|
|
128
|
-
mode: "silent";
|
|
129
|
-
reason: string;
|
|
130
|
-
};
|
|
131
|
-
history: () => import("./learning-journal.js").LearningEvent[];
|
|
132
|
-
previewCaseOutcome: (predictionId: string, reference: LearningCaseReference) => {
|
|
133
|
-
outcome: TrustReferenceOutcome;
|
|
134
|
-
caseReference: LearningCaseReference;
|
|
135
|
-
digest: string;
|
|
136
|
-
tip: string;
|
|
137
|
-
};
|
|
138
|
-
linkCaseOutcome(predictionId: string, reference: LearningCaseReference, authorizedDigests: readonly string[], referenceAuthor?: string): void;
|
|
139
|
-
predict(p: CalibrationPrediction): void;
|
|
140
|
-
correct(prior: string, p: CalibrationPrediction, reason: string): void;
|
|
141
|
-
outcome(value: TrustReferenceOutcome, authorizedReferenceDigests: readonly string[], referenceAuthor?: string): void;
|
|
142
|
-
expose(id: string, now: number): {
|
|
143
|
-
replayed: boolean;
|
|
144
|
-
mode: "ask" | "silent" | "retire";
|
|
145
|
-
reason: string;
|
|
146
|
-
} | {
|
|
147
|
-
replayed: boolean;
|
|
148
|
-
mode: "silent" | "ask" | "retire";
|
|
149
|
-
reason: string;
|
|
150
|
-
advisoryOnly: true;
|
|
151
|
-
};
|
|
152
|
-
};
|
package/dist/trust-lifecycle.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { calibratePredictions, recommendExposure } from '@skill-harness/core';
|
|
2
|
-
import { isAbsolute } from 'node:path';
|
|
3
|
-
import { readArchiveSource } from './evidence-archive.js';
|
|
4
|
-
import { learningCopy, learningHash, learningJournal, registerLearningStore, verifyLearningStore } from './learning-journal.js';
|
|
5
|
-
import { readLearningCase } from './learning-case.js';
|
|
6
|
-
export const trustPolicyDigest = (input) => learningHash({ version: 'trust-lifecycle-v1', input });
|
|
7
|
-
export const trustOutcomeDigest = (outcome) => learningHash({ version: 'trust-reference-v1', outcome });
|
|
8
|
-
function evidence(root, id) { const result = readArchiveSource(root, id); if (result.status !== 'available' || !['exact', 'redacted'].includes(result.reference.retention))
|
|
9
|
-
throw Error('independent retained evidence unavailable'); return result; }
|
|
10
|
-
const text = (v) => typeof v === 'string' && v.length > 0 && v.length <= 512 && !/[\u0000-\u001f\u007f]/.test(v);
|
|
11
|
-
function validate(input) {
|
|
12
|
-
if (!isAbsolute(input.archiveRoot) || Object.keys(input).sort().join() !== 'archiveRoot,cohort,component,exposure,maxUnflagged,seed' || !/^([a-f0-9]{64})$/.test(input.seed) || !Number.isSafeInteger(input.maxUnflagged) || input.maxUnflagged < 0 || input.maxUnflagged > 32 || !Array.isArray(input.cohort) || !input.cohort.length || input.cohort.length > 1024 || new Set(input.cohort.map(c => c.incidentId)).size !== input.cohort.length)
|
|
13
|
-
throw Error('invalid frozen trust cohort');
|
|
14
|
-
for (const c of input.cohort) {
|
|
15
|
-
if (Object.keys(c).sort().join() !== 'flagged,incidentId,manifestId,split' || !text(c.incidentId) || typeof c.flagged !== 'boolean' || !['calibration', 'heldout', 'tuning'].includes(c.split))
|
|
16
|
-
throw Error('invalid cohort row');
|
|
17
|
-
evidence(input.archiveRoot, c.manifestId);
|
|
18
|
-
}
|
|
19
|
-
const dummy = { id: 'validation', incidentId: 'validation', component: input.component, kind: input.component.kind === 'detector' ? 'positive' : 'approval', split: 'calibration' };
|
|
20
|
-
calibratePredictions([dummy]);
|
|
21
|
-
if (input.exposure) {
|
|
22
|
-
if (learningHash(input.exposure.component) !== learningHash(input.component))
|
|
23
|
-
throw Error('policy component scope mismatch');
|
|
24
|
-
const report = calibratePredictions([{ ...dummy, kind: input.exposure.kind, split: input.exposure.split }]).reports[0];
|
|
25
|
-
recommendExposure(report, input.exposure, 0);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
export function createTrustLifecycle(directory, input, authorizedPolicyDigests) {
|
|
29
|
-
const safe = learningCopy(input);
|
|
30
|
-
validate(safe);
|
|
31
|
-
const policyId = trustPolicyDigest(safe);
|
|
32
|
-
if (!authorizedPolicyDigests.includes(policyId))
|
|
33
|
-
throw Error('independent predeclared policy authority required');
|
|
34
|
-
const sampledIncidentIds = safe.cohort.filter(c => !c.flagged && c.split !== 'tuning').sort((a, b) => learningHash([safe.seed, a.incidentId]).localeCompare(learningHash([safe.seed, b.incidentId]))).slice(0, safe.maxUnflagged).map(c => c.incidentId);
|
|
35
|
-
const initial = { type: 'initial', kind: 'trust-lifecycle-v1', input: safe, policyId, sampledIncidentIds };
|
|
36
|
-
registerLearningStore(safe.archiveRoot, 'trust', policyId, directory, learningHash(initial));
|
|
37
|
-
try {
|
|
38
|
-
learningJournal(directory, initial);
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
if (e.code !== 'EEXIST')
|
|
42
|
-
throw e;
|
|
43
|
-
const old = learningJournal(directory).read()[0].value;
|
|
44
|
-
if (learningHash(old) !== learningHash(initial))
|
|
45
|
-
throw Error('trust policy already predeclared');
|
|
46
|
-
}
|
|
47
|
-
return openTrustLifecycle(directory);
|
|
48
|
-
}
|
|
49
|
-
/** Existing calibration is recomputed from durable scoped predictions and independently permitted
|
|
50
|
-
* retained labels. Applied exposure is an attention reservation, not proof a human saw a question. */
|
|
51
|
-
export function openTrustLifecycle(directory) {
|
|
52
|
-
const journal = learningJournal(directory), initial = journal.read()[0].value;
|
|
53
|
-
if (initial.kind !== 'trust-lifecycle-v1' || initial.type !== 'initial')
|
|
54
|
-
throw Error('wrong trust journal');
|
|
55
|
-
const input = initial.input, sampledIncidentIds = initial.sampledIncidentIds;
|
|
56
|
-
validate(input);
|
|
57
|
-
const replay = () => {
|
|
58
|
-
verifyLearningStore(input.archiveRoot, 'trust', String(initial.policyId), directory, learningHash(initial));
|
|
59
|
-
const history = journal.read(), predictions = new Map(), allIds = new Set(), outcomes = new Map(), caseLinks = new Map(), exposures = new Map();
|
|
60
|
-
let retired = false, lastExposureAt = 0;
|
|
61
|
-
for (const { value: v } of history.slice(1)) {
|
|
62
|
-
if (v.type === 'prediction' || v.type === 'correction') {
|
|
63
|
-
const p = v.prediction;
|
|
64
|
-
calibratePredictions([p]);
|
|
65
|
-
if (allIds.has(p.id))
|
|
66
|
-
throw Error('duplicate prediction identity');
|
|
67
|
-
const c = input.cohort.find(c => c.incidentId === p.incidentId);
|
|
68
|
-
if (!c?.flagged || c.split !== p.split || learningHash(p.component) !== learningHash(input.component))
|
|
69
|
-
throw Error('prediction scope mismatch');
|
|
70
|
-
if (v.type === 'correction') {
|
|
71
|
-
const old = predictions.get(String(v.prior));
|
|
72
|
-
if (!old || old.incidentId !== p.incidentId)
|
|
73
|
-
throw Error('stale prediction correction');
|
|
74
|
-
predictions.delete(String(v.prior));
|
|
75
|
-
}
|
|
76
|
-
predictions.set(p.id, p);
|
|
77
|
-
allIds.add(p.id);
|
|
78
|
-
}
|
|
79
|
-
else if (v.type === 'outcome') {
|
|
80
|
-
const r = v.outcome;
|
|
81
|
-
if (outcomes.has(r.referenceId))
|
|
82
|
-
throw Error('duplicate reference identity');
|
|
83
|
-
outcomes.set(r.referenceId, r);
|
|
84
|
-
if (v.caseReference)
|
|
85
|
-
caseLinks.set(r.referenceId, v.caseReference);
|
|
86
|
-
}
|
|
87
|
-
else if (v.type === 'exposure') {
|
|
88
|
-
const id = String(v.id), result = v.result;
|
|
89
|
-
if (typeof v.now !== 'number' || !Number.isFinite(v.now) || v.now < lastExposureAt || exposures.has(id) || !['ask', 'silent', 'retire'].includes(result.mode))
|
|
90
|
-
throw Error('invalid exposure history');
|
|
91
|
-
lastExposureAt = v.now;
|
|
92
|
-
exposures.set(id, result);
|
|
93
|
-
retired ||= result.mode === 'retire';
|
|
94
|
-
}
|
|
95
|
-
else
|
|
96
|
-
throw Error('unknown trust history event');
|
|
97
|
-
}
|
|
98
|
-
return { history, predictions, allIds, outcomes, caseLinks, exposures, retired, lastExposureAt, tip: history.at(-1).id };
|
|
99
|
-
};
|
|
100
|
-
replay();
|
|
101
|
-
const inspect = (now) => {
|
|
102
|
-
if (!Number.isFinite(now) || now < 0)
|
|
103
|
-
throw Error('valid policy clock required');
|
|
104
|
-
const s = replay(), labels = [];
|
|
105
|
-
for (const r of s.outcomes.values()) {
|
|
106
|
-
evidence(input.archiveRoot, r.evidenceManifestId);
|
|
107
|
-
const p = s.predictions.get(r.targetId), link = s.caseLinks.get(r.referenceId);
|
|
108
|
-
if (link && !readLearningCase(input.archiveRoot, link).matched)
|
|
109
|
-
continue;
|
|
110
|
-
if (r.kind === 'prediction' && p)
|
|
111
|
-
labels.push({ ...p, id: r.referenceId, correct: r.value });
|
|
112
|
-
}
|
|
113
|
-
for (const p of s.predictions.values())
|
|
114
|
-
evidence(input.archiveRoot, input.cohort.find(c => c.incidentId === p.incidentId).manifestId);
|
|
115
|
-
const calibration = calibratePredictions([...s.predictions.values()], { outcomes: labels });
|
|
116
|
-
let misses = 0, resolved = 0, conflicted = 0;
|
|
117
|
-
for (const id of sampledIncidentIds) {
|
|
118
|
-
evidence(input.archiveRoot, input.cohort.find(c => c.incidentId === id).manifestId);
|
|
119
|
-
const values = new Set([...s.outcomes.values()].filter(r => r.kind === 'unflagged' && r.targetId === id).map(r => r.value));
|
|
120
|
-
if (values.size === 1) {
|
|
121
|
-
resolved++;
|
|
122
|
-
if (values.has(true))
|
|
123
|
-
misses++;
|
|
124
|
-
}
|
|
125
|
-
else if (values.size > 1)
|
|
126
|
-
conflicted++;
|
|
127
|
-
}
|
|
128
|
-
return { policyId: String(initial.policyId), component: learningCopy(input.component), calibration, sampledIncidentIds: [...sampledIncidentIds], unflagged: { sampled: sampledIncidentIds.length, resolved, misses, unresolved: sampledIncidentIds.length - resolved, conflicted }, attentionUsed: [...s.exposures.values()].filter(e => e.mode === 'ask').length, retired: s.retired, exposures: [...s.exposures].map(([id, result]) => ({ id, ...result })), tip: s.tip, grantExpansion: false };
|
|
129
|
-
};
|
|
130
|
-
const prediction = (p) => { const copy = learningCopy(p); calibratePredictions([copy]); const row = input.cohort.find(c => c.incidentId === copy.incidentId); if (!row?.flagged || row.split !== copy.split || learningHash(copy.component) !== learningHash(input.component))
|
|
131
|
-
throw Error('prediction scope mismatch'); evidence(input.archiveRoot, row.manifestId); return copy; };
|
|
132
|
-
const previewCaseOutcome = (predictionId, reference) => {
|
|
133
|
-
const ref = learningCopy(reference), s = replay(), p = s.predictions.get(predictionId), row = p && input.cohort.find(c => c.incidentId === p.incidentId), resolved = readLearningCase(input.archiveRoot, ref);
|
|
134
|
-
if (!p || p.kind !== 'positive' || row?.manifestId !== ref.manifestId || !resolved.matched || !['confirmed_defect', 'expected_behavior'].includes(resolved.current.disposition) || learningHash(resolved.candidate.detector) !== learningHash({ id: p.component.id, version: p.component.version, population: p.component.population }))
|
|
135
|
-
throw Error('current independent case outcome scope required');
|
|
136
|
-
const outcome = { kind: 'prediction', targetId: p.id, value: resolved.current.disposition === 'confirmed_defect', evidenceManifestId: ref.manifestId, referenceId: ref.decisionId };
|
|
137
|
-
return { outcome, caseReference: ref, digest: learningHash({ outcome, caseReference: ref }), tip: s.tip };
|
|
138
|
-
};
|
|
139
|
-
const previewExposure = (now) => {
|
|
140
|
-
const view = inspect(now), policy = input.exposure ? { ...input.exposure, attentionRemaining: Math.max(0, input.exposure.attentionRemaining - view.attentionUsed) } : null;
|
|
141
|
-
const report = view.calibration.reports.find(r => policy && r.kind === policy.kind && r.split === policy.split);
|
|
142
|
-
return view.retired ? { mode: 'retire', reason: 'previously-retired' } : report ? recommendExposure(report, policy, now) : { mode: 'silent', reason: policy ? 'insufficient-independent-evidence' : 'policy-unavailable' };
|
|
143
|
-
};
|
|
144
|
-
return { inspect, configuration: () => learningCopy(input), previewExposure, history: () => journal.read(), previewCaseOutcome,
|
|
145
|
-
linkCaseOutcome(predictionId, reference, authorizedDigests, referenceAuthor) {
|
|
146
|
-
if (referenceAuthor !== undefined && !text(referenceAuthor))
|
|
147
|
-
throw Error('explicit reference author required');
|
|
148
|
-
const preview = previewCaseOutcome(predictionId, reference);
|
|
149
|
-
if (!authorizedDigests.includes(preview.digest))
|
|
150
|
-
throw Error('independent exact reference authority required');
|
|
151
|
-
const s = replay();
|
|
152
|
-
if (s.tip !== preview.tip)
|
|
153
|
-
throw Error('stale case outcome snapshot');
|
|
154
|
-
const old = s.outcomes.get(preview.outcome.referenceId);
|
|
155
|
-
if (old) {
|
|
156
|
-
if (trustOutcomeDigest(old) !== trustOutcomeDigest(preview.outcome) || learningHash(s.caseLinks.get(old.referenceId) ?? null) !== learningHash(reference))
|
|
157
|
-
throw Error('reference identity conflict');
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
journal.append(s.tip, { type: 'outcome', outcome: preview.outcome, caseReference: preview.caseReference, authorityDigest: preview.digest, ...(referenceAuthor === undefined ? {} : { referenceAuthor }) });
|
|
161
|
-
},
|
|
162
|
-
predict(p) { const safe = prediction(p), s = replay(); if (s.allIds.has(safe.id)) {
|
|
163
|
-
if (learningHash(s.predictions.get(safe.id) ?? null) !== learningHash(safe))
|
|
164
|
-
throw Error('prediction identity conflict');
|
|
165
|
-
return;
|
|
166
|
-
} journal.append(s.tip, { type: 'prediction', prediction: safe }); },
|
|
167
|
-
correct(prior, p, reason) { const safe = prediction(p), s = replay(), old = s.predictions.get(prior); if (!old || old.incidentId !== safe.incidentId || s.allIds.has(safe.id) || !text(reason))
|
|
168
|
-
throw Error('stale or invalid prediction correction'); journal.append(s.tip, { type: 'correction', prior, prediction: safe, reason }); },
|
|
169
|
-
outcome(value, authorizedReferenceDigests, referenceAuthor) {
|
|
170
|
-
if (referenceAuthor !== undefined && !text(referenceAuthor))
|
|
171
|
-
throw Error('explicit reference author required');
|
|
172
|
-
const r = learningCopy(value);
|
|
173
|
-
if (Object.keys(r).sort().join() !== 'evidenceManifestId,kind,referenceId,targetId,value' || !['prediction', 'unflagged'].includes(r.kind) || !text(r.targetId) || !text(r.referenceId) || typeof r.value !== 'boolean')
|
|
174
|
-
throw Error('invalid reference outcome');
|
|
175
|
-
const digest = trustOutcomeDigest(r);
|
|
176
|
-
if (!authorizedReferenceDigests.includes(digest))
|
|
177
|
-
throw Error('independent exact reference authority required');
|
|
178
|
-
evidence(input.archiveRoot, r.evidenceManifestId);
|
|
179
|
-
const s = replay();
|
|
180
|
-
if (r.kind === 'prediction' ? !s.predictions.has(r.targetId) : !sampledIncidentIds.includes(r.targetId))
|
|
181
|
-
throw Error('outcome outside current prediction or frozen sample');
|
|
182
|
-
const old = s.outcomes.get(r.referenceId);
|
|
183
|
-
if (old) {
|
|
184
|
-
if (trustOutcomeDigest(old) !== digest)
|
|
185
|
-
throw Error('reference identity conflict');
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
journal.append(s.tip, { type: 'outcome', outcome: r, authorityDigest: digest, ...(referenceAuthor === undefined ? {} : { referenceAuthor }) });
|
|
189
|
-
},
|
|
190
|
-
expose(id, now) {
|
|
191
|
-
if (!text(id))
|
|
192
|
-
throw Error('exposure identity required');
|
|
193
|
-
const s = replay(), existing = s.exposures.get(id);
|
|
194
|
-
if (existing)
|
|
195
|
-
return { ...learningCopy(existing), replayed: true };
|
|
196
|
-
if (now < s.lastExposureAt)
|
|
197
|
-
throw Error('policy clock moved backwards');
|
|
198
|
-
const view = inspect(now);
|
|
199
|
-
if (view.tip !== s.tip)
|
|
200
|
-
throw Error('stale exposure snapshot');
|
|
201
|
-
const policy = input.exposure ? { ...input.exposure, attentionRemaining: Math.max(0, input.exposure.attentionRemaining - view.attentionUsed) } : null;
|
|
202
|
-
const report = view.calibration.reports.find(r => policy && r.kind === policy.kind && r.split === policy.split);
|
|
203
|
-
const result = s.retired ? { mode: 'retire', reason: 'previously-retired' } : report ? recommendExposure(report, policy, now) : { mode: 'silent', reason: policy ? 'insufficient-independent-evidence' : 'policy-unavailable' };
|
|
204
|
-
journal.append(s.tip, { type: 'exposure', id, now, result, policyId: initial.policyId, evidenceTip: s.tip });
|
|
205
|
-
return { ...learningCopy(result), replayed: false };
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
//# sourceMappingURL=trust-lifecycle.js.map
|