@skill-harness/adapters 0.17.0 → 0.19.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.
Files changed (121) hide show
  1. package/dist/index.d.ts +0 -30
  2. package/dist/index.js +0 -30
  3. package/dist/model-pricing.d.ts +3 -0
  4. package/dist/model-pricing.js +24 -0
  5. package/dist/pi.js +26 -135
  6. package/package.json +5 -4
  7. package/prices/model-prices.json +43 -0
  8. package/dist/archive-access.d.ts +0 -58
  9. package/dist/archive-access.js +0 -61
  10. package/dist/archive-checkpoint.d.ts +0 -47
  11. package/dist/archive-checkpoint.js +0 -116
  12. package/dist/archive-facts.d.ts +0 -19
  13. package/dist/archive-facts.js +0 -20
  14. package/dist/archive-observer.d.ts +0 -21
  15. package/dist/archive-observer.js +0 -79
  16. package/dist/archive-policy.d.ts +0 -107
  17. package/dist/archive-policy.js +0 -135
  18. package/dist/archive-read-capability.d.ts +0 -49
  19. package/dist/archive-read-capability.js +0 -45
  20. package/dist/archive-retention-policy.d.ts +0 -52
  21. package/dist/archive-retention-policy.js +0 -49
  22. package/dist/archived-work.d.ts +0 -45
  23. package/dist/archived-work.js +0 -78
  24. package/dist/blind-intervention.d.ts +0 -35
  25. package/dist/blind-intervention.js +0 -218
  26. package/dist/codex-diagnostic-model.d.ts +0 -14
  27. package/dist/codex-diagnostic-model.js +0 -39
  28. package/dist/codex-host-observer.d.ts +0 -111
  29. package/dist/codex-host-observer.js +0 -309
  30. package/dist/codex-https.d.ts +0 -7
  31. package/dist/codex-https.js +0 -221
  32. package/dist/codex-model-profile.d.ts +0 -38
  33. package/dist/codex-model-profile.js +0 -54
  34. package/dist/codex-producer-ipc.d.ts +0 -55
  35. package/dist/codex-producer-ipc.js +0 -67
  36. package/dist/codex-sdk-transport.d.ts +0 -50
  37. package/dist/codex-sdk-transport.js +0 -294
  38. package/dist/codex-subscription.d.ts +0 -114
  39. package/dist/codex-subscription.js +0 -268
  40. package/dist/evidence-archive.d.ts +0 -65
  41. package/dist/evidence-archive.js +0 -225
  42. package/dist/execution-projection-schema.d.ts +0 -10
  43. package/dist/execution-projection-schema.js +0 -30
  44. package/dist/execution-retention-archive.d.ts +0 -69
  45. package/dist/execution-retention-archive.js +0 -154
  46. package/dist/generated/retention-v2-contract.d.ts +0 -72
  47. package/dist/generated/retention-v2-contract.js +0 -105
  48. package/dist/generated/retention-v2-json.d.ts +0 -24
  49. package/dist/generated/retention-v2-json.js +0 -268
  50. package/dist/generated/retention-v2-native-json.d.ts +0 -2
  51. package/dist/generated/retention-v2-native-json.js +0 -33
  52. package/dist/generated/retention-v2-native.d.ts +0 -58
  53. package/dist/generated/retention-v2-native.js +0 -155
  54. package/dist/generated/retention-v2-pin.d.ts +0 -2
  55. package/dist/generated/retention-v2-pin.js +0 -4
  56. package/dist/generated/retention-v2-types.d.ts +0 -49
  57. package/dist/generated/retention-v2-types.js +0 -2
  58. package/dist/generated/retention-v2-work-types.d.ts +0 -260
  59. package/dist/generated/retention-v2-work-types.js +0 -13
  60. package/dist/generated/work-v4/execution-id.d.ts +0 -5
  61. package/dist/generated/work-v4/execution-id.js +0 -14
  62. package/dist/generated/work-v4/json.d.ts +0 -24
  63. package/dist/generated/work-v4/json.js +0 -268
  64. package/dist/generated/work-v4/occurrences.d.ts +0 -226
  65. package/dist/generated/work-v4/occurrences.js +0 -116
  66. package/dist/generated/work-v4/pin.d.ts +0 -1
  67. package/dist/generated/work-v4/pin.js +0 -3
  68. package/dist/generated/work-v4/projection.d.ts +0 -294
  69. package/dist/generated/work-v4/projection.js +0 -238
  70. package/dist/generated/work-v4/reader.d.ts +0 -24
  71. package/dist/generated/work-v4/reader.js +0 -109
  72. package/dist/generated/work-v4/snapshot.d.ts +0 -28
  73. package/dist/generated/work-v4/snapshot.js +0 -268
  74. package/dist/generated/work-v4/types.d.ts +0 -260
  75. package/dist/generated/work-v4/types.js +0 -13
  76. package/dist/generated/work-v4/validation.d.ts +0 -13
  77. package/dist/generated/work-v4/validation.js +0 -227
  78. package/dist/installed-review-session.d.ts +0 -28
  79. package/dist/installed-review-session.js +0 -166
  80. package/dist/intervention-run.d.ts +0 -403
  81. package/dist/intervention-run.js +0 -169
  82. package/dist/learning-case.d.ts +0 -12
  83. package/dist/learning-case.js +0 -15
  84. package/dist/learning-journal.d.ts +0 -18
  85. package/dist/learning-journal.js +0 -256
  86. package/dist/learning-lifecycle.d.ts +0 -28
  87. package/dist/learning-lifecycle.js +0 -66
  88. package/dist/learning-trust-setup.d.ts +0 -64
  89. package/dist/learning-trust-setup.js +0 -55
  90. package/dist/learning-workspace.d.ts +0 -1084
  91. package/dist/learning-workspace.js +0 -705
  92. package/dist/principal-payload-port.d.ts +0 -25
  93. package/dist/principal-payload-port.js +0 -40
  94. package/dist/producer-product.d.ts +0 -70
  95. package/dist/producer-product.js +0 -186
  96. package/dist/producer-review.d.ts +0 -53
  97. package/dist/producer-review.js +0 -207
  98. package/dist/prompt-capture-extension.d.ts +0 -10
  99. package/dist/prompt-capture-extension.js +0 -26
  100. package/dist/prompt-provenance.d.ts +0 -22
  101. package/dist/prompt-provenance.js +0 -146
  102. package/dist/reviewed-archive-export.d.ts +0 -42
  103. package/dist/reviewed-archive-export.js +0 -78
  104. package/dist/session-observation.d.ts +0 -50
  105. package/dist/session-observation.js +0 -186
  106. package/dist/session-retention.d.ts +0 -48
  107. package/dist/session-retention.js +0 -121
  108. package/dist/trust-lifecycle.d.ts +0 -152
  109. package/dist/trust-lifecycle.js +0 -209
  110. package/dist/weekly-investigation.d.ts +0 -237
  111. package/dist/weekly-investigation.js +0 -330
  112. package/dist/work-candidates.d.ts +0 -29
  113. package/dist/work-candidates.js +0 -78
  114. package/dist/work-case-archive.d.ts +0 -25
  115. package/dist/work-case-archive.js +0 -63
  116. package/dist/work-case-review.d.ts +0 -45
  117. package/dist/work-case-review.js +0 -220
  118. package/dist/work-signal-cases.d.ts +0 -15
  119. package/dist/work-signal-cases.js +0 -54
  120. package/dist/work-signal-observation.d.ts +0 -23
  121. package/dist/work-signal-observation.js +0 -89
@@ -1,78 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { buildWorkCapture } from "@skill-harness/core";
3
- export const WORK_CANDIDATE_IMPLEMENTATION = "structural-work-v2";
4
- const hash = /^[a-f0-9]{64}$/;
5
- /** Consumes the actual P01 host projection, not arbitrary native wire or a new acceptance authority. */
6
- export function detectWorkCandidates(work, options) {
7
- if (![options.version, options.population].every(s => typeof s === "string" && s.length > 0 && s.length <= 128 && !/[\u0000-\u001f\u007f]/.test(s))
8
- || !Array.isArray(options.expectedWaits) || !Array.isArray(options.expectedFailures)
9
- || options.expectedWaits.length > 4096 || options.expectedFailures.length > 4096
10
- || options.expectedFailures.some(id => typeof id !== "string" || !id || id.length > 512)
11
- || !Number.isSafeInteger(options.minEquivalentAttempts) || options.minEquivalentAttempts < 2 || options.minEquivalentAttempts > 256
12
- || !hash.test(options.scopeDigest) || options.expectedWaits.some(d => !hash.test(d))
13
- || (options.exemplar && (!Number.isFinite(options.exemplar.maximum) || options.exemplar.maximum < 0)))
14
- throw new Error("invalid structural detector policy");
15
- if (work.selectedSnapshot && work.selectedSnapshot.digest !== options.scopeDigest)
16
- throw new Error("detector scope mismatch");
17
- if (work.scopeState !== "valid" || !work.selectedSnapshot || !work.runtime || work.errors.length) {
18
- return { version: "work-candidates-v1", cases: [], issues: ["work-scope-not-resolved"], expected: [] };
19
- }
20
- const policyDigest = createHash("sha256").update(JSON.stringify({ minEquivalentAttempts: options.minEquivalentAttempts, exemplar: options.exemplar ? { unit: options.exemplar.unit, maximum: options.exemplar.maximum } : null })).digest("hex");
21
- const version = `${WORK_CANDIDATE_IMPLEMENTATION}:${options.version}:${policyDigest}`;
22
- const cases = [], expected = [];
23
- const waits = new Set(options.expectedWaits), expectedFailures = new Set(options.expectedFailures);
24
- const occurrences = work.runtime.occurrences;
25
- for (const obligation of work.obligations) {
26
- const ref = obligation.binding.obligation;
27
- const target = { kind: "work", snapshotDigest: work.selectedSnapshot.digest, obligationId: ref.id, obligationDigest: ref.digest };
28
- const evidence = [target.snapshotDigest, target.obligationDigest];
29
- const add = (reason, classification, metrics, refs = evidence) => {
30
- cases.push(buildWorkCapture({ detector: { id: reason, version, population: options.population }, target, reason, classification, metrics, evidence: refs }));
31
- };
32
- if (waits.has(ref.digest)) {
33
- expected.push(`declared-wait:${ref.digest}`);
34
- continue;
35
- }
36
- if (obligation.acceptance === "unresolved" || obligation.artifactCoverage.state !== "available" || obligation.evidenceCoverage.state !== "available" || obligation.problems.some(problem => problem.code !== "TRUSTED_REJECTION")) {
37
- add("coverage_gap", "coverage_issue", {});
38
- continue;
39
- }
40
- for (const attempt of work.runtime.attempts)
41
- if (expectedFailures.has(attempt.executionId) && attempt.bindings.some(b => b.obligation.digest === ref.digest))
42
- expected.push(`expected-failure:${attempt.executionId}`);
43
- const attempts = work.runtime.attempts.filter(attempt => attempt.resolution === "resolved"
44
- && !expectedFailures.has(attempt.executionId)
45
- && attempt.bindings.some(b => b.obligation.id === ref.id && b.obligation.digest === ref.digest)
46
- && occurrences.some(o => o.payload.executionId === attempt.executionId && o.payload.obligation.id === ref.id && o.payload.obligation.digest === ref.digest
47
- && o.payload.provenance === "observed" && ["completed", "failed"].includes(o.payload.state)));
48
- if (obligation.acceptance === "accepted-under-supplied-authority") {
49
- if (!work.authoritySnapshot || !options.exemplar || !attempts.length)
50
- continue;
51
- const usage = attempts.map(a => options.usage?.[a.executionId]);
52
- if (usage.some(u => !u || !u.observed || u.unit !== options.exemplar.unit || !Number.isFinite(u.cost) || u.cost < 0 || !hash.test(u.evidence)))
53
- continue;
54
- const measuredCost = usage.reduce((sum, u) => sum + u.cost, 0);
55
- if (measuredCost <= options.exemplar.maximum)
56
- add("economical_exemplar", "candidate_exemplar", { measuredCost, costLimit: options.exemplar.maximum, costUnit: options.exemplar.unit }, [...evidence, ...usage.map(u => u.evidence)]);
57
- continue;
58
- }
59
- const groups = new Map();
60
- for (const attempt of attempts) {
61
- const config = attempt.effectiveLabels.configurationDigest;
62
- if (!config || !hash.test(config) || !attempt.observedLabels.some(label => label.configurationDigest === config))
63
- continue;
64
- const bindings = attempt.bindings.filter(b => b.obligation.id === ref.id && b.obligation.digest === ref.digest);
65
- const bindingKeys = bindings.map(b => JSON.stringify({ variants: [...b.variantIds].sort(), artifacts: b.artifacts.map(a => a.digest).sort() })).sort();
66
- const key = JSON.stringify([config, attempt.effectiveLabels.modelId, attempt.effectiveLabels.effortId, bindingKeys]);
67
- groups.set(key, [...(groups.get(key) ?? []), attempt]);
68
- }
69
- const strongest = [...groups].sort(([ka, a], [kb, b]) => b.length - a.length || (ka < kb ? -1 : ka > kb ? 1 : 0))[0]?.[1] ?? [];
70
- const ids = new Set(strongest.map(a => a.executionId));
71
- if (ids.size >= options.minEquivalentAttempts) {
72
- const refs = occurrences.filter(o => ids.has(o.payload.executionId) && o.payload.obligation.id === ref.id && o.payload.obligation.digest === ref.digest).map(o => o.event.digest);
73
- add("repeat_without_progress", "candidate_defect", { equivalentAttempts: ids.size }, [...evidence, ...refs]);
74
- }
75
- }
76
- return { version: "work-candidates-v1", cases: cases.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0), issues: [], expected: expected.sort() };
77
- }
78
- //# sourceMappingURL=work-candidates.js.map
@@ -1,25 +0,0 @@
1
- import { type WorkCaptureCaseV2 } from "@skill-harness/core";
2
- import { type WorkDetectionOptions } from "./work-candidates.js";
3
- import type { WorkProjection } from "./generated/retention-v2-work-types.js";
4
- /** Explicit private archival, never promotion into a scored specification or automatic alert exposure. */
5
- export declare function retainWorkCandidate(root: string, candidate: WorkCaptureCaseV2): string;
6
- export declare function readWorkCandidate(root: string, manifestId: string): WorkCaptureCaseV2;
7
- /** Capture the actual trusted P01 projection before retaining advisory cases; never a worker callback. */
8
- export declare function captureWorkCandidates(root: string, work: WorkProjection, options: WorkDetectionOptions): {
9
- batchId: string;
10
- observationId: string;
11
- candidateIds: string[];
12
- };
13
- /** Several observations/detector versions of the same scoped work are not independent incidents. */
14
- export declare function groupWorkIncidents(cases: readonly WorkCaptureCaseV2[]): {
15
- key: string;
16
- target: {
17
- kind: "work";
18
- snapshotDigest: string;
19
- obligationId: string;
20
- obligationDigest: string;
21
- };
22
- observations: WorkCaptureCaseV2[];
23
- status: "unresolved";
24
- visibility: "silent";
25
- }[];
@@ -1,63 +0,0 @@
1
- import { buildWorkCapture } from "@skill-harness/core";
2
- import { readArchiveSource, retainArchiveSource } from "./evidence-archive.js";
3
- import { detectWorkCandidates } from "./work-candidates.js";
4
- function validate(value) {
5
- if (!value || value.capture_schema !== 2 || value.status !== "unresolved" || value.visibility !== "silent" || value.causalAttribution !== "not-established")
6
- throw new Error("invalid work case state");
7
- const built = buildWorkCapture({ detector: value.detector, target: value.target, classification: value.classification,
8
- reason: value.reason, evidence: value.evidence, metrics: value.metrics });
9
- if (built.id !== value.id || Object.keys(value).sort().join() !== Object.keys(built).sort().join())
10
- throw new Error("invalid work case identity");
11
- return built;
12
- }
13
- /** Explicit private archival, never promotion into a scored specification or automatic alert exposure. */
14
- export function retainWorkCandidate(root, candidate) {
15
- const value = validate(candidate);
16
- return retainArchiveSource(root, { sourceId: `work-case-${value.id}`, parser: { id: "work-capture", version: "2" }, retention: "exact", bytes: Buffer.from(JSON.stringify(value)) }).manifestId;
17
- }
18
- export function readWorkCandidate(root, manifestId) {
19
- const source = readArchiveSource(root, manifestId);
20
- if (source.status !== "available" || source.reference.retention !== "exact" || source.reference.parser.id !== "work-capture" || source.reference.parser.version !== "2")
21
- throw new Error("work case missing or invalid");
22
- const value = validate(JSON.parse(source.bytes.toString("utf8")));
23
- if (source.reference.sourceId !== `work-case-${value.id}`)
24
- throw new Error("work case source mismatch");
25
- return value;
26
- }
27
- /** Capture the actual trusted P01 projection before retaining advisory cases; never a worker callback. */
28
- export function captureWorkCandidates(root, work, options) {
29
- const detection = detectWorkCandidates(work, options);
30
- const observation = retainArchiveSource(root, {
31
- sourceId: `work-facts-${options.scopeDigest}`, parser: { id: "pi-daddy-work-projection", version: "1" },
32
- retention: "exact", bytes: Buffer.from(JSON.stringify(work)),
33
- });
34
- const candidates = detection.cases.map(candidate => buildWorkCapture({
35
- detector: candidate.detector, target: candidate.target, classification: candidate.classification,
36
- reason: candidate.reason, metrics: candidate.metrics, evidence: [...candidate.evidence, observation.reference.sha256],
37
- }));
38
- const candidateIds = candidates.map(candidate => retainWorkCandidate(root, candidate));
39
- const batch = { version: "work-candidate-batch-v1", observationId: observation.manifestId, candidateIds,
40
- issues: detection.issues, expected: detection.expected, visibility: "silent", promotion: "not-authorized" };
41
- const stored = retainArchiveSource(root, { sourceId: `case-batch-${options.scopeDigest}`, parser: { id: "work-candidate-batch", version: "1" },
42
- retention: "exact", bytes: Buffer.from(JSON.stringify(batch)) });
43
- return { batchId: stored.manifestId, observationId: observation.manifestId, candidateIds };
44
- }
45
- /** Several observations/detector versions of the same scoped work are not independent incidents. */
46
- export function groupWorkIncidents(cases) {
47
- if (cases.length > 4096)
48
- throw new Error("work incident snapshot exceeds bound");
49
- const groups = new Map();
50
- for (const raw of cases) {
51
- const c = validate(raw);
52
- const key = JSON.stringify([c.target.snapshotDigest, c.target.obligationId, c.target.obligationDigest, c.detector.population]);
53
- const values = groups.get(key) ?? [];
54
- if (!values.some(v => v.id === c.id && JSON.stringify(v) === JSON.stringify(c)))
55
- values.push(c);
56
- groups.set(key, values);
57
- }
58
- return [...groups].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, values]) => ({
59
- key, target: values[0].target, observations: values.sort((a, b) => { const left = JSON.stringify(a), right = JSON.stringify(b); return left < right ? -1 : left > right ? 1 : 0; }),
60
- status: "unresolved", visibility: "silent",
61
- }));
62
- }
63
- //# sourceMappingURL=work-case-archive.js.map
@@ -1,45 +0,0 @@
1
- import { type WorkCaseDecision, type WorkCaseDisposition } from "@skill-harness/core";
2
- export interface WorkCaseReviewRequest {
3
- caseManifestId: string;
4
- priorDecisionId: string | null;
5
- disposition: WorkCaseDisposition;
6
- note: string;
7
- }
8
- /** Operator-selected batch/author capability. Not user authentication, worker authority or scenario promotion. */
9
- export declare function createWorkCaseReviewer(root: string, batchId: string, author: string): {
10
- history: (caseManifestId: string) => WorkCaseDecision[];
11
- list(offset?: number, limit?: number): {
12
- total: number;
13
- offset: number;
14
- items: {
15
- caseManifestId: string;
16
- candidate: import("@skill-harness/core").WorkCaptureCaseV2;
17
- priorDecisionId: string | null;
18
- disposition: string;
19
- }[];
20
- };
21
- decide(request: WorkCaseReviewRequest): {
22
- current: WorkCaseDecision;
23
- replayed: boolean;
24
- };
25
- };
26
- /** Explicit new signal contract; the existing v2 entry point still refuses these batches. */
27
- export declare function createWorkSignalReviewer(root: string, batchId: string, author: string): {
28
- list(offset?: number, limit?: number): {
29
- observationId: string;
30
- issues: string[];
31
- total: number;
32
- offset: number;
33
- items: {
34
- caseManifestId: string;
35
- candidate: import("@skill-harness/core").WorkCaptureCaseV2 | import("@skill-harness/core").WorkCaptureCaseV3;
36
- priorDecisionId: string | null;
37
- disposition: string;
38
- }[];
39
- };
40
- history: (caseManifestId: string) => WorkCaseDecision[];
41
- decide(request: WorkCaseReviewRequest): {
42
- current: WorkCaseDecision;
43
- replayed: boolean;
44
- };
45
- };
@@ -1,220 +0,0 @@
1
- import { constants, closeSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
2
- import { randomUUID } from "node:crypto";
3
- import { join } from "node:path";
4
- import { appendWorkCaseDecision } from "@skill-harness/core";
5
- import { readArchiveSource } from "./evidence-archive.js";
6
- import { readWorkCandidate } from "./work-case-archive.js";
7
- import { readWorkSignalBatch, readWorkSignalCase } from "./work-signal-cases.js";
8
- const SHA = /^[a-f0-9]{64}$/;
9
- const missing = (error) => error?.code === "ENOENT";
10
- function assertDirectory(path) {
11
- const stat = lstatSync(path);
12
- if (!stat.isDirectory() || stat.isSymbolicLink() || (stat.mode & 0o077) || (process.getuid && stat.uid !== process.getuid()))
13
- throw new Error("private case directory required");
14
- }
15
- function syncDirectory(path) {
16
- const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
17
- try {
18
- fsyncSync(fd);
19
- }
20
- finally {
21
- closeSync(fd);
22
- }
23
- }
24
- function privateDirectory(path) {
25
- let created = false;
26
- try {
27
- mkdirSync(path, { mode: 0o700 });
28
- created = true;
29
- }
30
- catch (error) {
31
- if (error.code !== "EEXIST")
32
- throw error;
33
- }
34
- assertDirectory(path);
35
- return created;
36
- }
37
- function bytes(path, limit) {
38
- const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
39
- try {
40
- const stat = fstatSync(fd);
41
- if (!stat.isFile() || stat.nlink !== 1 || stat.size > limit || (stat.mode & 0o077))
42
- throw new Error("invalid case history file");
43
- const out = Buffer.alloc(limit + 1);
44
- let used = 0;
45
- while (used <= limit) {
46
- const n = readSync(fd, out, used, out.length - used, used);
47
- if (!n)
48
- break;
49
- used += n;
50
- }
51
- if (used > limit)
52
- throw new Error("case history bound exceeded");
53
- return out.subarray(0, used);
54
- }
55
- finally {
56
- closeSync(fd);
57
- }
58
- }
59
- function historyAt(directory, caseId, brandNew = false) {
60
- let raw;
61
- try {
62
- raw = bytes(join(directory, "history.jsonl"), 1024 * 1024);
63
- }
64
- catch (error) {
65
- if (missing(error) && brandNew)
66
- return [];
67
- if (missing(error))
68
- throw new Error("case history missing; explicit recovery required");
69
- throw error;
70
- }
71
- if (!raw.length || raw.at(-1) !== 10)
72
- throw new Error("case history incomplete; explicit recovery required");
73
- const records = raw.toString("utf8").trimEnd().split("\n").map(line => JSON.parse(line));
74
- let valid = [];
75
- for (const record of records) {
76
- if (record.caseId !== caseId || record.decision_schema !== 1)
77
- throw new Error("case history binding mismatch");
78
- const { id, decision_schema: _schema, ...input } = record;
79
- valid = appendWorkCaseDecision(valid, input);
80
- if (!valid.some(r => r.id === id))
81
- throw new Error("case history identity mismatch");
82
- }
83
- return valid;
84
- }
85
- function assertAuthor(author) {
86
- if (typeof author !== "string" || !author || author.length > 512 || /[\u0000-\u001f\u007f]/.test(author))
87
- throw new Error("explicit operator author required");
88
- }
89
- /** Operator-selected batch/author capability. Not user authentication, worker authority or scenario promotion. */
90
- export function createWorkCaseReviewer(root, batchId, author) {
91
- assertAuthor(author);
92
- const source = readArchiveSource(root, batchId);
93
- if (source.status !== "available" || source.reference.parser.id !== "work-candidate-batch" || source.reference.parser.version !== "1" || source.reference.retention !== "exact")
94
- throw new Error("case batch missing or invalid");
95
- const batch = JSON.parse(source.bytes.toString("utf8"));
96
- if (batch.version !== "work-candidate-batch-v1" || batch.visibility !== "silent" || batch.promotion !== "not-authorized"
97
- || !Array.isArray(batch.candidateIds) || batch.candidateIds.length > 4096 || batch.candidateIds.some((id) => typeof id !== "string" || !SHA.test(id)))
98
- throw new Error("invalid selected case batch");
99
- return createSelectedCaseReviewer(root, author, batch.candidateIds, id => readWorkCandidate(root, id));
100
- }
101
- /** Explicit new signal contract; the existing v2 entry point still refuses these batches. */
102
- export function createWorkSignalReviewer(root, batchId, author) {
103
- assertAuthor(author);
104
- const batch = readWorkSignalBatch(root, batchId);
105
- const reviewer = createSelectedCaseReviewer(root, author, batch.candidateIds, id => {
106
- const selected = readWorkSignalCase(root, id);
107
- if (selected.observationId !== batch.observationId)
108
- throw new Error("work signal case outside frozen observation");
109
- return selected.candidate;
110
- });
111
- return { ...reviewer, list(offset = 0, limit = 5) {
112
- const current = readWorkSignalBatch(root, batchId);
113
- return { ...reviewer.list(offset, limit), observationId: current.observationId, issues: current.issues };
114
- } };
115
- }
116
- function createSelectedCaseReviewer(root, author, ids, readCandidate) {
117
- const allowed = new Set(ids);
118
- const selected = (id) => { if (!allowed.has(id))
119
- throw new Error("case outside selected batch"); return readCandidate(id); };
120
- const getHistory = (caseManifestId) => {
121
- const candidate = selected(caseManifestId), directory = join(root, "case-decisions", candidate.id);
122
- try {
123
- assertDirectory(join(root, "case-decisions"));
124
- assertDirectory(directory);
125
- }
126
- catch (error) {
127
- if (missing(error))
128
- return [];
129
- throw error;
130
- }
131
- return historyAt(directory, candidate.id);
132
- };
133
- return {
134
- history: getHistory,
135
- list(offset = 0, limit = 5) {
136
- if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 5)
137
- throw new Error("bounded case page required");
138
- const ids = [...allowed].sort();
139
- return { total: ids.length, offset, items: ids.slice(offset, offset + limit).map(caseManifestId => {
140
- const candidate = selected(caseManifestId), current = getHistory(caseManifestId).at(-1) ?? null;
141
- return { caseManifestId, candidate, priorDecisionId: current?.id ?? null, disposition: current?.disposition ?? "unresolved" };
142
- }) };
143
- },
144
- decide(request) {
145
- if (!request || Object.keys(request).sort().join() !== "caseManifestId,disposition,note,priorDecisionId"
146
- || !["confirmed_defect", "expected_behavior", "exemplar", "uncertain", "skip"].includes(request.disposition)
147
- || typeof request.note !== "string" || request.note.length > 4000
148
- || !(request.priorDecisionId === null || (typeof request.priorDecisionId === "string" && SHA.test(request.priorDecisionId))))
149
- throw new Error("invalid case review request");
150
- const candidate = selected(request.caseManifestId);
151
- const parent = join(root, "case-decisions");
152
- privateDirectory(parent);
153
- const directory = join(parent, candidate.id);
154
- const lockPath = join(parent, candidate.id + ".lock"), token = randomUUID();
155
- const lock = openSync(lockPath, constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
156
- const identity = fstatSync(lock);
157
- let primary;
158
- let result;
159
- try {
160
- writeFileSync(lock, token);
161
- fsyncSync(lock);
162
- // Hold the case lock BEFORE first directory creation; concurrent first reviewers cannot poison initialization.
163
- const brandNew = privateDirectory(directory);
164
- const before = historyAt(directory, candidate.id, brandNew);
165
- const after = appendWorkCaseDecision(before, { caseId: candidate.id, priorDecisionId: request.priorDecisionId,
166
- disposition: request.disposition, author, evidence: [request.caseManifestId], note: request.note });
167
- if (after.length > before.length) {
168
- const path = join(directory, "history.jsonl");
169
- const fd = openSync(path, constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600);
170
- try {
171
- const stat = fstatSync(fd);
172
- if (!stat.isFile() || stat.nlink !== 1 || (stat.mode & 0o077))
173
- throw new Error("invalid case history destination");
174
- const line = Buffer.from(JSON.stringify(after.at(-1)) + "\n");
175
- if (stat.size + line.length > 1024 * 1024)
176
- throw new Error("case history bound exceeded");
177
- let offset = 0;
178
- while (offset < line.length) {
179
- const n = writeSync(fd, line, offset, line.length - offset);
180
- if (!n)
181
- throw new Error("case history write stalled");
182
- offset += n;
183
- }
184
- fsyncSync(fd);
185
- }
186
- finally {
187
- closeSync(fd);
188
- }
189
- }
190
- syncDirectory(directory);
191
- syncDirectory(parent);
192
- syncDirectory(root);
193
- result = { current: after.at(-1), replayed: after.length === before.length };
194
- }
195
- catch (error) {
196
- primary = error;
197
- }
198
- finally {
199
- try {
200
- const present = lstatSync(lockPath);
201
- if (present.dev !== identity.dev || present.ino !== identity.ino || bytes(lockPath, 128).toString() !== token)
202
- throw new Error("case writer lock ownership lost");
203
- unlinkSync(lockPath);
204
- syncDirectory(parent);
205
- }
206
- catch (error) {
207
- if (!primary)
208
- primary = error;
209
- }
210
- finally {
211
- closeSync(lock);
212
- }
213
- }
214
- if (primary)
215
- throw primary;
216
- return result;
217
- },
218
- };
219
- }
220
- //# sourceMappingURL=work-case-review.js.map
@@ -1,15 +0,0 @@
1
- /** Case records point to frozen inputs, not cached verdicts or caller-authored authority. */
2
- export declare function captureWorkSignalCases(root: string, observationId: string): {
3
- batchId: string;
4
- observationId: string;
5
- candidateIds: string[];
6
- };
7
- export declare function readWorkSignalCase(root: string, manifestId: string): {
8
- observationId: string;
9
- candidate: import("@skill-harness/core").WorkCaptureCaseV2 | import("@skill-harness/core").WorkCaptureCaseV3;
10
- };
11
- export declare function readWorkSignalBatch(root: string, manifestId: string): {
12
- observationId: string;
13
- candidateIds: string[];
14
- issues: string[];
15
- };
@@ -1,54 +0,0 @@
1
- import { readArchiveSource, retainArchiveSource } from "./evidence-archive.js";
2
- import { readWorkSignalObservation } from "./work-signal-observation.js";
3
- const SHA = /^[a-f0-9]{64}$/;
4
- const hash = (v) => typeof v === "string" && SHA.test(v);
5
- function read(root, id, parser) {
6
- const source = readArchiveSource(root, id);
7
- if (source.status !== "available" || source.reference.retention !== "exact" || source.reference.parser.id !== parser || source.reference.parser.version !== "1"
8
- || source.bytes.length > 128 * 1024)
9
- throw new Error("work signal case evidence unavailable or unsupported");
10
- let value;
11
- try {
12
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(source.bytes));
13
- }
14
- catch {
15
- throw new Error("invalid work signal case JSON");
16
- }
17
- return { value, sourceId: source.reference.sourceId };
18
- }
19
- function closed(v, keys) {
20
- if (!v || typeof v !== "object" || Array.isArray(v) || Object.keys(v).sort().join() !== [...keys].sort().join())
21
- throw new Error("invalid closed work signal case record");
22
- }
23
- function retain(root, sourceId, parser, value) {
24
- return retainArchiveSource(root, { sourceId, parser: { id: parser, version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(value)) }).manifestId;
25
- }
26
- /** Case records point to frozen inputs, not cached verdicts or caller-authored authority. */
27
- export function captureWorkSignalCases(root, observationId) {
28
- const observation = readWorkSignalObservation(root, observationId);
29
- const candidateIds = observation.detection.cases.map(candidate => retain(root, `work-signal-case-${candidate.id}`, "work-signal-case", { version: "work-signal-case-v1", observationId, caseId: candidate.id }));
30
- const batchId = retain(root, `work-signal-batch-${observationId}`, "work-signal-batch", { version: "work-signal-batch-v1", observationId, candidateIds, visibility: "silent", promotion: "not-authorized" });
31
- return { batchId, observationId, candidateIds };
32
- }
33
- export function readWorkSignalCase(root, manifestId) {
34
- const { value, sourceId } = read(root, manifestId, "work-signal-case");
35
- closed(value, ["version", "observationId", "caseId"]);
36
- if (value.version !== "work-signal-case-v1" || !hash(value.observationId) || !hash(value.caseId) || sourceId !== `work-signal-case-${value.caseId}`)
37
- throw new Error("work signal case binding mismatch");
38
- const observation = readWorkSignalObservation(root, value.observationId);
39
- const candidate = observation.detection.cases.find(c => c.id === value.caseId);
40
- if (!candidate)
41
- throw new Error("case is not nominated by frozen work signal inputs");
42
- return { observationId: value.observationId, candidate };
43
- }
44
- export function readWorkSignalBatch(root, manifestId) {
45
- const { value, sourceId } = read(root, manifestId, "work-signal-batch");
46
- closed(value, ["version", "observationId", "candidateIds", "visibility", "promotion"]);
47
- if (value.version !== "work-signal-batch-v1" || !hash(value.observationId) || sourceId !== `work-signal-batch-${value.observationId}`
48
- || value.visibility !== "silent" || value.promotion !== "not-authorized" || !Array.isArray(value.candidateIds)
49
- || value.candidateIds.length > 1024 || !value.candidateIds.every(hash) || new Set(value.candidateIds).size !== value.candidateIds.length)
50
- throw new Error("invalid work signal batch binding");
51
- const observation = readWorkSignalObservation(root, value.observationId);
52
- return { observationId: value.observationId, candidateIds: value.candidateIds, issues: observation.detection.issues };
53
- }
54
- //# sourceMappingURL=work-signal-cases.js.map
@@ -1,23 +0,0 @@
1
- import { type WorkSignalFacts, type WorkSignalSnapshot } from "@skill-harness/core";
2
- interface WorkSignalInput {
3
- observation_schema: "work-signal-observation-v1";
4
- snapshot: WorkSignalSnapshot;
5
- facts: WorkSignalFacts;
6
- }
7
- /** Explicit private host-fact retention, not automatic discovery, authenticated authority or case promotion. */
8
- export declare function retainWorkSignalObservation(root: string, snapshot: WorkSignalSnapshot, facts: WorkSignalFacts): {
9
- manifestId: string;
10
- inputSha256: string;
11
- };
12
- /** Re-derive, never trust a cached nomination. Missing/corrupt inputs fail rather than becoming empty work. */
13
- export declare function readWorkSignalObservation(root: string, manifestId: string): {
14
- manifestId: string;
15
- inputSha256: string;
16
- input: WorkSignalInput;
17
- detection: {
18
- version: "work-signals-v1";
19
- cases: (import("@skill-harness/core").WorkCaptureCaseV2 | import("@skill-harness/core").WorkCaptureCaseV3)[];
20
- issues: string[];
21
- };
22
- };
23
- export {};
@@ -1,89 +0,0 @@
1
- import { detectAdditionalWorkCases } from "@skill-harness/core";
2
- import { readArchiveSource, retainArchiveSource } from "./evidence-archive.js";
3
- const LIMIT = 1024 * 1024;
4
- function closed(value, keys) {
5
- if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
6
- throw new Error("closed work signal object required");
7
- const descriptors = Object.getOwnPropertyDescriptors(value), names = Reflect.ownKeys(value);
8
- if (names.length !== keys.length || names.some(k => typeof k !== "string" || !keys.includes(k) || !descriptors[k].enumerable || !Object.hasOwn(descriptors[k], "value")))
9
- throw new Error("closed work signal fields required");
10
- }
11
- function array(value) {
12
- if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > 256
13
- || Reflect.ownKeys(value).length !== value.length + 1)
14
- throw new Error("bounded dense work signal array required");
15
- for (let i = 0; i < value.length; i++) {
16
- const d = Object.getOwnPropertyDescriptor(value, String(i));
17
- if (!d || !d.enumerable || !Object.hasOwn(d, "value"))
18
- throw new Error("dense work signal data array required");
19
- }
20
- }
21
- // Only called after closed primitive/shape validation. Arrays retain observation order.
22
- function canonical(value) {
23
- if (Array.isArray(value))
24
- return `[${value.map(canonical).join(",")}]`;
25
- if (value !== null && typeof value === "object")
26
- return `{${Object.keys(value).sort().map(k => `${JSON.stringify(k)}:${canonical(value[k])}`).join(",")}}`;
27
- return JSON.stringify(value);
28
- }
29
- function validate(value) {
30
- closed(value, ["observation_schema", "snapshot", "facts"]);
31
- if (value.observation_schema !== "work-signal-observation-v1")
32
- throw new Error("unsupported work signal observation");
33
- closed(value.snapshot, ["snapshotDigest", "scopeValid", "obligations"]);
34
- closed(value.facts, ["scopeDigest", "version", "population", "expectedWaits", "checkpoints", "violations", "priorAccepted"]);
35
- const s = value.snapshot, f = value.facts;
36
- if (typeof s.scopeValid !== "boolean")
37
- throw new Error("invalid work signal scope state");
38
- array(s.obligations);
39
- array(f.expectedWaits);
40
- array(f.checkpoints);
41
- array(f.violations);
42
- array(f.priorAccepted);
43
- const seen = new Set();
44
- for (const o of s.obligations) {
45
- closed(o, ["id", "digest", "intentDigest", "policyDigest", "artifactDigest", "acceptance", "coverage"]);
46
- if (seen.has(o.digest))
47
- throw new Error("duplicate work signal obligation identity");
48
- seen.add(o.digest);
49
- }
50
- for (const c of f.checkpoints)
51
- closed(c, ["obligationDigest", "deadlineMs", "observedAt", "status", "evidence"]);
52
- for (const v of f.violations)
53
- closed(v, ["obligationDigest", "status", "evidence"]);
54
- for (const p of f.priorAccepted)
55
- closed(p, ["obligationDigest", "intentDigest", "policyDigest", "artifactDigest", "acceptanceEvidence"]);
56
- const input = value;
57
- // Shared rules validate scalar types, exact scope, bounded timestamps, enums and evidence identities.
58
- detectAdditionalWorkCases(input.snapshot, input.facts);
59
- return input;
60
- }
61
- /** Explicit private host-fact retention, not automatic discovery, authenticated authority or case promotion. */
62
- export function retainWorkSignalObservation(root, snapshot, facts) {
63
- const input = validate({ observation_schema: "work-signal-observation-v1", snapshot, facts });
64
- const bytes = Buffer.from(canonical(input));
65
- if (bytes.length > LIMIT)
66
- throw new Error("work signal observation exceeds byte bound");
67
- const stored = retainArchiveSource(root, { sourceId: `work-signals-${snapshot.snapshotDigest}`, parser: { id: "work-signal-observation", version: "1" }, retention: "exact", bytes });
68
- return { manifestId: stored.manifestId, inputSha256: stored.reference.sha256 };
69
- }
70
- /** Re-derive, never trust a cached nomination. Missing/corrupt inputs fail rather than becoming empty work. */
71
- export function readWorkSignalObservation(root, manifestId) {
72
- const stored = readArchiveSource(root, manifestId);
73
- if (stored.status !== "available" || stored.reference.retention !== "exact" || stored.reference.parser.id !== "work-signal-observation"
74
- || stored.reference.parser.version !== "1" || stored.bytes.length > LIMIT)
75
- throw new Error("work signal observation unavailable or unsupported");
76
- let text, decoded;
77
- try {
78
- text = new TextDecoder("utf-8", { fatal: true }).decode(stored.bytes);
79
- decoded = JSON.parse(text);
80
- }
81
- catch {
82
- throw new Error("invalid work signal observation JSON");
83
- } // No raw byte excerpts in diagnostics.
84
- const input = validate(decoded);
85
- if (canonical(input) !== text || stored.reference.sourceId !== `work-signals-${input.snapshot.snapshotDigest}`)
86
- throw new Error("work signal observation binding mismatch");
87
- return { manifestId, inputSha256: stored.reference.sha256, input, detection: detectAdditionalWorkCases(input.snapshot, input.facts) };
88
- }
89
- //# sourceMappingURL=work-signal-observation.js.map