@skill-harness/core 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.
Files changed (93) hide show
  1. package/README.md +1 -2
  2. package/dist/adapters/types.d.ts +0 -12
  3. package/dist/capture-trace-types.d.ts +0 -96
  4. package/dist/capture-trace-types.js +0 -4
  5. package/dist/command-cost.d.ts +1 -1
  6. package/dist/command-cost.js +0 -5
  7. package/dist/execution-trace.js +1 -1
  8. package/dist/index.d.ts +3 -23
  9. package/dist/index.js +3 -23
  10. package/dist/instruction-coverage.d.ts +0 -7
  11. package/dist/instruction-coverage.js +5 -7
  12. package/dist/journal.d.ts +0 -8
  13. package/dist/metrics.d.ts +18 -0
  14. package/dist/metrics.js +28 -0
  15. package/dist/redaction.d.ts +6 -0
  16. package/dist/redaction.js +55 -0
  17. package/dist/regate.js +6 -71
  18. package/dist/regrade.d.ts +1 -3
  19. package/dist/regrade.js +1 -21
  20. package/dist/report.d.ts +1 -15
  21. package/dist/report.js +1 -13
  22. package/dist/reps.d.ts +1 -2
  23. package/dist/reps.js +0 -2
  24. package/dist/results.d.ts +0 -9
  25. package/dist/results.js +2 -19
  26. package/dist/run.js +11 -72
  27. package/dist/seeded.d.ts +1 -7
  28. package/dist/seeded.js +5 -11
  29. package/dist/sources.js +4 -9
  30. package/dist/spec.d.ts +0 -13
  31. package/dist/spec.js +6 -48
  32. package/dist/trajectory-events.d.ts +58 -0
  33. package/dist/trajectory-events.js +119 -0
  34. package/package.json +1 -1
  35. package/schemas/results-v2.schema.json +376 -75
  36. package/schemas/specification-v1.schema.json +128 -174
  37. package/dist/adjudication.d.ts +0 -219
  38. package/dist/adjudication.js +0 -422
  39. package/dist/adoption.d.ts +0 -128
  40. package/dist/adoption.js +0 -102
  41. package/dist/affected.d.ts +0 -88
  42. package/dist/affected.js +0 -222
  43. package/dist/capture.d.ts +0 -193
  44. package/dist/capture.js +0 -344
  45. package/dist/comparison.d.ts +0 -97
  46. package/dist/comparison.js +0 -189
  47. package/dist/factory-calibration.d.ts +0 -63
  48. package/dist/factory-calibration.js +0 -115
  49. package/dist/intervention-results.d.ts +0 -6
  50. package/dist/intervention-results.js +0 -52
  51. package/dist/intervention.d.ts +0 -123
  52. package/dist/intervention.js +0 -218
  53. package/dist/investigation.d.ts +0 -94
  54. package/dist/investigation.js +0 -148
  55. package/dist/judge-agreement.d.ts +0 -19
  56. package/dist/judge-agreement.js +0 -31
  57. package/dist/qualification-capture.d.ts +0 -44
  58. package/dist/qualification-capture.js +0 -163
  59. package/dist/qualification-config.d.ts +0 -233
  60. package/dist/qualification-config.js +0 -694
  61. package/dist/qualification-lock.d.ts +0 -15
  62. package/dist/qualification-lock.js +0 -87
  63. package/dist/qualification-oauth-directory.d.ts +0 -79
  64. package/dist/qualification-oauth-directory.js +0 -444
  65. package/dist/qualification-panel-store.d.ts +0 -14
  66. package/dist/qualification-panel-store.js +0 -188
  67. package/dist/qualification-panels.d.ts +0 -99
  68. package/dist/qualification-panels.js +0 -91
  69. package/dist/qualification-process.d.ts +0 -13
  70. package/dist/qualification-process.js +0 -190
  71. package/dist/qualification-runner.d.ts +0 -203
  72. package/dist/qualification-runner.js +0 -2037
  73. package/dist/qualification-store.d.ts +0 -187
  74. package/dist/qualification-store.js +0 -833
  75. package/dist/qualification-validation.d.ts +0 -12
  76. package/dist/qualification-validation.js +0 -8
  77. package/dist/screen.d.ts +0 -31
  78. package/dist/screen.js +0 -105
  79. package/dist/trajectory-gates.d.ts +0 -137
  80. package/dist/trajectory-gates.js +0 -576
  81. package/dist/trusted-host-supervision.d.ts +0 -25
  82. package/dist/trusted-host-supervision.js +0 -94
  83. package/dist/work-capture-schema.d.ts +0 -38
  84. package/dist/work-capture-schema.js +0 -33
  85. package/dist/work-capture.d.ts +0 -43
  86. package/dist/work-capture.js +0 -81
  87. package/dist/work-signals.d.ts +0 -55
  88. package/dist/work-signals.js +0 -71
  89. package/schemas/qualification-cell-result-v1.schema.json +0 -32
  90. package/schemas/qualification-config-v1.schema.json +0 -244
  91. package/schemas/qualification-invocation-request-v1.schema.json +0 -59
  92. package/schemas/qualification-judge-panel-result-v1.schema.json +0 -42
  93. package/schemas/trajectory-event-v1.schema.json +0 -80
@@ -1,94 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { qualificationProcessIdentity, cleanupQualificationProcessGroupAfterLeaderExit, terminateQualificationProcess } from './qualification-process.js';
3
- const monitored = new WeakSet();
4
- /** Observe an ALREADY admitted, caller-owned detached Linux child, after its spawn event.
5
- * No spawn/authorization/accounting/retry is performed here. The parent event loop must
6
- * remain responsive. Occurrence-safe same-group cleanup is not hostile-code containment,
7
- * survivor/crash recovery, hard aggregate RAM/CPU, or proof of remote provider termination.
8
- * Bytes are discarded, not retained or hashed; the existing worker journal owns artifacts. */
9
- export async function superviseTrustedHost(child, limits) {
10
- if (process.platform !== 'linux')
11
- throw Error('trusted host supervision requires Linux occurrence identity');
12
- if (!(limits.signal instanceof AbortSignal) || !Number.isSafeInteger(limits.wallMs) || limits.wallMs < 1 || limits.wallMs > 150000 || !Number.isSafeInteger(limits.settlementMs) || limits.settlementMs < 100 || limits.settlementMs > 5000 || !Number.isSafeInteger(limits.maxOutputBytes) || limits.maxOutputBytes < 1 || limits.maxOutputBytes > 1048576)
13
- throw Error('bounded trusted host limits required');
14
- if (monitored.has(child))
15
- throw Error('original child already monitored; no retry');
16
- if (!child.pid || !child.stdout || !child.stderr || child.exitCode !== null || child.signalCode !== null)
17
- throw Error('live caller-owned child with output pipes required');
18
- const identity = qualificationProcessIdentity(child.pid), stat = readFileSync(`/proc/${child.pid}/stat`, 'utf8'), fields = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
19
- if (Number(fields[2]) !== child.pid || fields[19] !== identity.start_ticks)
20
- throw Error('original detached process group required');
21
- monitored.add(child);
22
- const stdout = child.stdout, stderr = child.stderr;
23
- return new Promise(resolve => {
24
- let reason = null, done = false, exited = false, closed = false, exitCode = null, signal = null, stdoutBytes = 0, stderrBytes = 0, cleanupAttempted = false;
25
- let settling, cleanup = null;
26
- const finish = (outcome) => {
27
- if (done)
28
- return;
29
- done = true;
30
- clearTimeout(wall);
31
- clearTimeout(settling);
32
- limits.signal.removeEventListener('abort', abort);
33
- stdout.off('data', out);
34
- stderr.off('data', err);
35
- stdout.resume();
36
- stderr.resume();
37
- child.off('exit', exit);
38
- child.off('close', close);
39
- child.off('error', error);
40
- // On unknown, the caller still owns this child and occurrence. Never claim settlement.
41
- resolve({ outcome, identity, exitCode, signal, stdoutBytes, stderrBytes, truncated: stdoutBytes + stderrBytes > limits.maxOutputBytes, cleanupAttempted, acceptance: 'not-assessed' });
42
- };
43
- const boundSettlement = () => { settling ??= setTimeout(() => finish('unknown'), limits.settlementMs); };
44
- const stop = (why) => {
45
- if (done)
46
- return;
47
- reason ??= why;
48
- boundSettlement();
49
- if (cleanupAttempted)
50
- return;
51
- cleanupAttempted = true;
52
- try {
53
- terminateQualificationProcess(child, identity);
54
- }
55
- catch {
56
- finish('unknown');
57
- }
58
- };
59
- const out = (b) => { stdoutBytes += b.length; if (stdoutBytes + stderrBytes > limits.maxOutputBytes)
60
- stop('output-limit'); };
61
- const err = (b) => { stderrBytes += b.length; if (stdoutBytes + stderrBytes > limits.maxOutputBytes)
62
- stop('output-limit'); };
63
- const abort = () => stop('aborted');
64
- const error = () => stop('failed');
65
- const complete = () => {
66
- if (!exited || !closed || done)
67
- return;
68
- void (cleanup ?? Promise.resolve()).then(() => finish(reason ?? (exitCode === 0 ? 'completed' : 'failed')), () => finish('unknown'));
69
- };
70
- const exit = (code, sig) => {
71
- exited = true;
72
- exitCode = code;
73
- signal = sig;
74
- clearTimeout(wall);
75
- boundSettlement();
76
- cleanupAttempted = true;
77
- cleanup = cleanupQualificationProcessGroupAfterLeaderExit(child.pid, identity);
78
- // Attach rejection handling immediately, even if descendant-held pipes never close.
79
- void cleanup.catch(() => finish('unknown'));
80
- complete();
81
- };
82
- const close = () => { closed = true; complete(); };
83
- const wall = setTimeout(() => stop('timed-out'), limits.wallMs);
84
- stdout.on('data', out);
85
- stderr.on('data', err);
86
- child.once('error', error);
87
- child.once('exit', exit);
88
- child.once('close', close);
89
- limits.signal.addEventListener('abort', abort, { once: true });
90
- if (limits.signal.aborted)
91
- abort();
92
- });
93
- }
94
- //# sourceMappingURL=trusted-host-supervision.js.map
@@ -1,38 +0,0 @@
1
- export declare const WORK_CAPTURE_SCHEMA: {
2
- oneOf: ({
3
- properties: {
4
- reason: {
5
- const: string;
6
- };
7
- classification: {
8
- const: string;
9
- };
10
- metrics: {
11
- required: string[];
12
- };
13
- };
14
- } | {
15
- properties: {
16
- reason: {
17
- const: string;
18
- };
19
- classification: {
20
- const: string;
21
- };
22
- metrics?: undefined;
23
- };
24
- })[];
25
- type: string;
26
- properties: Record<string, object>;
27
- required: string[];
28
- additionalProperties: boolean;
29
- $schema: string;
30
- $id: string;
31
- };
32
- export declare const WORK_CASE_REVIEW_REQUEST_SCHEMA: {
33
- type: string;
34
- properties: Record<string, object>;
35
- required: string[];
36
- additionalProperties: boolean;
37
- $schema: string;
38
- };
@@ -1,33 +0,0 @@
1
- const text = { type: "string", minLength: 1, maxLength: 512, pattern: "^[^\\u0000-\\u001f\\u007f]+$" };
2
- const hash = { type: "string", pattern: "^[a-f0-9]{64}$" };
3
- const closed = (properties, required = Object.keys(properties)) => ({ type: "object", properties, required, additionalProperties: false });
4
- const evidence = { type: "array", items: hash, minItems: 1, maxItems: 256, uniqueItems: true };
5
- const metric = { type: "number", minimum: 0 };
6
- function freeze(value) { if (value && typeof value === "object") {
7
- Object.values(value).forEach(freeze);
8
- Object.freeze(value);
9
- } return value; }
10
- export const WORK_CAPTURE_SCHEMA = freeze({
11
- $schema: "https://json-schema.org/draft/2020-12/schema",
12
- $id: "https://github.com/mojomanyana/skill-harness/contracts/work-capture/v2/work-case.schema.json",
13
- ...closed({ capture_schema: { const: 2 }, id: hash,
14
- detector: closed({ id: text, version: text, population: text }),
15
- target: closed({ kind: { const: "work" }, snapshotDigest: hash, obligationId: text, obligationDigest: hash }),
16
- classification: { enum: ["candidate_defect", "candidate_exemplar", "coverage_issue"] },
17
- reason: { enum: ["repeat_without_progress", "economical_exemplar", "coverage_gap"] }, evidence,
18
- metrics: closed({ equivalentAttempts: { type: "integer", minimum: 2, maximum: Number.MAX_SAFE_INTEGER }, measuredCost: metric,
19
- costLimit: metric, costUnit: { enum: ["wall_ms", "tool_calls", "usd"] } }, []),
20
- status: { const: "unresolved" }, visibility: { const: "silent" }, causalAttribution: { const: "not-established" },
21
- }),
22
- oneOf: [
23
- { properties: { reason: { const: "repeat_without_progress" }, classification: { const: "candidate_defect" }, metrics: { required: ["equivalentAttempts"] } } },
24
- { properties: { reason: { const: "economical_exemplar" }, classification: { const: "candidate_exemplar" }, metrics: { required: ["measuredCost", "costLimit", "costUnit"] } } },
25
- { properties: { reason: { const: "coverage_gap" }, classification: { const: "coverage_issue" } } },
26
- ],
27
- });
28
- export const WORK_CASE_REVIEW_REQUEST_SCHEMA = freeze({
29
- $schema: "https://json-schema.org/draft/2020-12/schema",
30
- ...closed({ caseManifestId: hash, priorDecisionId: { anyOf: [hash, { type: "null" }] },
31
- disposition: { enum: ["confirmed_defect", "expected_behavior", "exemplar", "uncertain", "skip"] }, note: { type: "string", maxLength: 4000 } }),
32
- });
33
- //# sourceMappingURL=work-capture-schema.js.map
@@ -1,43 +0,0 @@
1
- /** Separate from human-authored capture_schema1; a nomination is not a test, verdict or promotion. */
2
- export interface WorkCaptureCaseV2 {
3
- capture_schema: 2;
4
- id: string;
5
- detector: {
6
- id: string;
7
- version: string;
8
- population: string;
9
- };
10
- target: {
11
- kind: "work";
12
- snapshotDigest: string;
13
- obligationId: string;
14
- obligationDigest: string;
15
- };
16
- classification: "candidate_defect" | "candidate_exemplar" | "coverage_issue";
17
- reason: "repeat_without_progress" | "economical_exemplar" | "coverage_gap";
18
- evidence: string[];
19
- metrics: {
20
- equivalentAttempts?: number;
21
- measuredCost?: number;
22
- costLimit?: number;
23
- costUnit?: "wall_ms" | "tool_calls" | "usd";
24
- };
25
- status: "unresolved";
26
- visibility: "silent";
27
- causalAttribution: "not-established";
28
- }
29
- export type WorkCaseDisposition = "confirmed_defect" | "expected_behavior" | "exemplar" | "uncertain" | "skip";
30
- export interface WorkCaseDecision {
31
- decision_schema: 1;
32
- id: string;
33
- caseId: string;
34
- priorDecisionId: string | null;
35
- disposition: WorkCaseDisposition;
36
- /** Attributable controller-supplied author, never filled from a nominator's hypothesis. */
37
- author: string;
38
- evidence: string[];
39
- note: string;
40
- }
41
- export declare function buildWorkCapture(input: Omit<WorkCaptureCaseV2, "capture_schema" | "id" | "status" | "visibility" | "causalAttribution">): WorkCaptureCaseV2;
42
- /** Immutable correction chain. Calling code must establish the registered case and authorized author. */
43
- export declare function appendWorkCaseDecision(history: readonly WorkCaseDecision[], input: Omit<WorkCaseDecision, "decision_schema" | "id">): WorkCaseDecision[];
@@ -1,81 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- const canonical = (value) => Array.isArray(value) ? `[${value.map(canonical).join(",")}]`
3
- : value !== null && typeof value === "object" ? `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`
4
- : JSON.stringify(value);
5
- const sha = (value) => createHash("sha256").update(canonical(value)).digest("hex");
6
- function closed(value, names) {
7
- if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
8
- return false;
9
- const fields = Object.getOwnPropertyDescriptors(value);
10
- return Reflect.ownKeys(fields).length === names.length && Reflect.ownKeys(fields).every(key => typeof key === "string" && names.includes(key) && fields[key].enumerable && Object.hasOwn(fields[key], "value"));
11
- }
12
- const hash = /^[a-f0-9]{64}$/;
13
- const text = (s) => typeof s === "string" && s.length > 0 && s.length <= 512 && !/[\u0000-\u001f\u007f]/.test(s);
14
- export function buildWorkCapture(input) {
15
- if (!closed(input, ["detector", "target", "classification", "reason", "evidence", "metrics"])
16
- || !closed(input.detector, ["id", "version", "population"]) || !closed(input.target, ["kind", "snapshotDigest", "obligationId", "obligationDigest"])
17
- || !input.metrics || typeof input.metrics !== "object" || !closed(input.metrics, Object.keys(input.metrics))
18
- || !Array.isArray(input.evidence) || input.evidence.length < 1 || input.evidence.length > 256
19
- || Array.from({ length: input.evidence.length }, (_, i) => i).some(i => !Object.hasOwn(input.evidence, i)))
20
- throw new Error("invalid work capture fields");
21
- if (![input.detector.id, input.detector.version, input.detector.population, input.target.obligationId].every(text)
22
- || input.target.kind !== "work" || !hash.test(input.target.snapshotDigest) || !hash.test(input.target.obligationDigest)
23
- || input.evidence.length > 256 || input.evidence.some(e => !hash.test(e))
24
- || !["candidate_defect", "candidate_exemplar", "coverage_issue"].includes(input.classification)
25
- || !["repeat_without_progress", "economical_exemplar", "coverage_gap"].includes(input.reason)
26
- || Object.keys(input.metrics).some(k => !["equivalentAttempts", "measuredCost", "costLimit", "costUnit"].includes(k))
27
- || Object.entries(input.metrics).some(([key, n]) => key === "costUnit" ? !["wall_ms", "tool_calls", "usd"].includes(String(n)) : typeof n !== "number" || !Number.isFinite(n) || n < 0)
28
- || (input.reason === "repeat_without_progress" && (input.metrics.equivalentAttempts === undefined || input.metrics.equivalentAttempts < 2))
29
- || (input.reason === "economical_exemplar" && (input.metrics.measuredCost === undefined || input.metrics.costLimit === undefined || input.metrics.costUnit === undefined || input.metrics.measuredCost > input.metrics.costLimit))
30
- || (input.metrics.equivalentAttempts !== undefined && !Number.isSafeInteger(input.metrics.equivalentAttempts)))
31
- throw new Error("invalid work capture nomination");
32
- const expected = { repeat_without_progress: "candidate_defect", economical_exemplar: "candidate_exemplar", coverage_gap: "coverage_issue" };
33
- if (input.classification !== expected[input.reason])
34
- throw new Error("work capture classification mismatch");
35
- const detector = { id: input.detector.id, version: input.detector.version, population: input.detector.population };
36
- const target = { kind: "work", snapshotDigest: input.target.snapshotDigest, obligationId: input.target.obligationId, obligationDigest: input.target.obligationDigest };
37
- return { capture_schema: 2, id: sha({ detector, target, reason: input.reason }), detector, target,
38
- classification: input.classification, reason: input.reason, evidence: [...new Set(input.evidence)].sort(), metrics: Object.fromEntries(Object.entries(input.metrics).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)),
39
- status: "unresolved", visibility: "silent", causalAttribution: "not-established" };
40
- }
41
- function validDecision(value) {
42
- return closed(value, ["caseId", "priorDecisionId", "disposition", "author", "evidence", "note"])
43
- && typeof value.caseId === "string" && hash.test(value.caseId)
44
- && (value.priorDecisionId === null || (typeof value.priorDecisionId === "string" && hash.test(value.priorDecisionId)))
45
- && text(value.author) && typeof value.note === "string" && value.note.length <= 4000
46
- && Array.isArray(value.evidence) && value.evidence.length <= 256
47
- && Array.from({ length: value.evidence.length }, (_, i) => i).every(i => Object.hasOwn(value.evidence, i) && typeof value.evidence[i] === "string" && hash.test(value.evidence[i]))
48
- && ["confirmed_defect", "expected_behavior", "exemplar", "uncertain", "skip"].includes(value.disposition);
49
- }
50
- /** Immutable correction chain. Calling code must establish the registered case and authorized author. */
51
- export function appendWorkCaseDecision(history, input) {
52
- if (!validDecision(input))
53
- throw new Error("invalid case decision");
54
- if (history.length > 4096)
55
- throw new Error("case decision history exceeds bound");
56
- const heads = new Map();
57
- const seen = new Set();
58
- for (const decision of history) {
59
- if (!closed(decision, ["decision_schema", "id", "caseId", "priorDecisionId", "disposition", "author", "evidence", "note"]) || decision.decision_schema !== 1)
60
- throw new Error("invalid case decision history");
61
- const { decision_schema: _schema, id: recordedId, ...prior } = decision;
62
- if (!validDecision(prior) || sha(prior) !== recordedId)
63
- throw new Error("case decision history identity mismatch");
64
- if (seen.has(recordedId))
65
- continue;
66
- if ((heads.get(decision.caseId) ?? null) !== decision.priorDecisionId)
67
- throw new Error("case decision history fork or missing parent");
68
- seen.add(recordedId);
69
- heads.set(decision.caseId, recordedId);
70
- }
71
- const body = { ...input, evidence: [...new Set(input.evidence)].sort() };
72
- const id = sha(body);
73
- if (history.some(d => d.id === id))
74
- return [...history];
75
- const own = history.filter(d => d.caseId === input.caseId);
76
- const last = own.at(-1)?.id ?? null;
77
- if (last !== input.priorDecisionId)
78
- throw new Error("stale case decision");
79
- return [...history, { decision_schema: 1, id, ...body }];
80
- }
81
- //# sourceMappingURL=work-capture.js.map
@@ -1,55 +0,0 @@
1
- import { type WorkCaptureCaseV2 } from "./work-capture.js";
2
- export interface WorkSignalSnapshot {
3
- snapshotDigest: string;
4
- scopeValid: boolean;
5
- obligations: Array<{
6
- id: string;
7
- digest: string;
8
- intentDigest: string;
9
- policyDigest: string;
10
- artifactDigest: string | null;
11
- acceptance: "accepted-under-supplied-authority" | "unaccepted" | "unresolved";
12
- coverage: "available" | "unknown" | "unavailable" | "conflicted";
13
- }>;
14
- }
15
- export interface WorkSignalFacts {
16
- scopeDigest: string;
17
- version: string;
18
- population: string;
19
- expectedWaits: string[];
20
- /** Frozen host facts, not inferred from absence in a display or from worker prose. */
21
- checkpoints: Array<{
22
- obligationDigest: string;
23
- deadlineMs: number;
24
- observedAt: number;
25
- status: "met" | "pending" | "unknown";
26
- evidence: string;
27
- }>;
28
- violations: Array<{
29
- obligationDigest: string;
30
- status: "FAIL" | "ERROR";
31
- evidence: string;
32
- }>;
33
- priorAccepted: Array<{
34
- obligationDigest: string;
35
- intentDigest: string;
36
- policyDigest: string;
37
- artifactDigest: string;
38
- acceptanceEvidence: string;
39
- }>;
40
- }
41
- export interface WorkCaptureCaseV3 extends Omit<WorkCaptureCaseV2, "capture_schema" | "reason" | "metrics"> {
42
- capture_schema: 3;
43
- reason: "overdue_checkpoint" | "reopened_acceptance" | "intent_conflict";
44
- metrics: {
45
- deadlineMs?: number;
46
- observedAt?: number;
47
- failedChecks?: number;
48
- };
49
- }
50
- /** Additional rules use an explicit new case version; the already-pinned capture_schema2 contract is unchanged. */
51
- export declare function detectAdditionalWorkCases(snapshot: WorkSignalSnapshot, facts: WorkSignalFacts): {
52
- version: "work-signals-v1";
53
- cases: (WorkCaptureCaseV2 | WorkCaptureCaseV3)[];
54
- issues: string[];
55
- };
@@ -1,71 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { buildWorkCapture } from "./work-capture.js";
3
- const hash = (x) => typeof x === "string" && /^[a-f0-9]{64}$/.test(x);
4
- const text = (x) => typeof x === "string" && x.length > 0 && x.length <= 512 && !/[\u0000-\u001f\u007f]/.test(x);
5
- function signal(base, reason, metrics, evidence) {
6
- const target = base.target, detector = { id: reason, version: base.detector.version, population: base.detector.population };
7
- const id = createHash("sha256").update(JSON.stringify({ capture_schema: 3, detector, target, reason, metrics, evidence: [...new Set(evidence)].sort() })).digest("hex");
8
- return Object.freeze({ ...base, capture_schema: 3, id, detector: Object.freeze(detector), reason, classification: "candidate_defect", metrics: Object.freeze(metrics), evidence: Object.freeze([...new Set(evidence)].sort()) });
9
- }
10
- /** Additional rules use an explicit new case version; the already-pinned capture_schema2 contract is unchanged. */
11
- export function detectAdditionalWorkCases(snapshot, facts) {
12
- if (!hash(snapshot.snapshotDigest) || !hash(facts.scopeDigest) || snapshot.snapshotDigest !== facts.scopeDigest)
13
- throw new Error("work signal scope mismatch");
14
- if (!text(facts.version) || facts.version.length > 128 || !text(facts.population) || !Array.isArray(snapshot.obligations) || snapshot.obligations.length > 256
15
- || ![facts.expectedWaits, facts.checkpoints, facts.violations, facts.priorAccepted].every(a => Array.isArray(a) && a.length <= 256)
16
- || facts.expectedWaits.some(d => !hash(d)))
17
- throw new Error("invalid work signal bounds");
18
- for (const o of snapshot.obligations)
19
- if (!text(o.id) || ![o.digest, o.intentDigest, o.policyDigest].every(hash) || !(o.artifactDigest === null || hash(o.artifactDigest))
20
- || !["accepted-under-supplied-authority", "unaccepted", "unresolved"].includes(o.acceptance) || !["available", "unknown", "unavailable", "conflicted"].includes(o.coverage))
21
- throw new Error("invalid work signal obligation");
22
- for (const c of facts.checkpoints)
23
- if (!hash(c.obligationDigest) || !hash(c.evidence) || !["met", "pending", "unknown"].includes(c.status)
24
- || ![c.deadlineMs, c.observedAt].every(n => Number.isSafeInteger(n) && n >= 0))
25
- throw new Error("invalid declared checkpoint fact");
26
- for (const v of facts.violations)
27
- if (!hash(v.obligationDigest) || !hash(v.evidence) || !["FAIL", "ERROR"].includes(v.status))
28
- throw new Error("invalid objective intent fact");
29
- for (const p of facts.priorAccepted)
30
- if (![p.obligationDigest, p.intentDigest, p.policyDigest, p.artifactDigest, p.acceptanceEvidence].every(hash))
31
- throw new Error("invalid prior acceptance fact");
32
- const cases = [];
33
- if (snapshot.scopeValid !== true)
34
- return { version: "work-signals-v1", cases, issues: ["scope-unresolved"] };
35
- for (const o of snapshot.obligations) {
36
- const base = buildWorkCapture({ detector: { id: "coverage_gap", version: `work-signals-v1:${facts.version}`, population: facts.population },
37
- target: { kind: "work", snapshotDigest: snapshot.snapshotDigest, obligationId: o.id, obligationDigest: o.digest },
38
- classification: "coverage_issue", reason: "coverage_gap", metrics: {}, evidence: [snapshot.snapshotDigest, o.digest] });
39
- const violations = facts.violations.filter(v => v.obligationDigest === o.digest);
40
- const checkpointFacts = facts.checkpoints.filter(c => c.obligationDigest === o.digest);
41
- const checkpointStates = new Set(checkpointFacts.map(c => JSON.stringify([c.deadlineMs, c.observedAt, c.status, c.evidence])));
42
- if (checkpointStates.size > 1) {
43
- cases.push(base);
44
- continue;
45
- } // No latest-timestamp election from contradictory host facts.
46
- if (o.coverage !== "available" || o.acceptance === "unresolved" || violations.some(v => v.status === "ERROR")) {
47
- cases.push(base);
48
- continue;
49
- }
50
- if (violations.length)
51
- cases.push(signal(base, "intent_conflict", { failedChecks: violations.length }, [...base.evidence, ...violations.map(v => v.evidence)]));
52
- if (facts.expectedWaits.includes(o.digest))
53
- continue;
54
- for (const c of checkpointFacts) {
55
- if (c.status === "unknown") {
56
- cases.push(base);
57
- continue;
58
- }
59
- if (c.status === "pending" && c.observedAt > c.deadlineMs)
60
- cases.push(signal(base, "overdue_checkpoint", { deadlineMs: c.deadlineMs, observedAt: c.observedAt }, [...base.evidence, c.evidence]));
61
- }
62
- if (o.acceptance === "unaccepted") {
63
- const prior = facts.priorAccepted.filter(p => p.obligationDigest === o.digest && p.intentDigest === o.intentDigest && p.policyDigest === o.policyDigest && p.artifactDigest === o.artifactDigest);
64
- if (prior.length)
65
- cases.push(signal(base, "reopened_acceptance", {}, [...base.evidence, ...prior.map(p => p.acceptanceEvidence)]));
66
- }
67
- }
68
- const unique = [...new Map(cases.map(c => [c.id, c])).values()].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
69
- return { version: "work-signals-v1", cases: unique, issues: [] };
70
- }
71
- //# sourceMappingURL=work-signals.js.map
@@ -1,32 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://skill-harness.dev/schemas/qualification-cell-result-v1.schema.json",
4
- "title": "skill-harness qualification cell result v1",
5
- "type": "object",
6
- "additionalProperties": false,
7
- "required": ["schema_version", "cell_id", "scenario_id", "subject_arm", "critical", "pass_threshold", "panels", "critical_failure", "acceptance", "collection", "disagreement"],
8
- "properties": {
9
- "schema_version": { "const": "qualification-cell-result-v1" },
10
- "cell_id": { "$ref": "#/$defs/id" }, "scenario_id": { "$ref": "#/$defs/id" }, "subject_arm": { "$ref": "#/$defs/id" },
11
- "critical": { "type": "boolean" }, "pass_threshold": { "type": "integer", "minimum": 1 },
12
- "panels": { "type": "array", "minItems": 1, "items": { "$ref": "qualification-judge-panel-result-v1.schema.json" } },
13
- "verdict": { "enum": ["PASS", "FAIL"] }, "critical_failure": { "type": "boolean" },
14
- "acceptance": { "enum": ["pass", "fail", "inconclusive"] }, "collection": { "const": "continue" },
15
- "disagreement": {
16
- "type": "object", "additionalProperties": false,
17
- "required": ["judge_calls", "clean_votes", "split_artifacts", "artifacts_with_two_clean_initial_votes", "unresolved_artifacts", "judge_split_rate"],
18
- "properties": {
19
- "judge_calls": { "type": "integer", "minimum": 0 }, "clean_votes": { "type": "integer", "minimum": 0 },
20
- "split_artifacts": { "type": "integer", "minimum": 0 }, "artifacts_with_two_clean_initial_votes": { "type": "integer", "minimum": 0 },
21
- "unresolved_artifacts": { "type": "integer", "minimum": 0 }, "judge_split_rate": { "type": "number", "minimum": 0, "maximum": 1 }
22
- }
23
- }
24
- },
25
- "allOf": [
26
- { "if": { "properties": { "acceptance": { "const": "inconclusive" } }, "required": ["acceptance"] }, "then": { "not": { "properties": { "verdict": {} }, "required": ["verdict"] }, "properties": { "critical_failure": { "const": false } } }, "else": { "required": ["verdict"] } },
27
- { "if": { "properties": { "acceptance": { "const": "pass" } }, "required": ["acceptance"] }, "then": { "properties": { "verdict": { "const": "PASS" }, "critical_failure": { "const": false } } } },
28
- { "if": { "properties": { "acceptance": { "const": "fail" } }, "required": ["acceptance"] }, "then": { "properties": { "verdict": { "const": "FAIL" } }, "required": ["verdict"] } },
29
- { "if": { "properties": { "critical_failure": { "const": true } }, "required": ["critical_failure"] }, "then": { "properties": { "critical": { "const": true }, "acceptance": { "const": "fail" }, "verdict": { "const": "FAIL" } }, "required": ["verdict"] } }
30
- ],
31
- "$defs": { "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" } }
32
- }