@skill-harness/cli 0.26.2 → 0.27.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.
- package/dist/decision.js +98 -9
- package/package.json +3 -3
package/dist/decision.js
CHANGED
|
@@ -716,6 +716,88 @@ async function writePreparedExport({ prepared, directory }) {
|
|
|
716
716
|
return { directory, trainingEligible: prepared.metadata.trainingEligible, files: Object.fromEntries(Object.entries(prepared.files).map(([name, s]) => [name, { sha256: learningDigest(s), bytes: Buffer.byteLength(s) }])) };
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
+
// experiments/decision-shadow/workflow-fixtures.mjs
|
|
720
|
+
var WORKFLOW_ORACLE_VERSION = "workflow-convergence-oracles-v1";
|
|
721
|
+
function evaluateWorkflowFixture(family, facts) {
|
|
722
|
+
if (!facts || typeof facts !== "object" || Array.isArray(facts)) return false;
|
|
723
|
+
switch (family) {
|
|
724
|
+
case "workspace":
|
|
725
|
+
return typeof facts.requestedRoot === "string" && facts.requestedRoot.startsWith("/") && facts.observedRoot === facts.requestedRoot && facts.pathsObserved === true && Array.isArray(facts.requiredPaths) && facts.requiredPaths.length > 0 && Array.isArray(facts.readablePaths) && facts.requiredPaths.every((path) => typeof path === "string" && path.startsWith(facts.requestedRoot + "/") && facts.readablePaths.includes(path));
|
|
726
|
+
case "identity":
|
|
727
|
+
return facts.expected?.algorithm === "principal-candidate-v1" && facts.actual?.algorithm === facts.expected.algorithm && typeof facts.expected.id === "string" && /^[a-f0-9]{64}$/.test(facts.expected.id) && facts.actual.id === facts.expected.id;
|
|
728
|
+
case "evidence":
|
|
729
|
+
return facts.candidateMatched === true && facts.referencesVerified === true && Array.isArray(facts.obligations) && facts.obligations.some((item) => item?.due === "review") && facts.obligations.every((item) => item && ["review", "finish"].includes(item.due) && typeof item.id === "string" && item.id.length > 0 && (item.due === "review" ? item.state === "verified" : ["pending", "verified"].includes(item.state)));
|
|
730
|
+
case "routing": {
|
|
731
|
+
if (facts.observationComplete !== true || !Array.isArray(facts.productFindings) || !Array.isArray(facts.dueEvidenceGaps)) return false;
|
|
732
|
+
const expected = facts.productFindings.length ? "build" : facts.dueEvidenceGaps.length ? "evidence" : "git-ops";
|
|
733
|
+
return facts.next === expected;
|
|
734
|
+
}
|
|
735
|
+
case "reuse":
|
|
736
|
+
return facts.operation === "static-inspection" && facts.purpose === "same-check" && facts.previous?.state === "complete" && facts.previous.outputsVerified === true && typeof facts.currentInput === "string" && /^[a-f0-9]{64}$/.test(facts.currentInput) && facts.previous.input === facts.currentInput && facts.previous.environment === facts.currentEnvironment && typeof facts.currentEnvironment === "string" && facts.currentEnvironment.length > 0;
|
|
737
|
+
default:
|
|
738
|
+
throw new TypeError("Unknown workflow fixture family");
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function workflowFixtureFamilies() {
|
|
742
|
+
const root = "/fixture/pilot", hash3 = "a".repeat(64);
|
|
743
|
+
const workspace = {
|
|
744
|
+
requestedRoot: root,
|
|
745
|
+
observedRoot: root,
|
|
746
|
+
pathsObserved: true,
|
|
747
|
+
requiredPaths: [`${root}/report.md`],
|
|
748
|
+
readablePaths: [`${root}/report.md`]
|
|
749
|
+
};
|
|
750
|
+
const identity2 = {
|
|
751
|
+
expected: { algorithm: "principal-candidate-v1", id: hash3 },
|
|
752
|
+
actual: { algorithm: "principal-candidate-v1", id: hash3 }
|
|
753
|
+
};
|
|
754
|
+
const evidence = {
|
|
755
|
+
candidateMatched: true,
|
|
756
|
+
referencesVerified: true,
|
|
757
|
+
obligations: [{ id: "behavior-check", due: "review", state: "verified" }, { id: "archive", due: "finish", state: "pending" }]
|
|
758
|
+
};
|
|
759
|
+
const routing = { observationComplete: true, productFindings: [], dueEvidenceGaps: ["missing-report"], next: "evidence" };
|
|
760
|
+
const reuse = {
|
|
761
|
+
operation: "static-inspection",
|
|
762
|
+
purpose: "same-check",
|
|
763
|
+
currentInput: hash3,
|
|
764
|
+
currentEnvironment: "node-fixture-v1",
|
|
765
|
+
previous: { state: "complete", input: hash3, environment: "node-fixture-v1", outputsVerified: true }
|
|
766
|
+
};
|
|
767
|
+
return [
|
|
768
|
+
{
|
|
769
|
+
family: "workspace",
|
|
770
|
+
split: "train",
|
|
771
|
+
question: "Do these explicitly observed roots and readable absolute paths establish access to the requested fixture workspace? Missing access evidence is not a permission-denial finding.",
|
|
772
|
+
facts: [workspace, { ...workspace, observedRoot: "/fixture/original" }, { ...workspace, readablePaths: [] }, { ...workspace, pathsObserved: false }]
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
family: "identity",
|
|
776
|
+
split: "train",
|
|
777
|
+
question: "Do these records contain matching full candidate IDs under the same principal-candidate-v1 algorithm? A diff hash or another algorithm is not an interchangeable candidate ID.",
|
|
778
|
+
facts: [identity2, { ...identity2, actual: { algorithm: "git-diff-sha256", id: hash3 } }, { ...identity2, actual: { algorithm: "principal-candidate-v1", id: "b".repeat(64) } }, { expected: { algorithm: "principal-candidate-v1", id: "aaaaaaa" }, actual: { algorithm: "principal-candidate-v1", id: "aaaaaaa" } }]
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
family: "evidence",
|
|
782
|
+
split: "validation",
|
|
783
|
+
question: "Are all review-due obligations verified by matching-candidate, verified references? Finish-due obligations may remain pending; a new runtime replay is not required by this fixture rule.",
|
|
784
|
+
facts: [evidence, { ...evidence, obligations: [{ id: "behavior-check", due: "review", state: "pending" }] }, { ...evidence, candidateMatched: false }, { ...evidence, referencesVerified: false }]
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
family: "routing",
|
|
788
|
+
split: "test",
|
|
789
|
+
question: "Does Next follow this explicit routing rule: observed product findings -> build, otherwise due evidence gaps -> evidence, otherwise git-ops? Incomplete observations cannot establish routing.",
|
|
790
|
+
facts: [routing, { ...routing, next: "build" }, { ...routing, productFindings: ["blocked-api-shutdown"], next: "build" }, { ...routing, observationComplete: false }]
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
family: "reuse",
|
|
794
|
+
split: "test",
|
|
795
|
+
question: "May this completed static inspection be reused for the same check, unchanged input/environment and verified outputs? A new independent review or live runtime observation requires a distinct operation.",
|
|
796
|
+
facts: [reuse, { ...reuse, previous: { ...reuse.previous, outputsVerified: false } }, { ...reuse, purpose: "independent-review" }, { ...reuse, operation: "live-database-observation" }]
|
|
797
|
+
}
|
|
798
|
+
];
|
|
799
|
+
}
|
|
800
|
+
|
|
719
801
|
// experiments/decision-shadow/learning-fixtures.mjs
|
|
720
802
|
var FIXTURE_ORACLE_VERSION = "mechanical-fixture-oracles-v1";
|
|
721
803
|
var COMMIT = /^[a-f0-9]{40}$/;
|
|
@@ -756,9 +838,10 @@ function evaluateFixture(family, e) {
|
|
|
756
838
|
throw new TypeError("Unknown fixture oracle family");
|
|
757
839
|
}
|
|
758
840
|
}
|
|
759
|
-
function createLearningFixtures({ recordedAt = "2026-10-08T00:00:00.000Z" } = {}) {
|
|
841
|
+
function createLearningFixtures({ recordedAt = "2026-10-08T00:00:00.000Z", set = "mechanical" } = {}) {
|
|
842
|
+
if (!["mechanical", "workflow"].includes(set)) throw new TypeError("Fixture set must be mechanical or workflow");
|
|
760
843
|
const commit = "a".repeat(40), complete = Object.fromEntries(PHASES.map((p) => [p, "complete"]));
|
|
761
|
-
const
|
|
844
|
+
const mechanicalFamilies = [
|
|
762
845
|
{ family: "candidate", split: "train", question: "Do the records establish one exact full 40-character lowercase Git candidate shared by candidate, tested and reviewed?", facts: [{ candidate: commit, tested: commit, reviewed: commit }, { candidate: commit, tested: "b".repeat(40), reviewed: commit }, { candidate: commit, tested: commit, reviewed: "c".repeat(40) }, { candidate: "aaaaaaa", tested: "aaaaaaa", reviewed: "aaaaaaa" }] },
|
|
763
846
|
{ family: "phases", split: "train", question: "Do the latest snapshots cover exactly every required step with all five named phases complete? Earlier complete phases cannot fill later omissions.", facts: [{ required: ["step-1"], records: [{ step: "step-1", phases: complete }] }, { required: ["step-1", "step-2"], records: [{ step: "step-1", phases: complete }] }, { required: ["step-1"], records: [{ step: "step-1", phases: complete }, { step: "step-extra", phases: complete }] }, { required: ["step-1"], records: [{ step: "step-1", phases: complete }, { step: "step-1", phases: { ...complete, verified: "unknown" } }] }] },
|
|
764
847
|
{ family: "findings", split: "train", question: "Does the observed finding history establish that every finding identity (step, source, id) has an explicit latest verified disposition? Omission never clears an earlier finding.", facts: [{ historyObserved: true, records: [{ step: "step-1", findings: [] }] }, { historyObserved: true, records: [{ step: "step-1", findings: [{ id: "f1", source: "report-a", status: "open" }] }, { step: "step-1", findings: [{ id: "f1", source: "report-a", status: "verified" }] }] }, { historyObserved: true, records: [{ step: "step-1", findings: [{ id: "f1", source: "report-a", status: "open" }] }, { step: "step-1", findings: [] }] }, { historyObserved: true, records: [{ step: "step-1", findings: [{ id: "f1", source: "report-a", status: "open" }] }, { step: "step-1", findings: [{ id: "f1", source: "report-b", status: "verified" }] }] }] },
|
|
@@ -766,15 +849,20 @@ function createLearningFixtures({ recordedAt = "2026-10-08T00:00:00.000Z" } = {}
|
|
|
766
849
|
{ family: "report", split: "test", question: "Does this structured requested delivery comply with the selected saved-full-report/five-line-summary protocol, including its explicit unavailable-persistence blocked exception?", facts: [{ protocol: "saved-full-report-and-five-line-summary", persistence: "available", requestedDelivery: "saved-full-report-and-five-line-summary", reportReference: "required" }, { protocol: "saved-full-report-and-five-line-summary", persistence: "available", requestedDelivery: "complete-report-only-in-final", reportReference: "forbidden" }, { protocol: "saved-full-report-and-five-line-summary", persistence: "available", requestedDelivery: "saved-full-report-and-five-line-summary", reportReference: "omitted" }, { protocol: "saved-full-report-and-five-line-summary", persistence: "unavailable", requestedDelivery: "blocked-no-invented-report", reportReference: "not-saved" }] },
|
|
767
850
|
{ family: "cleanup", split: "test", question: "Do these records establish settled cleanup with a matching execution identity and reapedAll true? This does not establish task success or approval.", facts: [{ executionId: "exec:one", state: "settled", receipt: { state: "settled", executionId: "exec:one", reapedAll: true } }, { executionId: "exec:one", state: "settled", receipt: null }, { executionId: "exec:one", state: "settled", receipt: { state: "settled", executionId: "exec:other", reapedAll: true } }, { executionId: "exec:one", state: "settled", receipt: { state: "settled", executionId: "exec:one", reapedAll: false } }] }
|
|
768
851
|
];
|
|
852
|
+
const families = set === "workflow" ? workflowFixtureFamilies() : mechanicalFamilies;
|
|
853
|
+
const evaluate = set === "workflow" ? evaluateWorkflowFixture : evaluateFixture;
|
|
854
|
+
const oracleVersion = set === "workflow" ? WORKFLOW_ORACLE_VERSION : FIXTURE_ORACLE_VERSION;
|
|
855
|
+
const experimentId = set === "workflow" ? "workflow-convergence-20-v1" : "mechanical-fixtures-24-v1";
|
|
856
|
+
const scope = set === "workflow" ? "20 synthetic workflow convergence cases; no observed sessions or model-quality claims." : "24 synthetic mechanical plumbing cases; no observed examples or model-quality claims.";
|
|
769
857
|
const caseDocument = { schema: 1, cases: families.flatMap((f) => f.facts.map((facts, i) => {
|
|
770
858
|
const input = JSON.stringify(facts);
|
|
771
|
-
return { id: `fixture-${f.family}-${i + 1}`, input, question: f.question, provenance: "synthetic", source: { sha256: learningDigest(input), recordId: `${
|
|
859
|
+
return { id: `fixture-${f.family}-${i + 1}`, input, question: f.question, provenance: "synthetic", source: { sha256: learningDigest(input), recordId: `${oracleVersion}/${f.family}/${i + 1}` }, visibility: "public" };
|
|
772
860
|
})) };
|
|
773
861
|
const cases = parseCases(caseDocument), receipts = [], labels = [], entries = [];
|
|
774
862
|
for (const c of cases) {
|
|
775
863
|
const family = c.id.split("-")[1], f = families.find((f2) => f2.family === family);
|
|
776
|
-
const value =
|
|
777
|
-
const receipt = { schema: 1, kind: "independent-decision-label", caseId: c.id, caseHash: c.hash, source: c.source, value, labelKind: "test", actor:
|
|
864
|
+
const value = evaluate(family, JSON.parse(c.input));
|
|
865
|
+
const receipt = { schema: 1, kind: "independent-decision-label", caseId: c.id, caseHash: c.hash, source: c.source, value, labelKind: "test", actor: oracleVersion, independent: true, recordedAt, method: { kind: "deterministic-test", id: family, version: oracleVersion + ":" + learningDigest(evaluate.toString()) } };
|
|
778
866
|
const bytes = JSON.stringify(receipt, null, 2) + "\n";
|
|
779
867
|
receipts.push({ caseId: c.id, filename: c.id + "-label.json", bytes, sha256: learningDigest(bytes) });
|
|
780
868
|
labels.push({ caseId: c.id, caseHash: c.hash, value, kind: "test", actor: receipt.actor, evidenceSha256: learningDigest(bytes), independent: true });
|
|
@@ -782,8 +870,8 @@ function createLearningFixtures({ recordedAt = "2026-10-08T00:00:00.000Z" } = {}
|
|
|
782
870
|
}
|
|
783
871
|
const labelDocument = { schema: 1, labels };
|
|
784
872
|
parseLabels(labelDocument, cases);
|
|
785
|
-
const manifest = parseExperiment(cases, { schema: 1, kind: "decision-learning-experiment", id:
|
|
786
|
-
return { caseDocument, labelDocument, manifest, labelReceipts: receipts, fixtureOnly: true, trainingEligible: false, scope
|
|
873
|
+
const manifest = parseExperiment(cases, { schema: 1, kind: "decision-learning-experiment", id: experimentId, frozenAt: recordedAt, entries });
|
|
874
|
+
return { caseDocument, labelDocument, manifest, labelReceipts: receipts, fixtureOnly: true, trainingEligible: false, scope };
|
|
787
875
|
}
|
|
788
876
|
|
|
789
877
|
// experiments/decision-shadow/research.mjs
|
|
@@ -1228,13 +1316,14 @@ var RESEARCH_OPTIONS = {
|
|
|
1228
1316
|
fixtures: ["out"]
|
|
1229
1317
|
};
|
|
1230
1318
|
var RESEARCH_OPTIONAL = {
|
|
1319
|
+
fixtures: ["set"],
|
|
1231
1320
|
"run-pi": ["pi-node", "auth-path", "timeout-ms"]
|
|
1232
1321
|
};
|
|
1233
1322
|
async function researchCommand(command, flags, helpers, options) {
|
|
1234
1323
|
const { cases, jsonFile: jsonFile2, textFile: textFile2, writeNew: writeNew2, readLegacyRun } = helpers;
|
|
1235
1324
|
const { emit = console.log, piRunner } = options;
|
|
1236
1325
|
if (command === "fixtures") {
|
|
1237
|
-
const f = createLearningFixtures({});
|
|
1326
|
+
const f = createLearningFixtures({ set: flags.set ?? "mechanical" });
|
|
1238
1327
|
const dir = resolve(flags.out);
|
|
1239
1328
|
await mkdir2(dir, { mode: 448 });
|
|
1240
1329
|
const refs = [];
|
|
@@ -2118,7 +2207,7 @@ var help = `Decision research workflow (Node >=20; qualified Pi execution needs
|
|
|
2118
2207
|
score --cases FILE --labels FILE --run RESULT.jsonl [--run RESULT2.jsonl]
|
|
2119
2208
|
corpus --cases FILE --labels FILE --out NEW.json
|
|
2120
2209
|
verify-sources --cases FILE --sources SELECTION.json --evidence-root DIR --out NEW.json
|
|
2121
|
-
fixtures --out NEW_DIR
|
|
2210
|
+
fixtures --out NEW_DIR [--set mechanical|workflow]
|
|
2122
2211
|
validate-experiment --cases FILE --experiment FILE
|
|
2123
2212
|
preview-pi --cases FILE --experiment FILE --model openai-codex:MODEL --thinking LEVEL --split test
|
|
2124
2213
|
run-pi --cases FILE --experiment FILE --model openai-codex:MODEL --thinking LEVEL --split test --pi-package DIR --out NEW.jsonl --allow-subscription [--pi-node PATH] [--auth-path FILE] [--timeout-ms N]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skill-harness/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "skill-harness CLI \u2014 run, grade, review, and lint agent-skill scenarios on the pi harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"prepack": "node ../../scripts/release-pack.mjs --guard"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@skill-harness/core": "0.
|
|
48
|
-
"@skill-harness/adapters": "0.
|
|
47
|
+
"@skill-harness/core": "0.27.0",
|
|
48
|
+
"@skill-harness/adapters": "0.27.0"
|
|
49
49
|
}
|
|
50
50
|
}
|