@skill-harness/adapters 0.12.0 → 0.13.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 (103) hide show
  1. package/dist/archive-access.d.ts +58 -0
  2. package/dist/archive-access.js +61 -0
  3. package/dist/archive-checkpoint.d.ts +47 -0
  4. package/dist/archive-checkpoint.js +116 -0
  5. package/dist/archive-facts.d.ts +19 -0
  6. package/dist/archive-facts.js +20 -0
  7. package/dist/archive-observer.d.ts +21 -0
  8. package/dist/archive-observer.js +79 -0
  9. package/dist/archive-policy.d.ts +107 -0
  10. package/dist/archive-policy.js +135 -0
  11. package/dist/archive-read-capability.d.ts +49 -0
  12. package/dist/archive-read-capability.js +45 -0
  13. package/dist/archive-retention-policy.d.ts +52 -0
  14. package/dist/archive-retention-policy.js +49 -0
  15. package/dist/archived-work.d.ts +44 -0
  16. package/dist/archived-work.js +59 -0
  17. package/dist/blind-intervention.d.ts +29 -0
  18. package/dist/blind-intervention.js +211 -0
  19. package/dist/codex-diagnostic-model.d.ts +14 -0
  20. package/dist/codex-diagnostic-model.js +39 -0
  21. package/dist/codex-host-observer.d.ts +111 -0
  22. package/dist/codex-host-observer.js +309 -0
  23. package/dist/codex-https.d.ts +7 -0
  24. package/dist/codex-https.js +221 -0
  25. package/dist/codex-model-profile.d.ts +38 -0
  26. package/dist/codex-model-profile.js +54 -0
  27. package/dist/codex-producer-ipc.d.ts +55 -0
  28. package/dist/codex-producer-ipc.js +67 -0
  29. package/dist/codex-sdk-transport.d.ts +50 -0
  30. package/dist/codex-sdk-transport.js +294 -0
  31. package/dist/codex-subscription.d.ts +114 -0
  32. package/dist/codex-subscription.js +268 -0
  33. package/dist/evidence-archive.d.ts +57 -0
  34. package/dist/evidence-archive.js +221 -0
  35. package/dist/execution-projection-schema.d.ts +10 -0
  36. package/dist/execution-projection-schema.js +30 -0
  37. package/dist/execution-retention-archive.d.ts +69 -0
  38. package/dist/execution-retention-archive.js +154 -0
  39. package/dist/generated/retention-v2-contract.d.ts +72 -0
  40. package/dist/generated/retention-v2-contract.js +105 -0
  41. package/dist/generated/retention-v2-json.d.ts +24 -0
  42. package/dist/generated/retention-v2-json.js +268 -0
  43. package/dist/generated/retention-v2-native-json.d.ts +2 -0
  44. package/dist/generated/retention-v2-native-json.js +33 -0
  45. package/dist/generated/retention-v2-native.d.ts +58 -0
  46. package/dist/generated/retention-v2-native.js +155 -0
  47. package/dist/generated/retention-v2-pin.d.ts +2 -0
  48. package/dist/generated/retention-v2-pin.js +4 -0
  49. package/dist/generated/retention-v2-types.d.ts +49 -0
  50. package/dist/generated/retention-v2-types.js +2 -0
  51. package/dist/generated/retention-v2-work-types.d.ts +260 -0
  52. package/dist/generated/retention-v2-work-types.js +13 -0
  53. package/dist/generated/work-v4/execution-id.d.ts +5 -0
  54. package/dist/generated/work-v4/execution-id.js +14 -0
  55. package/dist/generated/work-v4/json.d.ts +24 -0
  56. package/dist/generated/work-v4/json.js +268 -0
  57. package/dist/generated/work-v4/occurrences.d.ts +226 -0
  58. package/dist/generated/work-v4/occurrences.js +116 -0
  59. package/dist/generated/work-v4/pin.d.ts +1 -0
  60. package/dist/generated/work-v4/pin.js +3 -0
  61. package/dist/generated/work-v4/projection.d.ts +294 -0
  62. package/dist/generated/work-v4/projection.js +238 -0
  63. package/dist/generated/work-v4/reader.d.ts +24 -0
  64. package/dist/generated/work-v4/reader.js +109 -0
  65. package/dist/generated/work-v4/snapshot.d.ts +28 -0
  66. package/dist/generated/work-v4/snapshot.js +268 -0
  67. package/dist/generated/work-v4/types.d.ts +260 -0
  68. package/dist/generated/work-v4/types.js +13 -0
  69. package/dist/generated/work-v4/validation.d.ts +13 -0
  70. package/dist/generated/work-v4/validation.js +227 -0
  71. package/dist/index.d.ts +22 -0
  72. package/dist/index.js +22 -0
  73. package/dist/installed-review-session.d.ts +28 -0
  74. package/dist/installed-review-session.js +166 -0
  75. package/dist/intervention-run.d.ts +403 -0
  76. package/dist/intervention-run.js +169 -0
  77. package/dist/learning-case.d.ts +12 -0
  78. package/dist/learning-case.js +15 -0
  79. package/dist/learning-journal.d.ts +18 -0
  80. package/dist/learning-journal.js +256 -0
  81. package/dist/principal-payload-port.d.ts +25 -0
  82. package/dist/principal-payload-port.js +40 -0
  83. package/dist/producer-product.d.ts +70 -0
  84. package/dist/producer-product.js +186 -0
  85. package/dist/producer-review.d.ts +53 -0
  86. package/dist/producer-review.js +207 -0
  87. package/dist/reviewed-archive-export.d.ts +42 -0
  88. package/dist/reviewed-archive-export.js +78 -0
  89. package/dist/trust-lifecycle.d.ts +128 -0
  90. package/dist/trust-lifecycle.js +200 -0
  91. package/dist/weekly-investigation.d.ts +237 -0
  92. package/dist/weekly-investigation.js +330 -0
  93. package/dist/work-candidates.d.ts +29 -0
  94. package/dist/work-candidates.js +78 -0
  95. package/dist/work-case-archive.d.ts +25 -0
  96. package/dist/work-case-archive.js +63 -0
  97. package/dist/work-case-review.d.ts +45 -0
  98. package/dist/work-case-review.js +220 -0
  99. package/dist/work-signal-cases.d.ts +15 -0
  100. package/dist/work-signal-cases.js +54 -0
  101. package/dist/work-signal-observation.d.ts +23 -0
  102. package/dist/work-signal-observation.js +89 -0
  103. package/package.json +3 -2
@@ -0,0 +1,135 @@
1
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from "node:fs";
2
+ import { createHash } from "node:crypto";
3
+ import { dirname, isAbsolute, join, parse, resolve, sep } from "node:path";
4
+ import { ingestArchiveSnapshot, readArchiveCheckpoint } from "./archive-checkpoint.js";
5
+ import { retainArchiveSource } from "./evidence-archive.js";
6
+ import { ingestNativePolicy, inspectNativePolicy } from "./archive-retention-policy.js";
7
+ const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
8
+ const forbidden = new Set([".pi", ".env", "auth.json", "credentials", "credentials.json"]);
9
+ function fail() { throw new Error("archive policy refused invalid, expired or inaccessible input"); }
10
+ const keys = (v, names) => !!v && typeof v === "object" && !Array.isArray(v)
11
+ && Object.keys(v).length === names.length && Object.keys(v).every(k => names.includes(k));
12
+ const identifier = (v) => typeof v === "string" && ID.test(v);
13
+ function regularBytes(path, limit) {
14
+ if (!constants.O_NOFOLLOW || !constants.O_NONBLOCK)
15
+ fail();
16
+ const absolute = resolve(path);
17
+ if (absolute.split(sep).some(part => forbidden.has(part)))
18
+ fail();
19
+ let current = parse(absolute).root;
20
+ for (const part of dirname(absolute).slice(current.length).split(sep).filter(Boolean)) {
21
+ current = join(current, part);
22
+ const stat = lstatSync(current);
23
+ if (!stat.isDirectory() || stat.isSymbolicLink())
24
+ fail();
25
+ }
26
+ const fd = openSync(absolute, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
27
+ try {
28
+ const stat = fstatSync(fd);
29
+ if (!stat.isFile() || stat.size > limit || (stat.mode & 0o077) !== 0 || (process.getuid && stat.uid !== process.getuid()))
30
+ fail();
31
+ const bytes = Buffer.alloc(limit + 1);
32
+ let size = 0;
33
+ while (size <= limit) {
34
+ const n = readSync(fd, bytes, size, bytes.length - size, size);
35
+ if (!n)
36
+ break;
37
+ size += n;
38
+ }
39
+ if (size > limit)
40
+ fail();
41
+ return bytes.subarray(0, size);
42
+ }
43
+ finally {
44
+ closeSync(fd);
45
+ }
46
+ }
47
+ function selectedPolicy(path, sourceId) {
48
+ const bytes = regularBytes(path, 65536);
49
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
50
+ const p = JSON.parse(text);
51
+ // Canonical JSON excludes duplicate-key ambiguity. This is a selected operator configuration, not a signed approval.
52
+ if (JSON.stringify(p) !== text || !keys(p, ["version", "id", "revision", "sourceRoot", "archiveRoot", "maxBytes", "retention", "expiresAt", "sources"])
53
+ || !["archive-policy-v1", "archive-policy-v2"].includes(p.version) || !identifier(p.id) || !identifier(p.revision)
54
+ || typeof p.sourceRoot !== "string" || !isAbsolute(p.sourceRoot) || typeof p.archiveRoot !== "string" || !isAbsolute(p.archiveRoot)
55
+ || resolve(p.sourceRoot) === resolve(p.archiveRoot)
56
+ || [p.sourceRoot, p.archiveRoot].some(root => root.split(/[\\/]/).some(part => forbidden.has(part)))
57
+ || !Number.isSafeInteger(p.maxBytes) || p.maxBytes < 1 || p.maxBytes > 8 * 1024 * 1024
58
+ || !["exact", "redacted", "reference-only"].includes(p.retention)
59
+ || typeof p.expiresAt !== "string" || !Number.isFinite(Date.parse(p.expiresAt))
60
+ || new Date(p.expiresAt).toISOString() !== p.expiresAt || Date.parse(p.expiresAt) <= Date.now()
61
+ || !Array.isArray(p.sources) || p.sources.length < 1 || p.sources.length > 128)
62
+ fail();
63
+ const ids = new Set();
64
+ for (const item of p.sources) {
65
+ if (!keys(item, p.version === "archive-policy-v2" ? ["id", "path", "parser", "contentPolicy"] : ["id", "path", "parser"]) || !identifier(item.id) || ids.has(item.id)
66
+ || typeof item.path !== "string" || !item.path || isAbsolute(item.path) || item.path.includes("\\")
67
+ || item.path.split("/").some(part => !part || part === "." || part === ".." || forbidden.has(part))
68
+ || !keys(item.parser, ["id", "version"]) || !identifier(item.parser.id) || !identifier(item.parser.version))
69
+ fail();
70
+ if (p.version === "archive-policy-v2" && !["manifest-only", "referenced-blobs"].includes(item.contentPolicy))
71
+ fail();
72
+ if (item.contentPolicy === "referenced-blobs" && (p.retention !== "exact" || item.parser.id !== "pi-daddy-execution-retention" || item.parser.version !== "2.0"))
73
+ fail();
74
+ ids.add(item.id);
75
+ }
76
+ const source = p.sources.find(s => s.id === sourceId);
77
+ if (!source)
78
+ fail();
79
+ const root = lstatSync(p.sourceRoot);
80
+ if (!root.isDirectory() || root.isSymbolicLink() || (root.mode & 0o077) !== 0 || (process.getuid && root.uid !== process.getuid()))
81
+ fail();
82
+ const archiveSourceId = `policy-source-${createHash("sha256").update(JSON.stringify([p.id, source.id, resolve(p.sourceRoot), source.path])).digest("hex")}`;
83
+ return { policy: p, source, archiveSourceId, policySha256: createHash("sha256").update(bytes).digest("hex") };
84
+ }
85
+ function metadata(result, checkpointId, policySha256) {
86
+ return { checkpointId, policySha256, sourceId: result.checkpoint.sourceId, sourceSha256: result.checkpoint.sourceSha256,
87
+ sourceStatus: result.source.status, retention: result.checkpoint.retention, syntax: result.checkpoint.syntax,
88
+ completeBytes: result.checkpoint.completeBytes, pendingBytes: result.checkpoint.pendingBytes,
89
+ invalidLines: result.checkpoint.invalidLines, issues: result.checkpoint.issues,
90
+ activeBranch: result.checkpoint.activeBranch, acceptance: result.checkpoint.acceptance };
91
+ }
92
+ /** Host-only policy binding for bounded external observation; no source bytes are read. */
93
+ export function archivePolicyBinding(policyPath, sourceId) {
94
+ const selected = selectedPolicy(policyPath, sourceId);
95
+ return Object.freeze({ policySha256: selected.policySha256, archiveRoot: selected.policy.archiveRoot,
96
+ sourceId, archiveSourceId: selected.archiveSourceId, expiresAt: selected.policy.expiresAt });
97
+ }
98
+ /** Explicit operator-selected file policy. Not a credential, authorization attestation or hostile-agent sandbox. */
99
+ export function ingestPolicySource(policyPath, sourceId, previousCheckpointId, expectedPolicySha256) {
100
+ try {
101
+ const { policy, source, archiveSourceId, policySha256 } = selectedPolicy(policyPath, sourceId);
102
+ if (expectedPolicySha256 !== undefined && expectedPolicySha256 !== policySha256)
103
+ throw new Error("archive policy changed");
104
+ if (source.contentPolicy === "referenced-blobs")
105
+ return ingestNativePolicy({ policy, source, archiveSourceId, policySha256 }, previousCheckpointId, regularBytes);
106
+ const bytes = regularBytes(join(policy.sourceRoot, source.path), policy.maxBytes);
107
+ const result = ingestArchiveSnapshot(policy.archiveRoot, { sourceId: archiveSourceId, parser: source.parser, retention: policy.retention, bytes, previousCheckpointId });
108
+ const receipt = retainArchiveSource(policy.archiveRoot, {
109
+ sourceId: `policy-${policySha256}`, parser: { id: "archive-policy-receipt", version: "1" }, retention: "exact",
110
+ bytes: Buffer.from(JSON.stringify({ version: "archive-policy-receipt-v1", policySha256, checkpointId: result.checkpointId, sourceId })),
111
+ });
112
+ return { ...metadata(result, result.checkpointId, policySha256), sourceId, archiveSourceId, change: result.change, policyReceiptId: receipt.manifestId };
113
+ }
114
+ catch {
115
+ fail();
116
+ }
117
+ }
118
+ /** Metadata-only CLI/read-model output; no payload, local path or policy file is exported. */
119
+ export function inspectPolicyCheckpoint(policyPath, sourceId, checkpointId) {
120
+ try {
121
+ const { policy, source, archiveSourceId, policySha256 } = selectedPolicy(policyPath, sourceId);
122
+ if (source.contentPolicy === "referenced-blobs")
123
+ return inspectNativePolicy({ policy, source, archiveSourceId, policySha256 }, checkpointId);
124
+ const result = readArchiveCheckpoint(policy.archiveRoot, checkpointId);
125
+ const c = result.checkpoint;
126
+ if (c.sourceId !== archiveSourceId || c.retention !== policy.retention || c.sourceBytes > policy.maxBytes
127
+ || c.declaredParser.id !== source.parser.id || c.declaredParser.version !== source.parser.version)
128
+ fail();
129
+ return { ...metadata(result, checkpointId, policySha256), sourceId, archiveSourceId };
130
+ }
131
+ catch {
132
+ fail();
133
+ }
134
+ }
135
+ //# sourceMappingURL=archive-policy.js.map
@@ -0,0 +1,49 @@
1
+ import { type GovernedArchiveRoute } from './archive-access.js';
2
+ export interface ArchiveReadCapabilityOptions {
3
+ root: string;
4
+ /** Optional durable shared policy; absent preserves the historical raw route. */
5
+ access?: GovernedArchiveRoute;
6
+ /** Independently selected, content-reviewed artifact IDs; never accepted from model requests. */
7
+ manifestIds: readonly string[];
8
+ maxCalls: number;
9
+ /** Total returned bytes, not a claim about OS-level read bandwidth or process memory. */
10
+ maxBytes: number;
11
+ durationMs: number;
12
+ representations?: readonly ("exact" | "redacted")[];
13
+ }
14
+ /** A closed read interface for an existing host/tool integration, not an OS sandbox or model route qualification. */
15
+ export declare function createArchiveReadCapability(options: ArchiveReadCapabilityOptions, clock?: () => number): Readonly<{
16
+ snapshot: Readonly<{
17
+ id: string;
18
+ version: string;
19
+ manifestIds: readonly any[];
20
+ maxCalls: number;
21
+ maxBytes: number;
22
+ durationMs: number;
23
+ representations: readonly string[];
24
+ access?: Readonly<{
25
+ directory: string;
26
+ purpose: string;
27
+ }> | undefined;
28
+ }>;
29
+ status: () => Readonly<{
30
+ calls: number;
31
+ bytes: number;
32
+ expired: boolean;
33
+ }>;
34
+ read(manifestId: string): Readonly<{
35
+ manifestId: string;
36
+ reference: Readonly<{
37
+ schema: "archive-source-v1";
38
+ sourceId: string;
39
+ parser: {
40
+ id: string;
41
+ version: string;
42
+ };
43
+ sha256: string;
44
+ bytes: number;
45
+ retention: import("./evidence-archive.js").ArchiveRetention;
46
+ }>;
47
+ bytes: Buffer<ArrayBuffer>;
48
+ }>;
49
+ }>;
@@ -0,0 +1,45 @@
1
+ import { createHash } from "node:crypto";
2
+ import { performance } from "node:perf_hooks";
3
+ import { readGovernedArchive } from './archive-access.js';
4
+ import { readArchiveSource } from "./evidence-archive.js";
5
+ /** A closed read interface for an existing host/tool integration, not an OS sandbox or model route qualification. */
6
+ export function createArchiveReadCapability(options, clock = () => performance.now()) {
7
+ if (!Array.isArray(options.manifestIds) || !options.manifestIds.length || options.manifestIds.length > 4096
8
+ || options.manifestIds.some(id => typeof id !== "string" || !/^[a-f0-9]{64}$/.test(id))
9
+ || !Number.isSafeInteger(options.maxCalls) || options.maxCalls < 1 || options.maxCalls > 128
10
+ || !Number.isSafeInteger(options.maxBytes) || options.maxBytes < 1 || options.maxBytes > 64 * 1024 * 1024
11
+ || !Number.isSafeInteger(options.durationMs) || options.durationMs < 1 || options.durationMs > 3600000)
12
+ throw new Error("invalid archive capability bounds");
13
+ const root = options.root, maxCalls = options.maxCalls, maxBytes = options.maxBytes, durationMs = options.durationMs;
14
+ const representations = [...new Set(options.representations ?? ["redacted"])].sort();
15
+ if (!representations.length || representations.some(r => r !== "exact" && r !== "redacted"))
16
+ throw new Error("invalid archive representation policy");
17
+ const ids = Object.freeze([...new Set(options.manifestIds)].sort()), allowed = new Set(ids), started = clock();
18
+ if (!Number.isFinite(started))
19
+ throw new Error("invalid host clock");
20
+ const access = options.access ? Object.freeze({ ...options.access }) : undefined;
21
+ const descriptor = { ...(access ? { access } : {}), version: "archive-read-capability-v1", manifestIds: ids, maxCalls, maxBytes, durationMs, representations: Object.freeze(representations) };
22
+ const snapshot = Object.freeze({ ...descriptor, id: createHash("sha256").update(JSON.stringify(descriptor)).digest("hex") });
23
+ let calls = 0, returned = 0;
24
+ const elapsed = () => { const now = clock(); if (!Number.isFinite(now) || now < started)
25
+ return Infinity; return now - started; };
26
+ return Object.freeze({
27
+ snapshot,
28
+ status: () => Object.freeze({ calls, bytes: returned, expired: elapsed() >= durationMs }),
29
+ read(manifestId) {
30
+ if (calls >= maxCalls || elapsed() >= durationMs)
31
+ throw new Error("archive read refused");
32
+ calls++;
33
+ if (typeof manifestId !== "string" || !allowed.has(manifestId))
34
+ throw new Error("archive read refused");
35
+ const limit = Math.min(8 * 1024 * 1024, maxBytes - returned);
36
+ const source = access ? readGovernedArchive(root, manifestId, limit, access) : readArchiveSource(root, manifestId, limit);
37
+ if (source.status !== "available" || !representations.includes(source.reference.retention)
38
+ || source.bytes.length > maxBytes - returned || elapsed() >= durationMs)
39
+ throw new Error("archive read refused");
40
+ returned += source.bytes.length;
41
+ return Object.freeze({ manifestId, reference: Object.freeze({ ...source.reference }), bytes: Buffer.from(source.bytes) });
42
+ },
43
+ });
44
+ }
45
+ //# sourceMappingURL=archive-read-capability.js.map
@@ -0,0 +1,52 @@
1
+ import type { ArchiveIngestionPolicy, PolicySource } from "./archive-policy.js";
2
+ interface Context {
3
+ policy: ArchiveIngestionPolicy;
4
+ source: PolicySource;
5
+ archiveSourceId: string;
6
+ policySha256: string;
7
+ }
8
+ export declare function inspectNativePolicy(context: Context, checkpointId: string): {
9
+ kind: "execution-retention-v2";
10
+ checkpointId: string;
11
+ policySha256: string;
12
+ sourceId: string;
13
+ archiveSourceId: string;
14
+ sourceSha256: string;
15
+ sourceStatus: "available";
16
+ retention: "exact";
17
+ syntax: "not-applicable";
18
+ runtime: "running" | "terminal";
19
+ content: Record<"session" | "stdout" | "stderr" | "paneSnapshot" | "checkReceipt" | "result", {
20
+ status: "available" | "missing" | "mismatch";
21
+ sha256: string | null;
22
+ bytes: number | null;
23
+ }>;
24
+ activeBranch: null;
25
+ coverage: "partial";
26
+ issueCount: number;
27
+ acceptance: "not-assessed";
28
+ };
29
+ export declare function ingestNativePolicy(context: Context, previous: string | undefined, readBytes: (path: string, limit: number) => Buffer): {
30
+ change: string;
31
+ policyReceiptId: string;
32
+ kind: "execution-retention-v2";
33
+ checkpointId: string;
34
+ policySha256: string;
35
+ sourceId: string;
36
+ archiveSourceId: string;
37
+ sourceSha256: string;
38
+ sourceStatus: "available";
39
+ retention: "exact";
40
+ syntax: "not-applicable";
41
+ runtime: "running" | "terminal";
42
+ content: Record<"session" | "stdout" | "stderr" | "paneSnapshot" | "checkReceipt" | "result", {
43
+ status: "available" | "missing" | "mismatch";
44
+ sha256: string | null;
45
+ bytes: number | null;
46
+ }>;
47
+ activeBranch: null;
48
+ coverage: "partial";
49
+ issueCount: number;
50
+ acceptance: "not-assessed";
51
+ };
52
+ export {};
@@ -0,0 +1,49 @@
1
+ import { dirname, join } from "node:path";
2
+ import { parseExecutionRetentionManifest } from "./generated/retention-v2-contract.js";
3
+ import { ingestRetainedExecution, readRetainedExecution } from "./execution-retention-archive.js";
4
+ import { retainArchiveSource } from "./evidence-archive.js";
5
+ function metadata(context, checkpointId, projection) {
6
+ return {
7
+ kind: "execution-retention-v2", checkpointId, policySha256: context.policySha256,
8
+ sourceId: context.source.id, archiveSourceId: context.archiveSourceId, sourceSha256: projection.sourceSha256,
9
+ sourceStatus: "available", retention: "exact", syntax: "not-applicable",
10
+ runtime: projection.runtime, content: projection.content, activeBranch: null,
11
+ coverage: projection.coverage, issueCount: projection.issues.length, acceptance: projection.acceptance,
12
+ };
13
+ }
14
+ export function inspectNativePolicy(context, checkpointId) {
15
+ const read = readRetainedExecution(context.policy.archiveRoot, checkpointId);
16
+ if (read.sourceId !== context.archiveSourceId || Object.values(read.manifest.content).some(ref => ref.bytes !== null && ref.bytes > context.policy.maxBytes))
17
+ throw new Error("native snapshot outside policy");
18
+ return metadata(context, checkpointId, read.projection);
19
+ }
20
+ export function ingestNativePolicy(context, previous, readBytes) {
21
+ if (previous)
22
+ inspectNativePolicy(context, previous);
23
+ const path = join(context.policy.sourceRoot, context.source.path);
24
+ const manifestBytes = readBytes(path, Math.min(context.policy.maxBytes, 65536));
25
+ const manifest = parseExecutionRetentionManifest(new TextDecoder("utf-8", { fatal: true }).decode(manifestBytes));
26
+ const blobs = new Map();
27
+ for (const ref of Object.values(manifest.content)) {
28
+ if (!ref.path)
29
+ continue;
30
+ if (ref.bytes > context.policy.maxBytes)
31
+ throw new Error("native content exceeds policy bound");
32
+ try {
33
+ blobs.set(ref.path, readBytes(join(dirname(path), ref.path), Math.min(context.policy.maxBytes, 1024 * 1024)));
34
+ }
35
+ catch (error) {
36
+ if (error.code !== "ENOENT")
37
+ throw error;
38
+ }
39
+ }
40
+ const result = ingestRetainedExecution(context.policy.archiveRoot, {
41
+ manifest: manifestBytes, blobs, retention: "exact", sourceId: context.archiveSourceId,
42
+ });
43
+ const receipt = retainArchiveSource(context.policy.archiveRoot, {
44
+ sourceId: `policy-${context.policySha256}`, parser: { id: "archive-policy-receipt", version: "1" }, retention: "exact",
45
+ bytes: Buffer.from(JSON.stringify({ version: "archive-policy-receipt-v1", policySha256: context.policySha256, checkpointId: result.snapshotId, sourceId: context.source.id })),
46
+ });
47
+ return { ...metadata(context, result.snapshotId, result.projection), change: previous === result.snapshotId ? "repeat" : previous ? "observation" : "initial", policyReceiptId: receipt.manifestId };
48
+ }
49
+ //# sourceMappingURL=archive-retention-policy.js.map
@@ -0,0 +1,44 @@
1
+ import { type WorkProjectionContext, type WorkFrozen, type WorkProjection } from "./generated/work-v4/reader.js";
2
+ import type { WorkDetectionOptions } from "./work-candidates.js";
3
+ import type { WorkSignalFacts } from "@skill-harness/core";
4
+ export type ArchivedWork = {
5
+ state: "available";
6
+ manifestId: string;
7
+ sourceSha256: string;
8
+ producerCommit: string;
9
+ projection: WorkFrozen<WorkProjection>;
10
+ } | {
11
+ state: "missing" | "error";
12
+ manifestId: string;
13
+ reason: string;
14
+ };
15
+ /** Pinned producer's actual pure reader/projector, with no append/inspect/file-writing API in the generated facade. */
16
+ export declare function readArchivedWork(root: string, manifestId: string, context?: WorkFrozen<WorkProjectionContext>): ArchivedWork;
17
+ /** Preserve raw work bytes, derived facts and candidate batch linkage. No authority is read from an archive/context file. */
18
+ export declare function captureArchivedWorkCandidates(root: string, manifestId: string, context: WorkFrozen<WorkProjectionContext>, options: WorkDetectionOptions): {
19
+ linkageManifestId: string;
20
+ version: string;
21
+ workManifestId: string;
22
+ workSha256: string;
23
+ producerCommit: string;
24
+ observationId: string;
25
+ caseBatchId: string;
26
+ candidateIds: string[];
27
+ authorityBasis: string;
28
+ acceptance: string;
29
+ };
30
+ /** Derive binding/coverage/acceptance fields from the real pinned P01 projection, not caller replacements. */
31
+ export declare function captureArchivedWorkSignals(root: string, manifestId: string, context: WorkFrozen<WorkProjectionContext>, facts: WorkSignalFacts): {
32
+ linkageManifestId: string;
33
+ version: string;
34
+ bindingProfile: string;
35
+ workManifestId: string;
36
+ workSha256: string;
37
+ producerCommit: string;
38
+ projectionManifestId: string;
39
+ observationId: string;
40
+ caseBatchId: string;
41
+ candidateIds: string[];
42
+ authorityBasis: string;
43
+ acceptance: string;
44
+ };
@@ -0,0 +1,59 @@
1
+ import { readArchiveSource, retainArchiveSource } from "./evidence-archive.js";
2
+ import { projectWorkLedger } from "./generated/work-v4/reader.js";
3
+ import { WORK_V4_READER_COMMIT } from "./generated/work-v4/pin.js";
4
+ import { captureWorkCandidates } from "./work-case-archive.js";
5
+ import { retainWorkSignalObservation } from "./work-signal-observation.js";
6
+ import { captureWorkSignalCases } from "./work-signal-cases.js";
7
+ /** Pinned producer's actual pure reader/projector, with no append/inspect/file-writing API in the generated facade. */
8
+ export function readArchivedWork(root, manifestId, context = { selectedSnapshot: null, authority: null }) {
9
+ const source = readArchiveSource(root, manifestId);
10
+ if (source.status !== "available")
11
+ return { state: source.status === "missing" ? "missing" : "error", manifestId, reason: "work-source-unavailable" };
12
+ if (source.reference.retention !== "exact" || source.reference.parser.id !== "pi-daddy-work-ledger" || source.reference.parser.version !== "4")
13
+ return { state: "error", manifestId, reason: "exact-work-v4-source-required" };
14
+ try {
15
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(source.bytes);
16
+ const projection = projectWorkLedger(text, context);
17
+ return { state: "available", manifestId, sourceSha256: source.reference.sha256, producerCommit: WORK_V4_READER_COMMIT, projection };
18
+ }
19
+ catch {
20
+ return { state: "error", manifestId, reason: "invalid-work-source-or-context" };
21
+ }
22
+ }
23
+ /** Preserve raw work bytes, derived facts and candidate batch linkage. No authority is read from an archive/context file. */
24
+ export function captureArchivedWorkCandidates(root, manifestId, context, options) {
25
+ const read = readArchivedWork(root, manifestId, context);
26
+ if (read.state !== "available" || read.projection.errors.length || read.projection.scopeState !== "valid")
27
+ throw new Error("work source/selection incomplete; cannot nominate behavior");
28
+ const cases = captureWorkCandidates(root, read.projection, options);
29
+ const linkage = { version: "archived-work-candidates-v1", workManifestId: manifestId, workSha256: read.sourceSha256, producerCommit: read.producerCommit,
30
+ observationId: cases.observationId, caseBatchId: cases.batchId, candidateIds: cases.candidateIds, authorityBasis: "independently-supplied-host-context", acceptance: "not-assessed" };
31
+ const stored = retainArchiveSource(root, { sourceId: `work-case-link-${read.sourceSha256}`, parser: { id: "archived-work-candidates", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(linkage)) });
32
+ return { ...linkage, linkageManifestId: stored.manifestId };
33
+ }
34
+ /** Derive binding/coverage/acceptance fields from the real pinned P01 projection, not caller replacements. */
35
+ export function captureArchivedWorkSignals(root, manifestId, context, facts) {
36
+ const read = readArchivedWork(root, manifestId, context);
37
+ if (read.state !== "available" || read.projection.errors.length || read.projection.scopeState !== "valid" || !read.projection.selectedSnapshot || !read.projection.runtime)
38
+ throw new Error("work source/selection incomplete; cannot capture signals");
39
+ const work = read.projection, snapshotDigest = read.projection.selectedSnapshot.digest;
40
+ const snapshot = { snapshotDigest, scopeValid: true,
41
+ obligations: work.obligations.map(o => ({ id: o.binding.obligation.id, digest: o.binding.obligation.digest,
42
+ intentDigest: o.binding.intent.digest, policyDigest: o.binding.policy.digest, artifactDigest: o.binding.artifact?.digest ?? null,
43
+ acceptance: o.acceptance,
44
+ coverage: [o.artifactCoverage.state, o.evidenceCoverage.state].includes("conflicted") ? "conflicted"
45
+ : [o.artifactCoverage.state, o.evidenceCoverage.state].includes("unavailable") ? "unavailable"
46
+ : o.artifactCoverage.state === "available" && o.evidenceCoverage.state === "available" && o.problems.every(p => p.code === "TRUSTED_REJECTION") ? "available" : "unknown" })) };
47
+ // All four digests here are REVISION identities, not artifact content digests.
48
+ // Duplicate obligation bindings cannot be collapsed by this input profile; its validator refuses them.
49
+ const observation = retainWorkSignalObservation(root, snapshot, facts);
50
+ const projection = retainArchiveSource(root, { sourceId: `work-signal-projection-${read.sourceSha256}`, parser: { id: "pi-daddy-work-projection", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(work)) });
51
+ const cases = captureWorkSignalCases(root, observation.manifestId);
52
+ const linkage = { version: "archived-work-signals-v1", bindingProfile: "work-v4-revision-digests-v1", workManifestId: manifestId,
53
+ workSha256: read.sourceSha256, producerCommit: read.producerCommit, projectionManifestId: projection.manifestId,
54
+ observationId: observation.manifestId, caseBatchId: cases.batchId, candidateIds: cases.candidateIds,
55
+ authorityBasis: "independently-supplied-host-context", acceptance: "not-assessed" };
56
+ const stored = retainArchiveSource(root, { sourceId: `work-signal-link-${read.sourceSha256}`, parser: { id: "archived-work-signals", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(linkage)) });
57
+ return { ...linkage, linkageManifestId: stored.manifestId };
58
+ }
59
+ //# sourceMappingURL=archived-work.js.map
@@ -0,0 +1,29 @@
1
+ import { type BlindQualityChoice, type InterventionManifest, type InterventionEvidence, type InterventionQualification } from "@skill-harness/core";
2
+ /** Explicit private retention. Host role declarations are NOT authentication. No provider is called. */
3
+ export declare function retainBlindIntervention(root: string, manifest: InterventionManifest, evidence: InterventionEvidence[], qualification: InterventionQualification, author: string): string;
4
+ /** One immutable quality choice per comparison. Reopening cannot reset the reveal gate. */
5
+ export declare function openBlindIntervention(root: string, id: string, author: string): Readonly<{
6
+ view: () => {
7
+ version: string;
8
+ cards: {
9
+ label: string;
10
+ artifactDigests: string[];
11
+ }[];
12
+ limitations: string[];
13
+ };
14
+ quality(): BlindQualityChoice | null;
15
+ readArtifact: (label: string, hash: string) => Buffer<ArrayBuffer>;
16
+ choose(input: BlindQualityChoice): BlindQualityChoice;
17
+ reveal(): {
18
+ manifestId: string;
19
+ choice: BlindQualityChoice;
20
+ arms: {
21
+ label: string;
22
+ armId: string;
23
+ configuration: Record<import("@skill-harness/core").InterventionAxis, string>;
24
+ cost: number | null;
25
+ costUnit: string;
26
+ }[];
27
+ routingDefault: null;
28
+ };
29
+ }>;