@skill-harness/core 0.11.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 (95) hide show
  1. package/README.md +2 -1
  2. package/dist/adapters/types.d.ts +19 -0
  3. package/dist/adjudication.d.ts +9 -1
  4. package/dist/adjudication.js +41 -33
  5. package/dist/adoption.d.ts +128 -0
  6. package/dist/adoption.js +102 -0
  7. package/dist/arms.d.ts +1 -1
  8. package/dist/capture-trace-types.d.ts +2 -0
  9. package/dist/command-cost.d.ts +9 -0
  10. package/dist/command-cost.js +23 -0
  11. package/dist/comparison.d.ts +1 -0
  12. package/dist/comparison.js +9 -3
  13. package/dist/execution-trace.js +9 -1
  14. package/dist/factory-calibration.d.ts +63 -0
  15. package/dist/factory-calibration.js +115 -0
  16. package/dist/grade.d.ts +2 -0
  17. package/dist/grade.js +2 -1
  18. package/dist/index.d.ts +21 -0
  19. package/dist/index.js +21 -0
  20. package/dist/intervention-results.d.ts +6 -0
  21. package/dist/intervention-results.js +52 -0
  22. package/dist/intervention.d.ts +123 -0
  23. package/dist/intervention.js +218 -0
  24. package/dist/investigation.d.ts +94 -0
  25. package/dist/investigation.js +148 -0
  26. package/dist/journal.d.ts +1 -1
  27. package/dist/judge-agreement.d.ts +19 -0
  28. package/dist/judge-agreement.js +31 -0
  29. package/dist/judge-policy.js +5 -3
  30. package/dist/lift.js +1 -1
  31. package/dist/lint.js +1 -1
  32. package/dist/prompt-normalization.d.ts +6 -0
  33. package/dist/prompt-normalization.js +14 -0
  34. package/dist/qualification-capture.d.ts +44 -0
  35. package/dist/qualification-capture.js +163 -0
  36. package/dist/qualification-config.d.ts +233 -0
  37. package/dist/qualification-config.js +694 -0
  38. package/dist/qualification-lock.d.ts +15 -0
  39. package/dist/qualification-lock.js +87 -0
  40. package/dist/qualification-oauth-directory.d.ts +79 -0
  41. package/dist/qualification-oauth-directory.js +444 -0
  42. package/dist/qualification-panel-store.d.ts +14 -0
  43. package/dist/qualification-panel-store.js +188 -0
  44. package/dist/qualification-panels.d.ts +99 -0
  45. package/dist/qualification-panels.js +91 -0
  46. package/dist/qualification-process.d.ts +13 -0
  47. package/dist/qualification-process.js +190 -0
  48. package/dist/qualification-runner.d.ts +203 -0
  49. package/dist/qualification-runner.js +2037 -0
  50. package/dist/qualification-store.d.ts +187 -0
  51. package/dist/qualification-store.js +833 -0
  52. package/dist/qualification-validation.d.ts +12 -0
  53. package/dist/qualification-validation.js +8 -0
  54. package/dist/regate.js +42 -10
  55. package/dist/regrade.d.ts +3 -1
  56. package/dist/regrade.js +37 -5
  57. package/dist/reps.d.ts +4 -2
  58. package/dist/reps.js +13 -4
  59. package/dist/rescore.js +2 -1
  60. package/dist/results.d.ts +53 -7
  61. package/dist/results.js +210 -7
  62. package/dist/run.js +66 -17
  63. package/dist/score.d.ts +4 -3
  64. package/dist/score.js +13 -4
  65. package/dist/screen.d.ts +31 -0
  66. package/dist/screen.js +105 -0
  67. package/dist/seeded.d.ts +2 -1
  68. package/dist/seeded.js +1 -0
  69. package/dist/sources.d.ts +7 -1
  70. package/dist/sources.js +13 -5
  71. package/dist/spec.d.ts +1 -1
  72. package/dist/spec.js +1 -1
  73. package/dist/stability.js +1 -1
  74. package/dist/trajectory-gates.d.ts +14 -14
  75. package/dist/trajectory-gates.js +18 -34
  76. package/dist/trusted-host-supervision.d.ts +25 -0
  77. package/dist/trusted-host-supervision.js +94 -0
  78. package/dist/vote-panel.d.ts +33 -0
  79. package/dist/vote-panel.js +41 -0
  80. package/dist/work-capture-schema.d.ts +38 -0
  81. package/dist/work-capture-schema.js +33 -0
  82. package/dist/work-capture.d.ts +43 -0
  83. package/dist/work-capture.js +81 -0
  84. package/dist/work-signals.d.ts +55 -0
  85. package/dist/work-signals.js +71 -0
  86. package/dist/workspace.js +4 -1
  87. package/package.json +3 -3
  88. package/schemas/qualification-cell-result-v1.schema.json +32 -0
  89. package/schemas/qualification-config-v1.schema.json +244 -0
  90. package/schemas/qualification-invocation-request-v1.schema.json +59 -0
  91. package/schemas/qualification-judge-panel-result-v1.schema.json +42 -0
  92. package/schemas/results-v2.schema.json +19 -21
  93. package/schemas/results-v3.schema.json +654 -0
  94. package/schemas/specification-v1.schema.json +1 -1
  95. package/schemas/trajectory-event-v1.schema.json +20 -1
@@ -0,0 +1,38 @@
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
+ };
@@ -0,0 +1,33 @@
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
@@ -0,0 +1,43 @@
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[];
@@ -0,0 +1,81 @@
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
@@ -0,0 +1,55 @@
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
+ };
@@ -0,0 +1,71 @@
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
package/dist/workspace.js CHANGED
@@ -143,7 +143,10 @@ function gitBaseline(cwd) {
143
143
  * claim in the prompt, and needs no network.
144
144
  */
145
145
  function addLocalRemote(cwd) {
146
- const bare = mkdtempSync(join(tmpdir(), "sc-remote-")) + ".git";
146
+ // Use the directory mkdtemp created. Appending `.git` orphaned the original
147
+ // empty directory on every remote-backed scenario because cleanup removed only
148
+ // the suffixed repository.
149
+ const bare = mkdtempSync(join(tmpdir(), "sc-remote-"));
147
150
  execFileSync("git", ["init", "-q", "--bare", "-b", "main", bare], { timeout: GIT_TIMEOUT_MS });
148
151
  execFileSync("git", ["remote", "add", "origin", bare], { cwd, timeout: GIT_TIMEOUT_MS });
149
152
  execFileSync("git", ["push", "-q", "-u", "origin", "main"], { cwd, timeout: GIT_TIMEOUT_MS });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-harness/core",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "skill-harness engine — spec, discover, run, LLM-judge grade, score, results (internal API)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -39,9 +39,9 @@
39
39
  "node": ">=20"
40
40
  },
41
41
  "scripts": {
42
- "prepack": "rm -rf ./schemas && cp -R ../../schemas ./schemas && cp ../../LICENSE ./LICENSE"
42
+ "prepack": "node ../../scripts/release-pack.mjs --guard"
43
43
  },
44
44
  "dependencies": {
45
- "js-yaml": "^4.1.0"
45
+ "js-yaml": "^4.3.1"
46
46
  }
47
47
  }
@@ -0,0 +1,32 @@
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
+ }