@skill-harness/adapters 0.15.0 → 0.17.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.
@@ -1,6 +1,11 @@
1
1
  import { type BlindQualityChoice, type InterventionManifest, type InterventionEvidence, type InterventionQualification } from "@skill-harness/core";
2
2
  /** Explicit private retention. Host role declarations are NOT authentication. No provider is called. */
3
3
  export declare function retainBlindIntervention(root: string, manifest: InterventionManifest, evidence: InterventionEvidence[], qualification: InterventionQualification, author: string): string;
4
+ /** Opaque linkage metadata only; never exposes roles, arm identities or cost before choice. */
5
+ export declare function readBlindInterventionBinding(root: string, id: string, author: string): Readonly<{
6
+ experimentDigest: string;
7
+ investigationDigest: string;
8
+ }>;
4
9
  /** One immutable quality choice per comparison. Reopening cannot reset the reveal gate. */
5
10
  export declare function openBlindIntervention(root: string, id: string, author: string): Readonly<{
6
11
  view: () => {
@@ -12,6 +17,7 @@ export declare function openBlindIntervention(root: string, id: string, author:
12
17
  limitations: string[];
13
18
  };
14
19
  quality(): BlindQualityChoice | null;
20
+ previewChoice(input: BlindQualityChoice): BlindQualityChoice;
15
21
  readArtifact: (label: string, hash: string) => Buffer<ArrayBuffer>;
16
22
  choose(input: BlindQualityChoice): BlindQualityChoice;
17
23
  reveal(): {
@@ -90,7 +90,13 @@ function load(root, id, author) {
90
90
  throw new Error("blind artifact unavailable");
91
91
  artifacts.set(ref.hash, artifact.bytes);
92
92
  }
93
- return createBlindComparison(bundle.manifest, assessIntervention(bundle.manifest, bundle.evidence, { ...bundle.qualification, artifacts }), bundle.seed);
93
+ const assessment = assessIntervention(bundle.manifest, bundle.evidence, { ...bundle.qualification, artifacts });
94
+ return { blind: createBlindComparison(bundle.manifest, assessment, bundle.seed), manifest: bundle.manifest };
95
+ }
96
+ /** Opaque linkage metadata only; never exposes roles, arm identities or cost before choice. */
97
+ export function readBlindInterventionBinding(root, id, author) {
98
+ const { manifest } = load(root, id, author);
99
+ return Object.freeze({ experimentDigest: manifest.id, investigationDigest: manifest.investigationSha256 });
94
100
  }
95
101
  function directory(path) {
96
102
  const s = lstatSync(path);
@@ -159,10 +165,11 @@ function readChoice(root, id) {
159
165
  export function openBlindIntervention(root, id, author) {
160
166
  if (!SHA.test(id))
161
167
  throw new Error("invalid blind comparison identity");
162
- const current = () => load(root, id, author);
168
+ const current = () => load(root, id, author).blind;
163
169
  return Object.freeze({
164
170
  view: () => current().view(),
165
171
  quality() { const blind = current(), choice = readChoice(root, id); return choice ? blind.choose(choice) : null; },
172
+ previewChoice(input) { return current().choose(input); },
166
173
  readArtifact: (label, hash) => current().readArtifact(label, hash),
167
174
  choose(input) {
168
175
  const blind = current(), choice = blind.choose(input);
@@ -36,6 +36,14 @@ export declare function retainArchiveSource(root: string, input: ArchiveSourceIn
36
36
  manifestId: string;
37
37
  reference: ArchiveSourceReference;
38
38
  };
39
+ export type ArchiveReferenceRead = {
40
+ status: 'available';
41
+ reference: ArchiveSourceReference;
42
+ } | Exclude<ArchiveRead, {
43
+ status: 'available';
44
+ }>;
45
+ /** Metadata only for explicit archive inventory. Does not claim content availability. */
46
+ export declare function readArchiveSourceReference(root: string, manifestId: string): ArchiveReferenceRead;
39
47
  export declare function readArchiveSource(root: string, manifestId: string, maxBytes?: number): ArchiveRead;
40
48
  export interface ArchivedJsonl {
41
49
  status: "complete" | "partial" | "error";
@@ -149,27 +149,31 @@ export function retainArchiveSource(root, input) {
149
149
  syncDirectory(resolve(root));
150
150
  return { manifestId, reference };
151
151
  }
152
- export function readArchiveSource(root, manifestId, maxBytes = LIMIT) {
153
- if (!Number.isSafeInteger(maxBytes) || maxBytes < 0 || maxBytes > LIMIT)
154
- return { status: "error", reason: "invalid read bound" };
152
+ /** Metadata only for explicit archive inventory. Does not claim content availability. */
153
+ export function readArchiveSourceReference(root, manifestId) {
155
154
  if (!HASH.test(manifestId))
156
- return { status: "error", reason: "invalid manifest identity" };
155
+ return { status: 'error', reason: 'invalid manifest identity' };
157
156
  try {
158
- let manifest;
159
- try {
160
- directory(root, false);
161
- directory(join(root, "manifests"), false);
162
- manifest = readVerified(join(root, "manifests", manifestId), manifestId, 8192);
163
- }
164
- catch (error) {
165
- if (absent(error))
166
- return { status: "missing", reason: "manifest" };
167
- throw error;
168
- }
169
- const text = manifest.toString("utf8");
157
+ directory(root, false);
158
+ directory(join(root, 'manifests'), false);
159
+ const text = readVerified(join(root, 'manifests', manifestId), manifestId, 8192).toString('utf8');
170
160
  const reference = JSON.parse(text);
171
161
  if (!validReference(reference) || JSON.stringify(reference) !== text)
172
- fail("invalid manifest");
162
+ fail('invalid manifest');
163
+ return { status: 'available', reference };
164
+ }
165
+ catch (error) {
166
+ return absent(error) ? { status: 'missing', reason: 'manifest' } : { status: 'error', reason: 'invalid or inaccessible retained evidence' };
167
+ }
168
+ }
169
+ export function readArchiveSource(root, manifestId, maxBytes = LIMIT) {
170
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 0 || maxBytes > LIMIT)
171
+ return { status: "error", reason: "invalid read bound" };
172
+ try {
173
+ const manifest = readArchiveSourceReference(root, manifestId);
174
+ if (manifest.status !== 'available')
175
+ return manifest;
176
+ const { reference } = manifest;
173
177
  if (reference.retention === "reference-only")
174
178
  return { status: "missing", reason: "not-retained" };
175
179
  if (reference.bytes > maxBytes)
package/dist/index.d.ts CHANGED
@@ -19,6 +19,10 @@ export * from "./archive-read-capability.js";
19
19
  export * from "./archived-work.js";
20
20
  export * from "./blind-intervention.js";
21
21
  export * from "./learning-lifecycle.js";
22
+ export * from "./learning-workspace.js";
23
+ export * from "./learning-trust-setup.js";
24
+ export { learningHash, learningFile } from "./learning-journal.js";
25
+ export * from "./learning-case.js";
22
26
  export * from "./archive-observer.js";
23
27
  export * from "./weekly-investigation.js";
24
28
  export * from "./intervention-run.js";
@@ -28,3 +32,5 @@ export * from "./archive-access.js";
28
32
  export * from "./archive-facts.js";
29
33
  export * from "./trust-lifecycle.js";
30
34
  export * from "./producer-review.js";
35
+ export * from './session-observation.js';
36
+ export * from './session-retention.js';
package/dist/index.js CHANGED
@@ -31,6 +31,10 @@ export * from "./archive-read-capability.js";
31
31
  export * from "./archived-work.js";
32
32
  export * from "./blind-intervention.js";
33
33
  export * from "./learning-lifecycle.js";
34
+ export * from "./learning-workspace.js";
35
+ export * from "./learning-trust-setup.js";
36
+ export { learningHash, learningFile } from "./learning-journal.js";
37
+ export * from "./learning-case.js";
34
38
  export * from "./archive-observer.js";
35
39
  export * from "./weekly-investigation.js";
36
40
  export * from "./intervention-run.js";
@@ -40,4 +44,6 @@ export * from "./archive-access.js";
40
44
  export * from "./archive-facts.js";
41
45
  export * from "./trust-lifecycle.js";
42
46
  export * from "./producer-review.js";
47
+ export * from './session-observation.js';
48
+ export * from './session-retention.js';
43
49
  //# sourceMappingURL=index.js.map
@@ -14,5 +14,5 @@ export declare function learningJournal(path: string, initial?: Record<string, u
14
14
  append(prior: string, value: Record<string, unknown>): LearningEvent;
15
15
  };
16
16
  /** One authoritative store per weekly key/policy in this archive; a renamed directory cannot refill it. */
17
- export declare function registerLearningStore(root: string, kind: 'weekly' | 'trust' | 'intervention' | 'access', key: string, target: string, binding: string): void;
18
- export declare function verifyLearningStore(root: string, kind: 'weekly' | 'trust' | 'intervention' | 'access', key: string, target: string, binding: string): void;
17
+ export declare function registerLearningStore(root: string, kind: 'weekly' | 'trust' | 'intervention' | 'access' | 'workspace', key: string, target: string, binding: string): void;
18
+ export declare function verifyLearningStore(root: string, kind: 'weekly' | 'trust' | 'intervention' | 'access' | 'workspace', key: string, target: string, binding: string): void;
@@ -214,7 +214,7 @@ export function learningJournal(path, initial) {
214
214
  }
215
215
  /** One authoritative store per weekly key/policy in this archive; a renamed directory cannot refill it. */
216
216
  export function registerLearningStore(root, kind, key, target, binding) {
217
- if (!/^[a-f0-9]{64}$/.test(key) || !isAbsolute(target) || !['weekly', 'trust', 'intervention', 'access'].includes(kind))
217
+ if (!/^[a-f0-9]{64}$/.test(key) || !isAbsolute(target) || !['weekly', 'trust', 'intervention', 'access', 'workspace'].includes(kind))
218
218
  throw Error('invalid learning registration');
219
219
  directory(root);
220
220
  directory(dirname(target));
@@ -0,0 +1,64 @@
1
+ import type { CalibrationPrediction, CalibrationSplit, ExposurePolicy } from '@skill-harness/core';
2
+ import type { LearningCaseReference } from './learning-case.js';
3
+ import { type TrustLifecycleInput } from './trust-lifecycle.js';
4
+ export interface LearningTrustSetup {
5
+ caseName: string;
6
+ detectorId: string;
7
+ split: CalibrationSplit;
8
+ maxUnflagged: number;
9
+ unflagged: {
10
+ incidentId: string;
11
+ manifestId: string;
12
+ split: CalibrationSplit;
13
+ }[];
14
+ exposure: Omit<ExposurePolicy, 'component' | 'kind' | 'split'> | null;
15
+ }
16
+ /** Forms construct a frozen cohort from actual selected cases. Repeated observations of the
17
+ * same target are ONE incident; a detector nomination never becomes its own reference label. */
18
+ export declare function previewLearningTrust(directory: string, raw: LearningTrustSetup): {
19
+ input: TrustLifecycleInput;
20
+ policyDigest: string;
21
+ predictions: CalibrationPrediction[];
22
+ nominationCount: number;
23
+ independentIncidentCount: number;
24
+ caseManifestIds: string[];
25
+ labelsCreated: 0;
26
+ excludedOtherDetectors: number;
27
+ };
28
+ export declare function configureLearningTrust(directory: string, options: LearningTrustSetup, authorizedPolicyDigests: readonly string[]): {
29
+ policyId: string;
30
+ component: import("@skill-harness/core").CalibrationComponent;
31
+ calibration: {
32
+ version: "factory-calibration-v1";
33
+ reports: import("@skill-harness/core").CalibrationReport[];
34
+ excludedTuning: number;
35
+ referenceBasis: "independently-supplied-host-context";
36
+ advisoryOnly: true;
37
+ };
38
+ sampledIncidentIds: string[];
39
+ unflagged: {
40
+ sampled: number;
41
+ resolved: number;
42
+ misses: number;
43
+ unresolved: number;
44
+ conflicted: number;
45
+ };
46
+ attentionUsed: number;
47
+ retired: boolean;
48
+ exposures: {
49
+ mode: "ask" | "silent" | "retire";
50
+ reason: string;
51
+ id: string;
52
+ }[];
53
+ tip: string;
54
+ grantExpansion: false;
55
+ };
56
+ /** Selected case reference, not a retyped verdict. Separate explicit reference authority is
57
+ * still required by linkCaseOutcome; this only supplies the exact preview to the operator. */
58
+ export declare function previewLearningCaseLabel(directory: string, reference: LearningCaseReference): {
59
+ outcome: import("./trust-lifecycle.js").TrustReferenceOutcome;
60
+ caseReference: LearningCaseReference;
61
+ digest: string;
62
+ tip: string;
63
+ predictionId: string;
64
+ };
@@ -0,0 +1,55 @@
1
+ import { learningCopy, learningHash } from './learning-journal.js';
2
+ import { openLearningWorkspace } from './learning-workspace.js';
3
+ import { trustPolicyDigest } from './trust-lifecycle.js';
4
+ /** Forms construct a frozen cohort from actual selected cases. Repeated observations of the
5
+ * same target are ONE incident; a detector nomination never becomes its own reference label. */
6
+ export function previewLearningTrust(directory, raw) {
7
+ const options = learningCopy(raw), workspace = openLearningWorkspace(directory), config = workspace.configuration();
8
+ if (Object.keys(options).sort().join() !== 'caseName,detectorId,exposure,maxUnflagged,split,unflagged' || !['calibration', 'heldout', 'tuning'].includes(options.split) || !Array.isArray(options.unflagged) || options.unflagged.length > 1024)
9
+ throw Error('closed trust setup required');
10
+ const page = workspace.cases(options.caseName), items = [...page.items];
11
+ for (let offset = 5; offset < page.total; offset += 5)
12
+ items.push(...workspace.cases(options.caseName, offset).items);
13
+ const chosen = items.filter(c => c.candidate.detector.id === options.detectorId);
14
+ if (!chosen.length)
15
+ throw Error('selected detector has no retained cases');
16
+ const component = { kind: 'detector', ...chosen[0].candidate.detector };
17
+ if (chosen.some(c => learningHash(c.candidate.detector) !== learningHash(chosen[0].candidate.detector)))
18
+ throw Error('detector versions/populations must be calibrated separately');
19
+ const binding = workspace.inspect(0).cases.find(b => b.name === options.caseName);
20
+ if (!binding || binding.state !== 'ready')
21
+ throw Error('case binding unavailable');
22
+ const incidents = new Map();
23
+ for (const c of chosen) {
24
+ const id = learningHash({ target: c.candidate.target, population: component.population });
25
+ if (!incidents.has(id))
26
+ incidents.set(id, c);
27
+ }
28
+ const cohort = [...[...incidents].map(([incidentId, c]) => ({ incidentId, manifestId: c.caseManifestId, flagged: true, split: options.split })), ...options.unflagged.map(c => ({ ...c, flagged: false }))];
29
+ const input = { archiveRoot: config.archiveRoot, component, seed: learningHash({ scope: config.scopeDigest, component, cohort }), maxUnflagged: options.maxUnflagged, cohort,
30
+ exposure: options.exposure ? { ...options.exposure, component, kind: 'positive', split: options.split === 'tuning' ? 'calibration' : options.split } : null };
31
+ const predictions = [...incidents].map(([incidentId]) => ({ id: learningHash({ incidentId, component, split: options.split }), incidentId, component, kind: 'positive', split: options.split }));
32
+ return { input, policyDigest: trustPolicyDigest(input), predictions, nominationCount: chosen.length, independentIncidentCount: incidents.size,
33
+ caseManifestIds: [...incidents.values()].map(c => c.caseManifestId), labelsCreated: 0, excludedOtherDetectors: items.length - chosen.length };
34
+ }
35
+ export function configureLearningTrust(directory, options, authorizedPolicyDigests) {
36
+ const preview = previewLearningTrust(directory, options), workspace = openLearningWorkspace(directory);
37
+ workspace.configureTrust(preview.input, authorizedPolicyDigests);
38
+ for (const p of preview.predictions)
39
+ workspace.trust().predict(p);
40
+ return workspace.trust().inspect(0);
41
+ }
42
+ /** Selected case reference, not a retyped verdict. Separate explicit reference authority is
43
+ * still required by linkCaseOutcome; this only supplies the exact preview to the operator. */
44
+ export function previewLearningCaseLabel(directory, reference) {
45
+ const trust = openLearningWorkspace(directory).trust(), config = trust.configuration();
46
+ const row = config.cohort.find(c => c.flagged && c.manifestId === reference.manifestId);
47
+ if (!row)
48
+ throw Error('case outside frozen calibration cohort');
49
+ const predictions = trust.history().filter(e => e.value.type === 'prediction' || e.value.type === 'correction').map(e => e.value.prediction);
50
+ const p = predictions.filter(p => p.incidentId === row.incidentId).at(-1);
51
+ if (!p)
52
+ throw Error('prediction missing');
53
+ return { predictionId: p.id, ...trust.previewCaseOutcome(p.id, reference) };
54
+ }
55
+ //# sourceMappingURL=learning-trust-setup.js.map