@mhingston5/lasso 0.1.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/README.md +707 -0
- package/docs/agent-wrangling.png +0 -0
- package/package.json +26 -0
- package/src/capabilities/matcher.ts +25 -0
- package/src/capabilities/registry.ts +103 -0
- package/src/capabilities/types.ts +15 -0
- package/src/cir/lower.ts +253 -0
- package/src/cir/optimize.ts +251 -0
- package/src/cir/types.ts +131 -0
- package/src/cir/validate.ts +265 -0
- package/src/compiler/compile.ts +601 -0
- package/src/compiler/feedback.ts +471 -0
- package/src/compiler/runtime-helpers.ts +455 -0
- package/src/composition/chain.ts +58 -0
- package/src/composition/conditional.ts +76 -0
- package/src/composition/parallel.ts +75 -0
- package/src/composition/types.ts +105 -0
- package/src/environment/analyzer.ts +56 -0
- package/src/environment/discovery.ts +179 -0
- package/src/environment/types.ts +68 -0
- package/src/failures/classifiers.ts +134 -0
- package/src/failures/generator.ts +421 -0
- package/src/failures/map-reference-failures.ts +23 -0
- package/src/failures/ontology.ts +210 -0
- package/src/failures/recovery.ts +214 -0
- package/src/failures/types.ts +14 -0
- package/src/index.ts +67 -0
- package/src/memory/advisor.ts +132 -0
- package/src/memory/extractor.ts +166 -0
- package/src/memory/store.ts +107 -0
- package/src/memory/types.ts +53 -0
- package/src/metaharness/engine.ts +256 -0
- package/src/metaharness/predictor.ts +168 -0
- package/src/metaharness/types.ts +40 -0
- package/src/mutation/derive.ts +308 -0
- package/src/mutation/diff.ts +52 -0
- package/src/mutation/engine.ts +256 -0
- package/src/mutation/types.ts +84 -0
- package/src/pi/command-input.ts +209 -0
- package/src/pi/commands.ts +351 -0
- package/src/pi/extension.ts +16 -0
- package/src/planner/synthesize.ts +83 -0
- package/src/planner/template-rules.ts +183 -0
- package/src/planner/types.ts +42 -0
- package/src/reference/catalog.ts +128 -0
- package/src/reference/patch-validation-strategies.ts +170 -0
- package/src/reference/patch-validation.ts +174 -0
- package/src/reference/pr-review-merge.ts +155 -0
- package/src/reference/strategies.ts +126 -0
- package/src/reference/types.ts +33 -0
- package/src/replanner/risk-rules.ts +161 -0
- package/src/replanner/runtime.ts +308 -0
- package/src/replanner/synthesize.ts +619 -0
- package/src/replanner/types.ts +73 -0
- package/src/spec/schema.ts +254 -0
- package/src/spec/types.ts +319 -0
- package/src/spec/validate.ts +296 -0
- package/src/state/snapshots.ts +43 -0
- package/src/state/types.ts +12 -0
- package/src/synthesis/graph-builder.ts +267 -0
- package/src/synthesis/harness-builder.ts +113 -0
- package/src/synthesis/intent-ir.ts +63 -0
- package/src/synthesis/policy-builder.ts +320 -0
- package/src/synthesis/risk-analyzer.ts +182 -0
- package/src/synthesis/skill-parser.ts +441 -0
- package/src/verification/engine.ts +230 -0
- package/src/versioning/file-store.ts +103 -0
- package/src/versioning/history.ts +43 -0
- package/src/versioning/store.ts +16 -0
- package/src/versioning/types.ts +31 -0
- package/test/capabilities/matcher.test.ts +67 -0
- package/test/capabilities/registry.test.ts +136 -0
- package/test/capabilities/synthesis.test.ts +264 -0
- package/test/cir/lower.test.ts +417 -0
- package/test/cir/optimize.test.ts +266 -0
- package/test/cir/validate.test.ts +368 -0
- package/test/compiler/adaptive-runtime.test.ts +157 -0
- package/test/compiler/compile.test.ts +1198 -0
- package/test/compiler/feedback.test.ts +784 -0
- package/test/compiler/guardrails.test.ts +191 -0
- package/test/compiler/trace.test.ts +404 -0
- package/test/composition/chain.test.ts +328 -0
- package/test/composition/conditional.test.ts +241 -0
- package/test/composition/parallel.test.ts +215 -0
- package/test/environment/analyzer.test.ts +204 -0
- package/test/environment/discovery.test.ts +149 -0
- package/test/failures/classifiers.test.ts +287 -0
- package/test/failures/generator.test.ts +203 -0
- package/test/failures/ontology.test.ts +439 -0
- package/test/failures/recovery.test.ts +300 -0
- package/test/helpers/createFixtureRepo.ts +84 -0
- package/test/helpers/createPatchValidationFixture.ts +144 -0
- package/test/helpers/runCompiledWorkflow.ts +208 -0
- package/test/memory/advisor.test.ts +332 -0
- package/test/memory/extractor.test.ts +295 -0
- package/test/memory/store.test.ts +244 -0
- package/test/metaharness/engine.test.ts +575 -0
- package/test/metaharness/predictor.test.ts +436 -0
- package/test/mutation/derive-failure.test.ts +209 -0
- package/test/mutation/engine.test.ts +622 -0
- package/test/package-smoke.test.ts +29 -0
- package/test/pi/command-input.test.ts +153 -0
- package/test/pi/commands.test.ts +623 -0
- package/test/planner/classify-template.test.ts +32 -0
- package/test/planner/synthesize.test.ts +901 -0
- package/test/reference/PatchValidation.failures.test.ts +137 -0
- package/test/reference/PatchValidation.test.ts +326 -0
- package/test/reference/PrReviewMerge.failures.test.ts +121 -0
- package/test/reference/PrReviewMerge.test.ts +55 -0
- package/test/reference/catalog-open.test.ts +70 -0
- package/test/replanner/runtime.test.ts +207 -0
- package/test/replanner/synthesize.test.ts +303 -0
- package/test/spec/validate.test.ts +1056 -0
- package/test/state/snapshots.test.ts +264 -0
- package/test/synthesis/custom-workflow.test.ts +264 -0
- package/test/synthesis/graph-builder.test.ts +370 -0
- package/test/synthesis/harness-builder.test.ts +128 -0
- package/test/synthesis/policy-builder.test.ts +149 -0
- package/test/synthesis/risk-analyzer.test.ts +230 -0
- package/test/synthesis/skill-parser.test.ts +796 -0
- package/test/verification/engine.test.ts +509 -0
- package/test/versioning/history.test.ts +144 -0
- package/test/versioning/store.test.ts +254 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { FileLineageStore } from "../../src/versioning/file-store.js";
|
|
6
|
+
import type { HarnessVersion, LineageEntry } from "../../src/versioning/types.js";
|
|
7
|
+
import type { HarnessSpec } from "../../src/spec/types.js";
|
|
8
|
+
import { createInitialVersion, createNextVersion } from "../../src/versioning/history.js";
|
|
9
|
+
|
|
10
|
+
function makeSpec(name: string): HarnessSpec {
|
|
11
|
+
return {
|
|
12
|
+
name,
|
|
13
|
+
graph: {
|
|
14
|
+
entryNodeId: "start",
|
|
15
|
+
nodes: [{ id: "start", kind: "tool", tool: "bash", args: ["echo", name] }],
|
|
16
|
+
edges: [],
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function makeLineageEntry(version: number, overrides?: Partial<LineageEntry>): LineageEntry {
|
|
22
|
+
return {
|
|
23
|
+
version,
|
|
24
|
+
terminalNodeId: "start",
|
|
25
|
+
outputs: { start: { stdout: "ok" } },
|
|
26
|
+
nodeResults: { start: { stdout: "ok" } },
|
|
27
|
+
failures: [],
|
|
28
|
+
metrics: { retries: 0, durationMs: 50 },
|
|
29
|
+
trace: [{ nodeId: "start", source: { specNodeId: "start", specNodeKind: "tool", specPath: "graph.nodes[0]" }, phase: "enter" }],
|
|
30
|
+
completedAt: 1000 + version,
|
|
31
|
+
...overrides,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("versioning/FileLineageStore", () => {
|
|
36
|
+
let storeDir: string;
|
|
37
|
+
let store: FileLineageStore;
|
|
38
|
+
|
|
39
|
+
beforeEach(async () => {
|
|
40
|
+
storeDir = await mkdtemp(join(tmpdir(), "lineage-test-"));
|
|
41
|
+
store = new FileLineageStore(storeDir);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(async () => {
|
|
45
|
+
await rm(storeDir, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("saveVersion / getVersion", () => {
|
|
49
|
+
it("should save and retrieve a version", async () => {
|
|
50
|
+
const version = createInitialVersion(makeSpec("wf-1"));
|
|
51
|
+
|
|
52
|
+
await store.saveVersion(version);
|
|
53
|
+
const retrieved = await store.getVersion(1);
|
|
54
|
+
|
|
55
|
+
expect(retrieved).toEqual(version);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should return null for a missing version", async () => {
|
|
59
|
+
const result = await store.getVersion(999);
|
|
60
|
+
expect(result).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should deep clone on save (mutations do not affect store)", async () => {
|
|
64
|
+
const spec = makeSpec("wf-mutate");
|
|
65
|
+
const version = createInitialVersion(spec);
|
|
66
|
+
|
|
67
|
+
await store.saveVersion(version);
|
|
68
|
+
version.reason = "mutated";
|
|
69
|
+
|
|
70
|
+
const retrieved = await store.getVersion(1);
|
|
71
|
+
expect(retrieved!.reason).toBe("initial");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("saveLineage / getLineageForVersion", () => {
|
|
76
|
+
it("should save and retrieve a lineage entry", async () => {
|
|
77
|
+
const entry = makeLineageEntry(1);
|
|
78
|
+
|
|
79
|
+
await store.saveLineage(entry);
|
|
80
|
+
const retrieved = await store.getLineageForVersion(1);
|
|
81
|
+
|
|
82
|
+
expect(retrieved).toEqual(entry);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should return null for a missing lineage entry", async () => {
|
|
86
|
+
const result = await store.getLineageForVersion(999);
|
|
87
|
+
expect(result).toBeNull();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should deep clone on save", async () => {
|
|
91
|
+
const entry = makeLineageEntry(1, { outputs: { start: { data: "original" } } });
|
|
92
|
+
|
|
93
|
+
await store.saveLineage(entry);
|
|
94
|
+
entry.outputs.start = "mutated";
|
|
95
|
+
|
|
96
|
+
const retrieved = await store.getLineageForVersion(1);
|
|
97
|
+
expect(retrieved!.outputs).toEqual({ start: { data: "original" } });
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("getLineageChain", () => {
|
|
102
|
+
it("should return single entry for version with no parent", async () => {
|
|
103
|
+
const v1 = createInitialVersion(makeSpec("chain-1"));
|
|
104
|
+
const e1 = makeLineageEntry(1);
|
|
105
|
+
|
|
106
|
+
await store.saveVersion(v1);
|
|
107
|
+
await store.saveLineage(e1);
|
|
108
|
+
|
|
109
|
+
const chain = await store.getLineageChain(1);
|
|
110
|
+
|
|
111
|
+
expect(chain).toHaveLength(1);
|
|
112
|
+
expect(chain[0].version).toBe(1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should walk parentVersion links to build chain", async () => {
|
|
116
|
+
const v1 = createInitialVersion(makeSpec("chain-2"));
|
|
117
|
+
const v2 = createNextVersion(v1, makeSpec("chain-2-v2"), "escalation");
|
|
118
|
+
const v3 = createNextVersion(v2, makeSpec("chain-2-v3"), "retry");
|
|
119
|
+
|
|
120
|
+
const e1 = makeLineageEntry(1);
|
|
121
|
+
const e2 = makeLineageEntry(2);
|
|
122
|
+
const e3 = makeLineageEntry(3);
|
|
123
|
+
|
|
124
|
+
for (const v of [v1, v2, v3]) await store.saveVersion(v);
|
|
125
|
+
for (const e of [e1, e2, e3]) await store.saveLineage(e);
|
|
126
|
+
|
|
127
|
+
const chain = await store.getLineageChain(3);
|
|
128
|
+
|
|
129
|
+
expect(chain).toHaveLength(3);
|
|
130
|
+
expect(chain.map((e) => e.version)).toEqual([1, 2, 3]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should stop at first missing version in chain", async () => {
|
|
134
|
+
const v1 = createInitialVersion(makeSpec("chain-gap"));
|
|
135
|
+
const v3 = { ...createNextVersion(v1, makeSpec("chain-gap-v3"), "skip"), version: 3, parentVersion: 2 };
|
|
136
|
+
|
|
137
|
+
await store.saveVersion(v1);
|
|
138
|
+
await store.saveVersion(v3);
|
|
139
|
+
await store.saveLineage(makeLineageEntry(1));
|
|
140
|
+
await store.saveLineage(makeLineageEntry(3));
|
|
141
|
+
|
|
142
|
+
const chain = await store.getLineageChain(3);
|
|
143
|
+
|
|
144
|
+
expect(chain).toHaveLength(1);
|
|
145
|
+
expect(chain[0].version).toBe(3);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should return empty array for completely missing chain", async () => {
|
|
149
|
+
const chain = await store.getLineageChain(999);
|
|
150
|
+
expect(chain).toEqual([]);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("queryLineage", () => {
|
|
155
|
+
beforeEach(async () => {
|
|
156
|
+
const specs = [makeSpec("alpha"), makeSpec("beta"), makeSpec("alpha")];
|
|
157
|
+
const entries: LineageEntry[] = [
|
|
158
|
+
makeLineageEntry(1, { terminalNodeId: "node-a", completedAt: 1000 }),
|
|
159
|
+
makeLineageEntry(2, { terminalNodeId: "node-b", completedAt: 2000 }),
|
|
160
|
+
makeLineageEntry(3, { terminalNodeId: "node-a", completedAt: 3000 }),
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < specs.length; i++) {
|
|
164
|
+
await store.saveVersion(createInitialVersion(specs[i]));
|
|
165
|
+
}
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
await store.saveLineage(entry);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should filter by terminalNodeId", async () => {
|
|
172
|
+
const results = await store.queryLineage({ terminalNodeId: "node-a" });
|
|
173
|
+
|
|
174
|
+
expect(results).toHaveLength(2);
|
|
175
|
+
expect(results.every((e) => e.terminalNodeId === "node-a")).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should filter by since (epoch ms)", async () => {
|
|
179
|
+
const results = await store.queryLineage({ since: 1500 });
|
|
180
|
+
|
|
181
|
+
expect(results).toHaveLength(2);
|
|
182
|
+
expect(results.every((e) => e.completedAt >= 1500)).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should apply limit", async () => {
|
|
186
|
+
const results = await store.queryLineage({ limit: 1 });
|
|
187
|
+
|
|
188
|
+
expect(results).toHaveLength(1);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should combine filters", async () => {
|
|
192
|
+
const results = await store.queryLineage({
|
|
193
|
+
terminalNodeId: "node-a",
|
|
194
|
+
since: 2000,
|
|
195
|
+
limit: 10,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
expect(results).toHaveLength(1);
|
|
199
|
+
expect(results[0].version).toBe(3);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should return empty when no entries match", async () => {
|
|
203
|
+
const results = await store.queryLineage({ terminalNodeId: "nonexistent" });
|
|
204
|
+
expect(results).toEqual([]);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("round-trip integrity", () => {
|
|
209
|
+
it("should preserve all fields through save → retrieve", async () => {
|
|
210
|
+
const spec = makeSpec("roundtrip");
|
|
211
|
+
const version = createInitialVersion(spec);
|
|
212
|
+
const entry: LineageEntry = {
|
|
213
|
+
version: 1,
|
|
214
|
+
terminalNodeId: "end",
|
|
215
|
+
outputs: { start: { nested: { deep: true } }, end: [1, 2, 3] },
|
|
216
|
+
nodeResults: { start: { value: 42 } },
|
|
217
|
+
failures: [
|
|
218
|
+
{
|
|
219
|
+
domainType: "lasso",
|
|
220
|
+
rootCause: "verification_failed",
|
|
221
|
+
nodeId: "start",
|
|
222
|
+
message: "boom",
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
metrics: { retries: 2, durationMs: 1234 },
|
|
226
|
+
trace: {
|
|
227
|
+
entries: [
|
|
228
|
+
{ nodeId: "start", source: { specNodeId: "start", specNodeKind: "tool", specPath: "graph.nodes[0]" }, phase: "enter", startedAt: 1000 },
|
|
229
|
+
{ nodeId: "start", source: { specNodeId: "start", specNodeKind: "tool", specPath: "graph.nodes[0]" }, phase: "success", completedAt: 1050 },
|
|
230
|
+
],
|
|
231
|
+
totalDurationMs: 50,
|
|
232
|
+
nodeCount: 1,
|
|
233
|
+
failureCount: 0,
|
|
234
|
+
startTimeMs: 1000,
|
|
235
|
+
endTimeMs: 1050,
|
|
236
|
+
},
|
|
237
|
+
completedAt: 5000,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
await store.saveVersion(version);
|
|
241
|
+
await store.saveLineage(entry);
|
|
242
|
+
|
|
243
|
+
const retrievedVersion = await store.getVersion(1);
|
|
244
|
+
const retrievedEntry = await store.getLineageForVersion(1);
|
|
245
|
+
|
|
246
|
+
expect(retrievedVersion).toEqual(version);
|
|
247
|
+
expect(retrievedEntry).toEqual(entry);
|
|
248
|
+
|
|
249
|
+
expect(retrievedEntry!.outputs).toEqual(entry.outputs);
|
|
250
|
+
expect(retrievedEntry!.failures).toEqual(entry.failures);
|
|
251
|
+
expect(retrievedEntry!.trace).toEqual(entry.trace);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|