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:
-Puter
2026-07-27 22:52:14 +05:30
parent cb7484912c
commit 005b26fa32
19 changed files with 2480 additions and 13 deletions

View File

@@ -15,7 +15,12 @@
"./project-workspace": "./src/project-workspace.ts",
"./signal": "./src/signal.ts",
"./smoke": "./src/smoke.ts",
"./work": "./src/work.ts"
"./work": "./src/work.ts",
"./work-definition": "./src/work-definition.ts",
"./work-design": "./src/work-design.ts",
"./work-lifecycle": "./src/work-lifecycle.ts",
"./resolver": "./src/resolver.ts",
"./harness-runtime": "./src/harness-runtime.ts"
},
"scripts": {
"check-types": "tsc --noEmit",

View File

@@ -0,0 +1,167 @@
import { Effect, Schema } from "effect";
import type { AttemptOutcome } from "./resolver";
const Text = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
export const HarnessEventKind = Schema.Literals([
"started",
"progress",
"question",
"log",
"completed",
"failed",
"cancelled",
]);
export type HarnessEventKind = typeof HarnessEventKind.Type;
export const HarnessEvent = Schema.Struct({
kind: HarnessEventKind,
message: Text,
metadata: Schema.Record(Schema.String, Schema.String),
occurredAt: Schema.Number,
sequence: Schema.Int,
});
export type HarnessEvent = typeof HarnessEvent.Type;
export const FakeScenario = Schema.Literals([
"success",
"transient-failure-then-success",
"needs-input",
"permanent-failure",
"cancelled",
]);
export type FakeScenario = typeof FakeScenario.Type;
export interface HarnessRuntime {
readonly name: string;
readonly run: (input: {
readonly attemptNumber?: number;
readonly scenario: FakeScenario;
readonly signal?: AbortSignal;
}) => Effect.Effect<readonly [readonly HarnessEvent[], AttemptOutcome]>;
}
const event = (
sequence: number,
kind: HarnessEventKind,
message: string,
occurredAt: number
): HarnessEvent => ({ kind, message, metadata: {}, occurredAt, sequence });
export const FakeHarnessLive = (
now: () => number = Date.now
): HarnessRuntime => ({
name: "fake",
run: ({ attemptNumber = 1, scenario, signal }) =>
Effect.sync(() => {
const started = now();
const events: HarnessEvent[] = [
event(0, "started", `fake harness started: ${scenario}`, started),
];
if (signal?.aborted || scenario === "cancelled") {
events.push(event(1, "cancelled", "simulation cancelled", now()));
return [
events,
{
classification: "Cancelled",
retryable: false,
summary: "Simulation cancelled",
},
] as const;
}
events.push(
event(1, "progress", "validated approved Definition and Design", now())
);
switch (scenario) {
case "success": {
events.push(
event(
2,
"completed",
"fake implementation evidence recorded",
now()
)
);
return [
events,
{
classification: "Succeeded",
retryable: false,
summary: "Simulation succeeded; no implementation was claimed",
},
] as const;
}
case "transient-failure-then-success": {
if (attemptNumber > 1) {
events.push(
event(2, "completed", "transient failure recovered", now())
);
return [
events,
{
classification: "Succeeded",
retryable: false,
summary:
"Simulation recovered after a transient failure; no implementation was claimed",
},
] as const;
}
events.push(event(2, "failed", "transient provider failure", now()));
return [
events,
{
classification: "RetryableFailure",
retryable: true,
summary: "Transient simulation failure",
},
] as const;
}
case "needs-input": {
events.push(
event(2, "question", "simulation needs a human decision", now())
);
return [
events,
{
classification: "NeedsInput",
retryable: false,
summary: "Simulation needs input",
},
] as const;
}
case "permanent-failure": {
events.push(
event(
2,
"failed",
"deterministic permanent simulation failure",
now()
)
);
return [
events,
{
classification: "PermanentFailure",
retryable: false,
summary: "Permanent simulation failure",
},
] as const;
}
default: {
return [
events,
{
classification: "PermanentFailure",
retryable: false,
summary: "Unknown simulation scenario",
},
] as const;
}
}
}),
});

View File

@@ -10,3 +10,8 @@ export * from "./project-work";
export * from "./signal";
export * from "./smoke";
export * from "./work";
export * from "./work-definition";
export * from "./work-design";
export * from "./work-lifecycle";
export * from "./resolver";
export * from "./harness-runtime";

View File

@@ -0,0 +1,71 @@
import { Schema } from "effect";
const Text = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
export const RunStatus = Schema.Literals(["ready", "running", "terminal"]);
export type RunStatus = typeof RunStatus.Type;
export const AttemptStatus = Schema.Literals([
"queued",
"claimed",
"running",
"terminal",
]);
export type AttemptStatus = typeof AttemptStatus.Type;
export const AttemptClassification = Schema.Literals([
"Succeeded",
"RetryableFailure",
"NeedsInput",
"Blocked",
"VerificationFailed",
"BudgetExhausted",
"Cancelled",
"PermanentFailure",
]);
export type AttemptClassification = typeof AttemptClassification.Type;
export const AttemptOutcome = Schema.Struct({
classification: AttemptClassification,
retryable: Schema.Boolean,
summary: Text,
});
export type AttemptOutcome = typeof AttemptOutcome.Type;
export const RetryPolicy = Schema.Struct({
maxAttempts: Schema.Int,
retryableClassifications: Schema.Array(AttemptClassification),
});
export type RetryPolicy = typeof RetryPolicy.Type;
export const CodingKitV0 = Schema.Struct({
harness: Schema.Literal("fake"),
id: Schema.Literal("coding-kit-v0"),
retryPolicy: RetryPolicy,
version: Schema.Literal("0.1.0"),
});
export type CodingKitV0 = typeof CodingKitV0.Type;
export const isTerminalClassification = (_: AttemptClassification): true =>
true;
export const shouldRetry = (
outcome: AttemptOutcome,
attemptNumber: number,
policy: RetryPolicy
): boolean =>
outcome.retryable &&
attemptNumber < policy.maxAttempts &&
policy.retryableClassifications.includes(outcome.classification);
export const defaultCodingKitV0: CodingKitV0 = {
harness: "fake",
id: "coding-kit-v0",
retryPolicy: {
maxAttempts: 3,
retryableClassifications: ["RetryableFailure"],
},
version: "0.1.0",
};

View File

@@ -0,0 +1,91 @@
import { Effect, Schema } from "effect";
const Text = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
export const DefinitionRisk = Schema.Literals(["low", "medium", "high"]);
export type DefinitionRisk = typeof DefinitionRisk.Type;
export const QuestionImpact = Schema.Literals(["low", "medium", "high"]);
export type QuestionImpact = typeof QuestionImpact.Type;
export const WorkQuestion = Schema.Struct({
alternatives: Schema.Array(Text),
answer: Schema.optional(Text),
id: Text,
impact: QuestionImpact,
prompt: Text,
recommendation: Schema.optional(Text),
status: Schema.Literals(["open", "answered", "withdrawn"]),
});
export type WorkQuestion = typeof WorkQuestion.Type;
export const WorkDefinition = Schema.Struct({
acceptanceCriteria: Schema.NonEmptyArray(Text),
affectedUsers: Schema.Array(Text),
assumptions: Schema.Array(Text),
constraints: Schema.Array(Text),
desiredOutcome: Text,
inScope: Schema.Array(Text),
outOfScope: Schema.Array(Text),
problem: Text,
questions: Schema.Array(WorkQuestion),
requiredArtifacts: Schema.Array(Text),
risk: DefinitionRisk,
rollback: Schema.optional(Text),
rollout: Schema.optional(Text),
version: Schema.Int,
});
export type WorkDefinition = typeof WorkDefinition.Type;
export const DefinitionApproval = Schema.Struct({
approvedAt: Schema.Number,
approvedBy: Text,
definitionVersion: Schema.Int,
});
export type DefinitionApproval = typeof DefinitionApproval.Type;
export const DefinitionProposal = WorkDefinition;
export type DefinitionProposal = typeof DefinitionProposal.Type;
export class DefinitionError extends Schema.TaggedErrorClass<DefinitionError>()(
"DefinitionError",
{
message: Schema.String,
reason: Schema.Literals(["Invalid", "OpenHighImpactQuestion"]),
}
) {}
export const validateDefinition = Effect.fn("Work.validateDefinition")(
function* validateDefinition(input: unknown) {
const definition = yield* Schema.decodeUnknownEffect(WorkDefinition)(
input
).pipe(
Effect.mapError(
(cause) =>
new DefinitionError({ message: cause.message, reason: "Invalid" })
)
);
const blocked = definition.questions.some(
(question) => question.status === "open" && question.impact === "high"
);
if (blocked) {
return yield* Effect.fail(
new DefinitionError({
message:
"High-impact open questions must be resolved before approval",
reason: "OpenHighImpactQuestion",
})
);
}
return definition;
}
);
export const canApproveDefinition = (definition: WorkDefinition): boolean =>
definition.questions.every(
(question) => question.status !== "open" || question.impact !== "high"
);

View File

@@ -0,0 +1,98 @@
import { Effect, Schema } from "effect";
const Text = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
export const ImpactMap = Schema.Struct({
files: Schema.Array(Text),
modules: Schema.Array(Text),
risks: Schema.Array(Text),
summary: Text,
});
export type ImpactMap = typeof ImpactMap.Type;
export const VerticalSlice = Schema.Struct({
codeBoundaries: Schema.Array(Text),
dependsOn: Schema.Array(Text),
evidenceRequirements: Schema.NonEmptyArray(Text),
id: Text,
objective: Text,
observableBehavior: Text,
reviewRequired: Schema.Boolean,
title: Text,
verification: Schema.NonEmptyArray(Text),
});
export type VerticalSlice = typeof VerticalSlice.Type;
export const DesignPacket = Schema.Struct({
architectureSummary: Text,
callFlowDelta: Schema.Array(Text),
concerns: Schema.Array(Text),
definitionVersion: Schema.Int,
evidenceRequirements: Schema.NonEmptyArray(Text),
fileTreeDelta: Schema.Array(Text),
impactMap: ImpactMap,
invariants: Schema.NonEmptyArray(Text),
keyInterfaces: Schema.Array(Text),
slices: Schema.Array(VerticalSlice),
tradeoffs: Schema.Array(Text),
version: Schema.Int,
});
export type DesignPacket = typeof DesignPacket.Type;
export const DesignApproval = Schema.Struct({
approvedAt: Schema.Number,
approvedBy: Text,
definitionVersion: Schema.Int,
designVersion: Schema.Int,
});
export type DesignApproval = typeof DesignApproval.Type;
export class DesignError extends Schema.TaggedErrorClass<DesignError>()(
"DesignError",
{
message: Schema.String,
reason: Schema.Literals([
"Invalid",
"NoObservableSlices",
"DefinitionMismatch",
]),
}
) {}
export const validateDesignPacket = Effect.fn("Work.validateDesignPacket")(
function* validateDesignPacket(input: unknown) {
const design = yield* Schema.decodeUnknownEffect(DesignPacket)(input).pipe(
Effect.mapError(
(cause) =>
new DesignError({ message: cause.message, reason: "Invalid" })
)
);
if (
design.slices.length === 0 ||
design.slices.some(
(slice) =>
slice.observableBehavior.trim().length === 0 ||
slice.evidenceRequirements.length === 0 ||
slice.verification.length === 0
)
) {
return yield* Effect.fail(
new DesignError({
message:
"Every Design must contain observable, independently verifiable slices",
reason: "NoObservableSlices",
})
);
}
return design;
}
);
export const isObservableSlice = (slice: VerticalSlice): boolean =>
slice.observableBehavior.trim().length > 0 &&
slice.evidenceRequirements.length > 0 &&
slice.verification.length > 0;

View File

@@ -0,0 +1,69 @@
import { Schema } from "effect";
export const WorkStatus = Schema.Literals([
"proposed",
"defining",
"awaiting-definition-approval",
"designing",
"awaiting-design-approval",
"ready",
"executing",
"needs-input",
"blocked",
"completed",
"failed",
"cancelled",
]);
export type WorkStatus = typeof WorkStatus.Type;
export const WORK_TRANSITIONS: Readonly<
Record<WorkStatus, readonly WorkStatus[]>
> = {
"awaiting-definition-approval": ["designing", "defining"],
"awaiting-design-approval": [
"ready",
"designing",
"awaiting-definition-approval",
],
blocked: ["ready", "executing", "cancelled"],
cancelled: ["ready", "proposed"],
completed: ["proposed", "defining"],
defining: ["awaiting-definition-approval", "proposed"],
designing: ["awaiting-design-approval", "awaiting-definition-approval"],
executing: [
"ready",
"needs-input",
"blocked",
"completed",
"failed",
"cancelled",
],
failed: ["ready", "executing", "cancelled"],
"needs-input": ["ready", "executing", "cancelled"],
proposed: ["defining"],
ready: ["executing", "designing", "cancelled"],
};
export const canTransitionWork = (from: WorkStatus, to: WorkStatus): boolean =>
WORK_TRANSITIONS[from].includes(to);
export const assertWorkTransition = (
from: WorkStatus,
to: WorkStatus
): void => {
if (!canTransitionWork(from, to)) {
throw new Error(`Invalid Work transition: ${from} -> ${to}`);
}
};
export const definitionRevisionInvalidation = {
definitionApproval: "invalidate" as const,
dependentDesign: "invalidate" as const,
designApproval: "invalidate" as const,
workStatus: "defining" as const,
};
export const designRevisionInvalidation = {
designApproval: "invalidate" as const,
workStatus: "designing" as const,
};

View 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);
});
});

View File

@@ -1,14 +1,14 @@
import { Array as EffectArray, Effect, Order, Schema } from "effect";
export { WorkStatus } from "./work-lifecycle";
export type { WorkStatus as WorkLifecycleStatus } from "./work-lifecycle";
const MeaningfulString = Schema.String.check(
Schema.makeFilter((value) => value.trim().length > 0, {
expected: "a non-empty string",
})
);
export const WorkStatus = Schema.Literal("proposed");
export type WorkStatus = typeof WorkStatus.Type;
export const WorkDraft = Schema.Struct({
objective: MeaningfulString,
title: MeaningfulString,
@@ -91,6 +91,24 @@ const WorkAttachmentInput = Schema.Struct({
export const WorkEventKind = Schema.Literals([
"work.proposed",
"signal.attached",
"definition.requested",
"definition.saved",
"definition.revised",
"definition.approved",
"definition.invalidated",
"question.answered",
"question.withdrawn",
"design.requested",
"design.saved",
"design.revised",
"design.approved",
"design.invalidated",
"run.started",
"run.cancelled",
"attempt.claimed",
"attempt.event",
"attempt.completed",
"attempt.reconciled",
]);
export type WorkEventKind = typeof WorkEventKind.Type;