Slices 2-4: Work becomes executable
Domain primitives: versioned WorkDefinition/DesignPacket with risk, questions, and approval gates; lifecycle transition table with invalidation rules; Resolver (Run/Attempt/outcomes/CodingKitV0); provider-neutral HarnessRuntime with normalized events and a deterministic FakeHarnessLive that always reaches a terminal classification and never claims implementation. Convex durable model: workDefinitions, workQuestions, workApprovals, designPackets, workSlices, workRuns, workAttempts, workAttemptEvents tables; broadened works.status union; generalized workEvents with optional signalId, referenceId, and payloadJson. Authenticated commands for definition request/ save/revise/approve, question answer/withdraw, design save/revise/approve, and simulated execution start/cancel/retry with leased attempts, checkpointed events, and expired-lease reconciliation. Private work-planner FLUE agent with proposal-only tools (definition, design, question). Convex validates and stores every proposal; FLUE never approves or advances Work. Expanded Work card with Outcome, Design, and Build sections wired to the new mutations. Slice 1 conversation and provenance preserved.
This commit is contained in:
105
packages/primitives/src/work-resolution.test.ts
Normal file
105
packages/primitives/src/work-resolution.test.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Effect } from "effect";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { FakeHarnessLive } from "./harness-runtime";
|
||||
import { defaultCodingKitV0, shouldRetry } from "./resolver";
|
||||
import { validateDefinition } from "./work-definition";
|
||||
import { validateDesignPacket } from "./work-design";
|
||||
import { canTransitionWork } from "./work-lifecycle";
|
||||
|
||||
const definition = {
|
||||
acceptanceCriteria: ["terminal outcome"],
|
||||
affectedUsers: ["founders"],
|
||||
assumptions: [],
|
||||
constraints: [],
|
||||
desiredOutcome: "A visible terminal simulation exists",
|
||||
inScope: ["fake execution"],
|
||||
outOfScope: ["real sandboxing"],
|
||||
problem: "A deterministic build path is needed",
|
||||
questions: [
|
||||
{
|
||||
alternatives: [],
|
||||
id: "q1",
|
||||
impact: "high",
|
||||
prompt: "Which runtime?",
|
||||
status: "open",
|
||||
},
|
||||
],
|
||||
requiredArtifacts: ["events"],
|
||||
risk: "medium",
|
||||
version: 1,
|
||||
};
|
||||
|
||||
describe("work resolution contracts", () => {
|
||||
test("high-impact open questions block definition approval", async () => {
|
||||
await expect(
|
||||
Effect.runPromise(validateDefinition(definition))
|
||||
).rejects.toThrow(/High-impact/u);
|
||||
});
|
||||
|
||||
test("observable slices and terminal fake outcomes are enforced", async () => {
|
||||
const approved = await Effect.runPromise(
|
||||
validateDefinition({ ...definition, questions: [] })
|
||||
);
|
||||
const design = await Effect.runPromise(
|
||||
validateDesignPacket({
|
||||
architectureSummary: "small",
|
||||
callFlowDelta: [],
|
||||
concerns: [],
|
||||
definitionVersion: approved.version,
|
||||
evidenceRequirements: ["event"],
|
||||
fileTreeDelta: [],
|
||||
impactMap: { files: [], modules: [], risks: [], summary: "small" },
|
||||
invariants: ["terminal"],
|
||||
keyInterfaces: [],
|
||||
slices: [
|
||||
{
|
||||
codeBoundaries: ["runtime"],
|
||||
dependsOn: [],
|
||||
evidenceRequirements: ["event"],
|
||||
id: "s1",
|
||||
objective: "one",
|
||||
observableBehavior: "visible",
|
||||
reviewRequired: false,
|
||||
title: "one",
|
||||
verification: ["assert"],
|
||||
},
|
||||
],
|
||||
tradeoffs: [],
|
||||
version: 1,
|
||||
})
|
||||
);
|
||||
expect(design.slices).toHaveLength(1);
|
||||
const [, outcome] = await Effect.runPromise(
|
||||
FakeHarnessLive(() => 1).run({ scenario: "success" })
|
||||
);
|
||||
expect(outcome.classification).toBe("Succeeded");
|
||||
expect(outcome.summary).toMatch(/no implementation/u);
|
||||
const [, firstTransient] = await Effect.runPromise(
|
||||
FakeHarnessLive(() => 1).run({
|
||||
attemptNumber: 1,
|
||||
scenario: "transient-failure-then-success",
|
||||
})
|
||||
);
|
||||
const [, recoveredTransient] = await Effect.runPromise(
|
||||
FakeHarnessLive(() => 1).run({
|
||||
attemptNumber: 2,
|
||||
scenario: "transient-failure-then-success",
|
||||
})
|
||||
);
|
||||
expect(firstTransient.classification).toBe("RetryableFailure");
|
||||
expect(recoveredTransient.classification).toBe("Succeeded");
|
||||
expect(
|
||||
shouldRetry(
|
||||
{
|
||||
classification: "RetryableFailure",
|
||||
retryable: true,
|
||||
summary: "retry",
|
||||
},
|
||||
1,
|
||||
defaultCodingKitV0.retryPolicy
|
||||
)
|
||||
).toBe(true);
|
||||
expect(canTransitionWork("ready", "executing")).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user