@effect-agent/testing 0.1.0-beta.84 → 0.1.0-beta.86

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 (42) hide show
  1. package/dist/Certification.d.mts +15 -14
  2. package/dist/Certification.mjs +85 -44
  3. package/dist/Certification.mjs.map +1 -1
  4. package/dist/Chaos.d.mts +6 -6
  5. package/dist/Chaos.mjs +20 -20
  6. package/dist/Chaos.mjs.map +1 -1
  7. package/dist/CodeExecutorConformance.d.mts +2 -2
  8. package/dist/CodeExecutorConformance.mjs +2 -2
  9. package/dist/CodeExecutorConformance.mjs.map +1 -1
  10. package/dist/CodeExecutorSubstitute.d.mts +2 -2
  11. package/dist/CodeExecutorSubstitute.mjs +2 -2
  12. package/dist/CodeExecutorSubstitute.mjs.map +1 -1
  13. package/dist/DocsResearcher.d.mts +25 -19
  14. package/dist/DocsResearcher.mjs +15 -15
  15. package/dist/DocsResearcher.mjs.map +1 -1
  16. package/dist/ScriptedModel.mjs +1 -1
  17. package/dist/ScriptedModel.mjs.map +1 -1
  18. package/dist/TravelPlanner.d.mts +47 -32
  19. package/dist/TravelPlanner.mjs +21 -21
  20. package/dist/TravelPlanner.mjs.map +1 -1
  21. package/dist/{deterministic-layers-Eka0fMZq.mjs → deterministic-layers-D5owIoke.mjs} +8 -8
  22. package/dist/deterministic-layers-D5owIoke.mjs.map +1 -0
  23. package/package.json +1 -1
  24. package/src/Certification.ts +160 -99
  25. package/src/Chaos.ts +21 -31
  26. package/src/CodeExecutorConformance.ts +3 -3
  27. package/src/CodeExecutorSubstitute.ts +3 -3
  28. package/src/ScriptedModel.ts +3 -4
  29. package/src/fixtures/docs-researcher/definition.ts +6 -6
  30. package/src/fixtures/docs-researcher/harness.ts +9 -13
  31. package/src/fixtures/docs-researcher/mcp.ts +3 -3
  32. package/src/fixtures/travel-planner/definition.ts +2 -2
  33. package/src/fixtures/travel-planner/deterministic-layers.ts +5 -5
  34. package/src/fixtures/travel-planner/phase2.ts +2 -2
  35. package/src/fixtures/travel-planner/phase3.ts +5 -5
  36. package/src/fixtures/travel-planner/phase4.ts +8 -8
  37. package/src/fixtures/travel-planner/phase5.ts +9 -13
  38. package/src/fixtures/travel-planner/phase6.ts +10 -10
  39. package/src/fixtures/travel-planner/subagents-durable.ts +11 -13
  40. package/src/fixtures/travel-planner/subagents.ts +6 -6
  41. package/src/internal/certification-report.ts +25 -0
  42. package/dist/deterministic-layers-Eka0fMZq.mjs.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import { Context, Deferred, Effect, Layer, Option, Ref, Schema } from "effect";
2
2
  import { Tool, Toolkit } from "effect/unstable/ai";
3
- import * as Agent from "@effect-agent/core/Agent";
4
- import { AgentPolicy } from "@effect-agent/core/AgentPolicy";
5
- import { RunId, ThreadId, TurnId } from "@effect-agent/core/Identifiers";
6
- import { IdGenerator } from "@effect-agent/core/IdGenerator";
7
- import { RunContextPreparationPassthrough } from "@effect-agent/engine/RunOptions";
8
- import { ThreadHistory } from "@effect-agent/engine/ThreadHistory";
3
+ import * as Agent from "effect-agent/agent";
4
+ import { AgentPolicy } from "effect-agent/agent-policy";
5
+ import { IdGenerator } from "effect-agent/id-generator";
6
+ import { RunId, ThreadId, TurnId } from "effect-agent/identifiers";
7
+ import { RunContextPreparationPassthrough } from "effect-agent/run-options";
8
+ import { ThreadHistory } from "effect-agent/thread-history";
9
9
  //#region src/fixtures/travel-planner/definition.ts
10
10
  const AirportCode = Schema.NonEmptyString.pipe(Schema.brand("@effect-agent/testing/travel-planner/AirportCode"));
11
11
  const QuoteId = Schema.NonEmptyString.pipe(Schema.brand("@effect-agent/testing/travel-planner/QuoteId"));
@@ -351,8 +351,8 @@ const DeterministicIdGeneratorLayer = Layer.effect(IdGenerator, Effect.gen(funct
351
351
  nextTurnId: Ref.updateAndGet(turn, (n) => n + 1).pipe(Effect.map((n) => Schema.decodeSync(TurnId)(`turn-${n}`)))
352
352
  });
353
353
  }));
354
- const TravelPlannerRuntimeLayer = Layer.mergeAll(RunContextPreparationPassthrough, ThreadHistory.layerTransient, TravelPlannerToolkitLayer, FlightCatalogLayer, LodgingCatalogLayer, ActivityCatalogLayer, TravelGuidanceLayer, DeterministicIdGeneratorLayer).pipe(Layer.provide(CatalogLifecycle.layerNoDeps));
354
+ const TravelPlannerRuntimeLayer = Layer.mergeAll(RunContextPreparationPassthrough, ThreadHistory.layer, TravelPlannerToolkitLayer, FlightCatalogLayer, LodgingCatalogLayer, ActivityCatalogLayer, TravelGuidanceLayer, DeterministicIdGeneratorLayer).pipe(Layer.provide(CatalogLifecycle.layerNoDeps));
355
355
  //#endregion
356
356
  export { LodgingQuery as A, TravelPlannerToolkitLayer as B, FlightOption as C, Itinerary as D, GuidanceFailure as E, SearchLodging as F, TravelGuidance as I, TravelPlan as L, QuoteId as M, SearchActivities as N, LodgingCatalog as O, SearchFlights as P, TravelPlanner as R, FlightCatalog as S, FlightUnavailable as T, TripRequest as V, ActivityCatalog as _, DeterministicIdGeneratorLayer as a, ActivityUnavailable as b, ReverseCompletionToolkitLayer as c, SupplierOperation as d, SupplierUnavailable as f, supplierBookingRefFor as g, cancelBookingIdempotencyKey as h, CatalogLifecycleCounts as i, LodgingUnavailable as j, LodgingOption as k, SupplierBookingDesk as l, TravelPlannerRuntimeLayer as m, BookingRef as n, FlightCatalogLayer as o, TravelGuidanceLayer as p, CatalogLifecycle as r, LodgingCatalogLayer as s, ActivityCatalogLayer as t, SupplierBookingRecord as u, ActivityQuery as v, FlightQuery as w, AirportCode as x, ActivitySearchResult as y, TravelPlannerToolkit as z };
357
357
 
358
- //# sourceMappingURL=deterministic-layers-Eka0fMZq.mjs.map
358
+ //# sourceMappingURL=deterministic-layers-D5owIoke.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-layers-D5owIoke.mjs","names":[],"sources":["../src/fixtures/travel-planner/definition.ts","../src/fixtures/travel-planner/deterministic-layers.ts"],"sourcesContent":["import { Context, Effect, Schema } from \"effect\";\nimport * as Agent from \"effect-agent/agent\";\nimport { AgentPolicy } from \"effect-agent/agent-policy\";\nimport { Tool, Toolkit } from \"effect/unstable/ai\";\n\nexport const AirportCode = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/AirportCode\"),\n);\n\nexport type AirportCode = typeof AirportCode.Type;\n\nexport const QuoteId = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/QuoteId\"),\n);\n\nexport type QuoteId = typeof QuoteId.Type;\n\nexport class TripRequest extends Schema.Class<TripRequest>(\"TripRequest\")({\n request: Schema.NonEmptyString,\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n budgetCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class FlightQuery extends Schema.Class<FlightQuery>(\"FlightQuery\")({\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class LodgingQuery extends Schema.Class<LodgingQuery>(\"LodgingQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class ActivityQuery extends Schema.Class<ActivityQuery>(\"ActivityQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class FlightOption extends Schema.Class<FlightOption>(\"FlightOption\")({\n quoteId: QuoteId,\n flight: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class LodgingOption extends Schema.Class<LodgingOption>(\"LodgingOption\")({\n lodging: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\n/** A successful empty activity search is distinct from supplier unavailability. */\nexport class ActivitySearchResult extends Schema.Class<ActivitySearchResult>(\n \"ActivitySearchResult\",\n)({\n activities: Schema.Array(Schema.String),\n}) {}\n\nexport class Itinerary extends Schema.Class<Itinerary>(\"Itinerary\")({\n title: Schema.String,\n route: Schema.String,\n dates: Schema.String,\n flight: Schema.String,\n lodging: Schema.String,\n activities: Schema.Array(Schema.String),\n estimatedTotalCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n quoteId: QuoteId,\n assumptions: Schema.Array(Schema.String),\n unresolvedConstraints: Schema.Array(Schema.String),\n nextAction: Schema.Literal(\"review\"),\n}) {}\n\nexport class TravelPlan extends Schema.Class<TravelPlan>(\"TravelPlan\")({\n itineraries: Schema.Array(Itinerary),\n}) {}\n\nconst unavailableFields = { query: Schema.String, message: Schema.String };\n\nexport class FlightUnavailable extends Schema.TaggedError<FlightUnavailable>()(\n \"FlightUnavailable\",\n unavailableFields,\n) {}\n\nexport class LodgingUnavailable extends Schema.TaggedError<LodgingUnavailable>()(\n \"LodgingUnavailable\",\n unavailableFields,\n) {}\n\nexport class ActivityUnavailable extends Schema.TaggedError<ActivityUnavailable>()(\n \"ActivityUnavailable\",\n unavailableFields,\n) {}\n\nexport class GuidanceFailure extends Schema.TaggedError<GuidanceFailure>()(\"GuidanceFailure\", {\n message: Schema.String,\n}) {}\n\nexport class FlightCatalog extends Context.Service<\n FlightCatalog,\n { readonly search: (query: FlightQuery) => Effect.Effect<FlightOption, FlightUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/FlightCatalog\") {}\n\nexport class LodgingCatalog extends Context.Service<\n LodgingCatalog,\n { readonly search: (query: LodgingQuery) => Effect.Effect<LodgingOption, LodgingUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/LodgingCatalog\") {}\n\nexport class ActivityCatalog extends Context.Service<\n ActivityCatalog,\n {\n readonly search: (\n query: ActivityQuery,\n ) => Effect.Effect<ActivitySearchResult, ActivityUnavailable>;\n }\n>()(\"@effect-agent/testing/travel-planner/ActivityCatalog\") {}\n\nexport class TravelGuidance extends Context.Service<\n TravelGuidance,\n { readonly instructions: (input: TripRequest) => Effect.Effect<string, GuidanceFailure> }\n>()(\"@effect-agent/testing/travel-planner/TravelGuidance\") {}\n\nexport const SearchFlights = Tool.make(\"search_flights\", {\n parameters: FlightQuery,\n success: FlightOption,\n failure: FlightUnavailable,\n failureMode: \"error\",\n dependencies: [FlightCatalog],\n});\n\nexport const SearchLodging = Tool.make(\"search_lodging\", {\n parameters: LodgingQuery,\n success: LodgingOption,\n failure: LodgingUnavailable,\n failureMode: \"error\",\n dependencies: [LodgingCatalog],\n});\n\nexport const SearchActivities = Tool.make(\"search_activities\", {\n parameters: ActivityQuery,\n success: ActivitySearchResult,\n failure: ActivityUnavailable,\n failureMode: \"error\",\n dependencies: [ActivityCatalog],\n});\n\nexport const TravelPlannerToolkit = Toolkit.make(SearchFlights, SearchLodging, SearchActivities);\n\nexport const TravelPlannerToolkitLayer = TravelPlannerToolkit.toLayer({\n search_flights: (query) => Effect.flatMap(FlightCatalog, (catalog) => catalog.search(query)),\n search_lodging: (query) => Effect.flatMap(LodgingCatalog, (catalog) => catalog.search(query)),\n search_activities: (query) => Effect.flatMap(ActivityCatalog, (catalog) => catalog.search(query)),\n});\n\nexport const TravelPlanner = Agent.make(\"travel-planner\", {\n input: TripRequest,\n output: TravelPlan,\n instructions: (input) =>\n Effect.flatMap(TravelGuidance, (guidance) => guidance.instructions(input)),\n toolkit: TravelPlannerToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 3,\n maxDuration: \"30 seconds\",\n toolConcurrency: 3,\n }),\n description: \"Build one review-only itinerary from bounded parallel deterministic searches.\",\n metadata: { deploymentClass: \"E\", phase: \"P1\" },\n});\n","import { Context, Deferred, Effect, Layer, Option, Ref, Schema } from \"effect\";\nimport { IdGenerator } from \"effect-agent/id-generator\";\nimport { ThreadId, RunId, TurnId } from \"effect-agent/identifiers\";\nimport { RunContextPreparationPassthrough } from \"effect-agent/run-options\";\nimport { ThreadHistory } from \"effect-agent/thread-history\";\n\nimport {\n ActivityCatalog,\n ActivitySearchResult,\n ActivityUnavailable,\n FlightCatalog,\n FlightOption,\n FlightUnavailable,\n LodgingCatalog,\n LodgingOption,\n LodgingUnavailable,\n QuoteId,\n TravelGuidance,\n TravelPlannerToolkit,\n TravelPlannerToolkitLayer,\n} from \"./definition.ts\";\n\nexport class CatalogLifecycleCounts extends Schema.Class<CatalogLifecycleCounts>(\n \"CatalogLifecycleCounts\",\n)({\n acquired: Schema.Natural,\n finalized: Schema.Natural,\n}) {}\n\nexport class CatalogLifecycle extends Context.Service<\n CatalogLifecycle,\n {\n readonly markAcquired: Effect.Effect<void>;\n readonly markFinalized: Effect.Effect<void>;\n readonly counts: Effect.Effect<CatalogLifecycleCounts>;\n }\n>()(\"@effect-agent/testing/travel-planner/CatalogLifecycle\") {\n static readonly layerNoDeps = Layer.effect(\n this,\n Effect.gen(function* () {\n const acquired = yield* Ref.make(0);\n const finalized = yield* Ref.make(0);\n\n return CatalogLifecycle.of({\n markAcquired: Ref.update(acquired, (n) => n + 1),\n markFinalized: Ref.update(finalized, (n) => n + 1),\n counts: Effect.all({ acquired: Ref.get(acquired), finalized: Ref.get(finalized) }).pipe(\n Effect.map((counts) => CatalogLifecycleCounts.make(counts)),\n ),\n });\n }),\n );\n}\n\nconst flight = FlightOption.make({\n quoteId: Schema.decodeSync(QuoteId)(\"quote-sfo-lhr-001\"),\n flight: \"EA 218 · nonstop · SFO 18:40 → LHR 13:05+1\",\n estimatedCents: 180_000,\n currency: \"USD\",\n});\n\nconst lodging = LodgingOption.make({\n lodging: \"Bloomsbury House · refundable studio · 4 nights\",\n estimatedCents: 104_000,\n currency: \"USD\",\n});\n\nconst activities = ActivitySearchResult.make({\n activities: [\"British Museum timed entry\", \"Thames evening walk\"],\n});\n\n/**\n * Deterministic controls for a Tool batch whose completions are released in a\n * caller-selected order. This is intentionally a test fixture: it uses no\n * clock or sleep and lets engine scheduler tests prove parallel starts and\n * declaration-order prompt materialization.\n */\nexport interface TravelPlannerCompletionControls {\n readonly flightStarted: Effect.Effect<void>;\n readonly lodgingStarted: Effect.Effect<void>;\n readonly activityStarted: Effect.Effect<void>;\n readonly releaseFlight: Effect.Effect<void>;\n readonly releaseLodging: Effect.Effect<void>;\n readonly releaseActivity: Effect.Effect<void>;\n}\n\nexport const ReverseCompletionToolkitLayer = Effect.gen(function* () {\n const flightStarted = yield* Deferred.make<void>();\n const lodgingStarted = yield* Deferred.make<void>();\n const activityStarted = yield* Deferred.make<void>();\n const releaseFlight = yield* Deferred.make<void>();\n const releaseLodging = yield* Deferred.make<void>();\n const releaseActivity = yield* Deferred.make<void>();\n\n const awaitRelease = <A>(\n started: Deferred.Deferred<void>,\n release: Deferred.Deferred<void>,\n value: A,\n ) =>\n Deferred.succeed(started, undefined).pipe(\n Effect.andThen(Deferred.await(release)),\n Effect.as(value),\n );\n\n return {\n controls: {\n flightStarted: Deferred.await(flightStarted),\n lodgingStarted: Deferred.await(lodgingStarted),\n activityStarted: Deferred.await(activityStarted),\n releaseFlight: Deferred.succeed(releaseFlight, undefined).pipe(Effect.asVoid),\n releaseLodging: Deferred.succeed(releaseLodging, undefined).pipe(Effect.asVoid),\n releaseActivity: Deferred.succeed(releaseActivity, undefined).pipe(Effect.asVoid),\n },\n layer: TravelPlannerToolkit.toLayer({\n search_flights: () => awaitRelease(flightStarted, releaseFlight, flight),\n search_lodging: () => awaitRelease(lodgingStarted, releaseLodging, lodging),\n search_activities: () => awaitRelease(activityStarted, releaseActivity, activities),\n }),\n };\n});\n\nexport const FlightCatalogLayer = Layer.effect(\n FlightCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return FlightCatalog.of({\n search: (query) =>\n query.origin === query.destination\n ? Effect.fail(\n FlightUnavailable.make({\n query: `${query.origin}-${query.destination}`,\n message: \"Origin and destination must differ.\",\n }),\n )\n : Effect.succeed(flight),\n });\n }),\n);\n\nexport const LodgingCatalogLayer = Layer.effect(\n LodgingCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return LodgingCatalog.of({\n search: (query) =>\n query.nights < 1\n ? Effect.fail(\n LodgingUnavailable.make({\n query: query.destination,\n message: \"At least one night is required.\",\n }),\n )\n : Effect.succeed(lodging),\n });\n }),\n);\n\nexport const ActivityCatalogLayer = Layer.effect(\n ActivityCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return ActivityCatalog.of({\n search: (query) =>\n query.destination === \"\"\n ? Effect.fail(\n ActivityUnavailable.make({\n query: query.destination,\n message: \"Destination is required.\",\n }),\n )\n : Effect.succeed(activities),\n });\n }),\n);\n\n/** Stable supplier-side booking identity, minted deterministically from the idempotency key. */\nexport const BookingRef = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/BookingRef\"),\n);\n\nexport type BookingRef = typeof BookingRef.Type;\n\n/** The supplier desk operations the P5 booking Tools and Steps invoke. */\nexport const SupplierOperation = Schema.Literals([\n \"book-flight\",\n \"cancel-booking\",\n \"reserve-flight\",\n \"reserve-lodging\",\n \"issue-confirmation\",\n]);\n\nexport type SupplierOperation = typeof SupplierOperation.Type;\n\n/**\n * One row of external supplier truth. The desk deduplicates by `idempotencyKey` — replaying a\n * call with the same key returns this exact record without creating a second booking — which is\n * precisely the honesty model of DUR-010: the framework never makes an external call\n * exactly-once; the supplier's idempotency key does.\n */\nexport class SupplierBookingRecord extends Schema.Class<SupplierBookingRecord>(\n \"@effect-agent/testing/travel-planner/SupplierBookingRecord\",\n)({\n bookingRef: BookingRef,\n idempotencyKey: Schema.NonEmptyString,\n operation: SupplierOperation,\n detail: Schema.NonEmptyString,\n status: Schema.Literals([\"confirmed\", \"cancelled\"]),\n}) {}\n\nexport class SupplierUnavailable extends Schema.TaggedError<SupplierUnavailable>()(\n \"SupplierUnavailable\",\n { message: Schema.String },\n) {}\n\nexport interface SupplierBookRequest {\n readonly operation: SupplierOperation;\n readonly idempotencyKey: string;\n readonly detail: string;\n}\n\n/** Controls returned by an armed crash window (`holdAfterWrite`). */\nexport interface SupplierHoldControls {\n /** Resolves once the armed call has performed its supplier write and is blocked. */\n readonly held: Effect.Effect<void>;\n /** Releases the blocked call (tests that interrupt the Attempt never call this). */\n readonly release: Effect.Effect<void>;\n}\n\n/** The desk-internal idempotency key of one cancellation: cancel is idempotent by bookingRef. */\nexport const cancelBookingIdempotencyKey = (bookingRef: string): string =>\n `cancel-booking:${bookingRef}`;\n\n/** The deterministic bookingRef the desk mints for one idempotency key. */\nexport const supplierBookingRefFor = (idempotencyKey: string): BookingRef =>\n Schema.decodeSync(BookingRef)(`ref:${idempotencyKey}`);\n\ninterface SupplierHoldWindow {\n readonly held: Deferred.Deferred<void>;\n readonly release: Deferred.Deferred<void>;\n}\n\ninterface SupplierDeskState {\n readonly bookings: ReadonlyMap<string, SupplierBookingRecord>;\n readonly counts: ReadonlyMap<string, number>;\n readonly holds: ReadonlyMap<string, SupplierHoldWindow>;\n}\n\n/**\n * The deterministic in-memory supplier: an idempotency-keyed booking store with per-key call\n * counters and injectable crash windows.\n *\n * - `book`/`cancel` always count the call (at-least-once execution stays observable), then\n * dedupe the external effect by idempotency key — the supplier-side contract the P5 Tools and\n * Steps rely on.\n * - `holdAfterWrite` arms a one-shot crash window: the next call with that key performs its\n * supplier write, signals `held`, and never returns. Interrupting the Attempt at that point\n * models \"the external effect happened but no outcome was recorded\" without any wall clock.\n * - `bookings`/`lookup` expose external truth for the reconciler and for never-fabricate\n * assertions.\n */\nexport class SupplierBookingDesk extends Context.Service<\n SupplierBookingDesk,\n {\n readonly book: (\n request: SupplierBookRequest,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly cancel: (\n bookingRef: BookingRef,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly lookup: (\n idempotencyKey: string,\n ) => Effect.Effect<Option.Option<SupplierBookingRecord>>;\n readonly bookings: Effect.Effect<ReadonlyArray<SupplierBookingRecord>>;\n readonly callCount: (idempotencyKey: string) => Effect.Effect<number>;\n readonly holdAfterWrite: (idempotencyKey: string) => Effect.Effect<SupplierHoldControls>;\n }\n>()(\"@effect-agent/testing/travel-planner/SupplierBookingDesk\") {\n static readonly layer: Layer.Layer<SupplierBookingDesk> = Layer.effect(\n this,\n Effect.gen(function* () {\n const state = yield* Ref.make<SupplierDeskState>({\n bookings: new Map(),\n counts: new Map(),\n holds: new Map(),\n });\n\n const enterHold = (hold: Option.Option<SupplierHoldWindow>) =>\n Option.isSome(hold)\n ? Deferred.succeed(hold.value.held, undefined).pipe(\n Effect.andThen(Deferred.await(hold.value.release)),\n )\n : Effect.void;\n\n const book = (request: SupplierBookRequest) =>\n Ref.modify(state, (current) => {\n const counts = new Map(current.counts).set(\n request.idempotencyKey,\n (current.counts.get(request.idempotencyKey) ?? 0) + 1,\n );\n\n const existing = current.bookings.get(request.idempotencyKey);\n\n const record =\n existing ??\n SupplierBookingRecord.make({\n bookingRef: supplierBookingRefFor(request.idempotencyKey),\n idempotencyKey: request.idempotencyKey,\n operation: request.operation,\n detail: request.detail,\n status: \"confirmed\",\n });\n\n const bookings =\n existing === undefined\n ? new Map(current.bookings).set(request.idempotencyKey, record)\n : current.bookings;\n\n const hold = Option.fromNullishOr(current.holds.get(request.idempotencyKey));\n\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n\n next.delete(request.idempotencyKey);\n\n return next;\n })()\n : current.holds;\n\n return [\n { record, hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(Effect.flatMap(({ hold, record }) => enterHold(hold).pipe(Effect.as(record))));\n\n const cancel = (bookingRef: BookingRef) =>\n Ref.modify(state, (current) => {\n const key = cancelBookingIdempotencyKey(bookingRef);\n const counts = new Map(current.counts).set(key, (current.counts.get(key) ?? 0) + 1);\n\n const existingEntry = [...current.bookings.entries()].find(\n ([, record]) => record.bookingRef === bookingRef,\n );\n\n if (existingEntry === undefined) {\n return [\n { record: Option.none<SupplierBookingRecord>(), hold: Option.none() },\n { ...current, counts },\n ] as const;\n }\n const [storeKey, existing] = existingEntry;\n\n const cancelled =\n existing.status === \"cancelled\"\n ? existing\n : SupplierBookingRecord.make({ ...existing, status: \"cancelled\" });\n\n const bookings = new Map(current.bookings).set(storeKey, cancelled);\n const hold = Option.fromNullishOr(current.holds.get(key));\n\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n\n next.delete(key);\n\n return next;\n })()\n : current.holds;\n\n return [\n { record: Option.some(cancelled), hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(\n Effect.flatMap(({ hold, record }) =>\n Option.isNone(record)\n ? Effect.fail(\n SupplierUnavailable.make({\n message: `The supplier desk has no booking under ${bookingRef}.`,\n }),\n )\n : enterHold(hold).pipe(Effect.as(record.value)),\n ),\n );\n\n return SupplierBookingDesk.of({\n book,\n cancel,\n lookup: (idempotencyKey) =>\n Ref.get(state).pipe(\n Effect.map((current) => Option.fromNullishOr(current.bookings.get(idempotencyKey))),\n ),\n bookings: Ref.get(state).pipe(Effect.map((current) => [...current.bookings.values()])),\n callCount: (idempotencyKey) =>\n Ref.get(state).pipe(Effect.map((current) => current.counts.get(idempotencyKey) ?? 0)),\n holdAfterWrite: (idempotencyKey) =>\n Effect.gen(function* () {\n const held = yield* Deferred.make<void>();\n const release = yield* Deferred.make<void>();\n\n yield* Ref.update(state, (current) => ({\n ...current,\n holds: new Map(current.holds).set(idempotencyKey, { held, release }),\n }));\n\n return {\n held: Deferred.await(held),\n release: Deferred.succeed(release, undefined).pipe(Effect.asVoid),\n };\n }),\n });\n }),\n );\n}\n\nexport const TravelGuidanceLayer = Layer.succeed(\n TravelGuidance,\n TravelGuidance.of({\n instructions: (input) =>\n Effect.succeed(\n [\n \"You are the Effect Agent Travel Planner P1 interpreter fixture.\",\n `The user asked: ${input.request}`,\n \"Call search_flights, search_lodging, and search_activities exactly once in one Tool batch.\",\n \"Then return only a JSON object of exactly this shape, no prose:\",\n '{\"itineraries\": [{\"title\": \"<short itinerary name>\", \"route\": \"<origin-destination>\", \"dates\": \"<date range>\", \"flight\": \"<flight description from the Tool result>\", \"lodging\": \"<lodging description from the Tool result>\", \"activities\": [\"<activity>\", \"...\"], \"estimatedTotalCents\": <positive integer total in cents>, \"currency\": \"USD\", \"quoteId\": \"<quoteId from the flight Tool result>\", \"assumptions\": [\"<assumption>\", \"...\"], \"unresolvedConstraints\": [], \"nextAction\": \"review\"}]}',\n \"Use the Tool results verbatim; activity results may legitimately be an empty array.\",\n \"This is read-only planning. Require review before any mutation.\",\n ].join(\"\\n\"),\n ),\n }),\n);\n\nexport const DeterministicIdGeneratorLayer = Layer.effect(\n IdGenerator,\n Effect.gen(function* () {\n const thread = yield* Ref.make(0);\n const run = yield* Ref.make(0);\n const turn = yield* Ref.make(0);\n\n return IdGenerator.of({\n nextThreadId: Ref.updateAndGet(thread, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(ThreadId)(`thread-${n}`)),\n ),\n nextRunId: Ref.updateAndGet(run, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(RunId)(`run-${n}`)),\n ),\n nextTurnId: Ref.updateAndGet(turn, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(TurnId)(`turn-${n}`)),\n ),\n });\n }),\n);\n\nexport const TravelPlannerRuntimeLayer = Layer.mergeAll(\n RunContextPreparationPassthrough,\n ThreadHistory.layer,\n TravelPlannerToolkitLayer,\n FlightCatalogLayer,\n LodgingCatalogLayer,\n ActivityCatalogLayer,\n TravelGuidanceLayer,\n DeterministicIdGeneratorLayer,\n).pipe(Layer.provide(CatalogLifecycle.layerNoDeps));\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@effect-agent/testing","version":"0.1.0-beta.84","dependencies":{"@effect-agent/capabilities":"0.1.0-beta.84","@effect-agent/core":"0.1.0-beta.84","@effect-agent/engine":"0.1.0-beta.84","@effect-agent/sandbox":"0.1.0-beta.84","@effect-agent/thread":"0.1.0-beta.84"},"devDependencies":{"@effect-agent/platform-node":"0.1.0-beta.84","@effect-agent/storage-memory":"0.1.0-beta.84","@effect-agent/storage-sqlite":"0.1.0-beta.84","@effect/platform-node":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112","@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Certification":{"types":"./dist/Certification.d.mts","default":"./dist/Certification.mjs"},"./Chaos":{"types":"./dist/Chaos.d.mts","default":"./dist/Chaos.mjs"},"./CodeExecutorConformance":{"types":"./dist/CodeExecutorConformance.d.mts","default":"./dist/CodeExecutorConformance.mjs"},"./CodeExecutorSubstitute":{"types":"./dist/CodeExecutorSubstitute.d.mts","default":"./dist/CodeExecutorSubstitute.mjs"},"./DocsResearcher":{"types":"./dist/DocsResearcher.d.mts","default":"./dist/DocsResearcher.mjs"},"./ScriptedModel":{"types":"./dist/ScriptedModel.d.mts","default":"./dist/ScriptedModel.mjs"},"./TravelPlanner":{"types":"./dist/TravelPlanner.d.mts","default":"./dist/TravelPlanner.mjs"}},"description":"Scripted models, deterministic fixtures, and adapter conformance kits for testing Effect Agent applications.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/testing"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
1
+ {"name":"@effect-agent/testing","version":"0.1.0-beta.86","dependencies":{"effect-agent":"0.1.0-beta.86"},"devDependencies":{"@effect-agent/platform-node":"0.1.0-beta.86","@effect-agent/storage-memory":"0.1.0-beta.86","@effect-agent/storage-sqlite":"0.1.0-beta.86","@effect/platform-node":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112","@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./certification":{"types":"./dist/Certification.d.mts","default":"./dist/Certification.mjs"},"./chaos":{"types":"./dist/Chaos.d.mts","default":"./dist/Chaos.mjs"},"./code-executor-conformance":{"types":"./dist/CodeExecutorConformance.d.mts","default":"./dist/CodeExecutorConformance.mjs"},"./code-executor-substitute":{"types":"./dist/CodeExecutorSubstitute.d.mts","default":"./dist/CodeExecutorSubstitute.mjs"},"./docs-researcher":{"types":"./dist/DocsResearcher.d.mts","default":"./dist/DocsResearcher.mjs"},"./scripted-model":{"types":"./dist/ScriptedModel.d.mts","default":"./dist/ScriptedModel.mjs"},"./travel-planner":{"types":"./dist/TravelPlanner.d.mts","default":"./dist/TravelPlanner.mjs"}},"description":"Scripted models, deterministic fixtures, and adapter conformance kits for testing Effect Agent applications.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/testing"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
@@ -1,39 +1,53 @@
1
- import * as Subagent from "@effect-agent/capabilities/Subagent";
2
- import { SubagentPolicy, SubagentRuntime } from "@effect-agent/capabilities/Subagent";
3
- import { SubagentReservationsMemoryLive } from "@effect-agent/capabilities/SubagentReservations";
4
- import * as Agent from "@effect-agent/core/Agent";
5
- import { AgentPolicy } from "@effect-agent/core/AgentPolicy";
1
+ import type { Crypto } from "effect";
6
2
  import {
7
- ThreadId,
8
- RunId,
9
- ToolCallId,
10
- TurnId,
11
- type AgentId,
12
- type SubmissionId,
13
- } from "@effect-agent/core/Identifiers";
14
- import { IdGenerator } from "@effect-agent/core/IdGenerator";
15
- import { DurableStep, DurableStepError } from "@effect-agent/engine/DurableStep";
16
- import { RunToolAuthorization } from "@effect-agent/engine/RunOptions";
17
- import { DurableWorkerBinding, type ResolvedBinding } from "@effect-agent/thread/AgentRegistration";
3
+ Cause,
4
+ Clock,
5
+ DateTime,
6
+ Duration,
7
+ Effect,
8
+ Exit,
9
+ Layer,
10
+ Option,
11
+ Ref,
12
+ Schema,
13
+ Stream,
14
+ } from "effect";
15
+ import * as Agent from "effect-agent/agent";
16
+ import { AgentPolicy } from "effect-agent/agent-policy";
17
+ import { DurableWorkerBinding, type ResolvedBinding } from "effect-agent/agent-registration";
18
18
  import {
19
19
  DurableAgentRuntime,
20
20
  DurableRuntimeConfig,
21
21
  type DurableSubmitFailure,
22
22
  type DurableSubmitOptions,
23
23
  type Receipt,
24
- } from "@effect-agent/thread/DurableAgentRuntime";
24
+ } from "effect-agent/durable-agent-runtime";
25
25
  import {
26
26
  DurableRuntimeFailpointError,
27
27
  DurableRuntimeFailpointLocation,
28
- } from "@effect-agent/thread/DurableFailpoint";
28
+ } from "effect-agent/durable-failpoint";
29
+ import { DurableStep, DurableStepError } from "effect-agent/durable-step";
30
+ import { IdGenerator } from "effect-agent/id-generator";
31
+ import {
32
+ ThreadId,
33
+ RunId,
34
+ ToolCallId,
35
+ TurnId,
36
+ type AgentId,
37
+ type SubmissionId,
38
+ } from "effect-agent/identifiers";
29
39
  import {
30
40
  DefinitionDigests,
31
41
  DeploymentId,
32
42
  Digest,
33
43
  ProducerId,
34
44
  type BatchId,
35
- } from "@effect-agent/thread/Records";
36
- import { childThreadIdFor } from "@effect-agent/thread/RunJournal";
45
+ } from "effect-agent/records";
46
+ import { childThreadIdFor } from "effect-agent/run-journal";
47
+ import { RunToolAuthorization } from "effect-agent/run-options";
48
+ import * as Subagent from "effect-agent/subagent";
49
+ import { SubagentPolicy } from "effect-agent/subagent";
50
+ import { SubagentReservationsMemoryLive } from "effect-agent/subagent-reservations";
37
51
  import {
38
52
  ApprovalDecisionCommand,
39
53
  IdempotencyKey,
@@ -44,42 +58,26 @@ import {
44
58
  UnknownResolutionCommand,
45
59
  DEFAULT_OWNERSHIP_LEASE_DURATION,
46
60
  type SubmissionSnapshot,
47
- } from "@effect-agent/thread/SubmissionLedger";
61
+ } from "effect-agent/submission-ledger";
48
62
  import {
49
63
  type CertificationCaseResult,
50
- CertificationReport,
64
+ type CertificationReport,
51
65
  CertificationSweepResult,
52
66
  CertificationTierThreeReport,
53
67
  CertifiedAdapterIdentity,
54
68
  certifyPorts,
55
69
  type CertificationScenario,
56
- } from "@effect-agent/thread/testing/Certification";
57
- import { DurableRuntimeFailpointTestControl } from "@effect-agent/thread/testing/DurableFailpointTestControl";
58
- import { verifyThreadInvariants } from "@effect-agent/thread/ThreadInvariants";
59
- import {
60
- ThreadExportRequest,
61
- ThreadStore,
62
- LoadCheckpointRequest,
63
- } from "@effect-agent/thread/ThreadStore";
64
- import { ToolReconciler } from "@effect-agent/thread/ToolReconciler";
65
- import { WakeScheduler } from "@effect-agent/thread/WakeScheduler";
66
- import type { Crypto } from "effect";
67
- import {
68
- Cause,
69
- Clock,
70
- DateTime,
71
- Duration,
72
- Effect,
73
- Exit,
74
- Layer,
75
- Option,
76
- Ref,
77
- Schema,
78
- Stream,
79
- } from "effect";
70
+ } from "effect-agent/testing/certification";
71
+ import { DurableRuntimeFailpointTestControl } from "effect-agent/testing/durable-failpoint-test-control";
72
+ import { verifyThreadInvariants } from "effect-agent/thread-invariants";
73
+ import { ThreadExportRequest, ThreadStore, LoadCheckpointRequest } from "effect-agent/thread-store";
74
+ import { ToolReconciler } from "effect-agent/tool-reconciler";
75
+ import { WakeScheduler } from "effect-agent/wake-scheduler";
80
76
  import { TestClock } from "effect/testing";
81
77
  import { LanguageModel, Model, Tool, Toolkit, type Response } from "effect/unstable/ai";
82
78
 
79
+ import { makeCertificationReport } from "./internal/certification-report.ts";
80
+
83
81
  /**
84
82
  * P7 WP2 — `certifyDurableAdapters` (plan §1): the one certification entry point a durable
85
83
  * adapter pair runs to earn a Schema-encoded certificate.
@@ -88,12 +86,13 @@ import { LanguageModel, Model, Tool, Toolkit, type Response } from "effect/unsta
88
86
  * `certifyPorts` (TEST-004/STORE-010).
89
87
  * - **Tier 2 — coordinator protocol + failpoint convergence**: the durable coordinator is
90
88
  * assembled over the CANDIDATE Layer pair with a scripted deterministic model; every
91
- * `DurableRuntimeFailpointLocation` is armed one-shot across the six scenario shapes
92
- * (plain / uncertain-tool / durable-steps / approval / join / delegation). After the injected
93
- * fault the runner asserts the state stays CLASSIFIABLE (recovery + the public unblocking
94
- * operations `resolveUnknown`/`resolveApproval` are the only levers used) and that the
95
- * re-drive CONVERGES to `verifyThreadInvariants` with `requireAllSettled` including a
96
- * fully discharged digest-chain check, because the runner captures per-batch producer
89
+ * reached `DurableRuntimeFailpointLocation` is armed one-shot across the six scenario shapes
90
+ * (plain / uncertain-tool / durable-steps / approval / join / delegation). Unreached locations
91
+ * share a verified clean run per shape; new unaccounted-for locations get a full sweep.
92
+ * After the injected fault the runner asserts the state stays CLASSIFIABLE (recovery +
93
+ * the public unblocking operations `resolveUnknown`/`resolveApproval` are the only levers
94
+ * used) and that the re-drive CONVERGES to `verifyThreadInvariants` with `requireAllSettled`,
95
+ * including a fully discharged digest-chain check, because the runner captures per-batch producer
97
96
  * identity at append time.
98
97
  * - **Tier 3 — real loss lever**: recorded honestly. A durable adapter either supplies a
99
98
  * `CertificationCrashLever` executed in this run, cites its committed real-loss evidence
@@ -161,9 +160,9 @@ export const CERTIFICATION_SCENARIOS: ReadonlyArray<CertificationScenario> = [
161
160
 
162
161
  /**
163
162
  * Coordinator failpoint locations that none of the six scenario shapes can reach, recorded
164
- * honestly instead of silently claimed. These require operator, compaction, reservation, or
165
- * background-worker paths the shapes do not take. They are pinned in-process by the P5/S2 suites
166
- * (`packages/testing/test/durable-tools.test.ts` "resolveUnknown is idempotent across the
163
+ * honestly instead of silently claimed. These require operator, compaction, reservation,
164
+ * background-worker, or Agent-update paths the shapes do not take. They are pinned in-process
165
+ * by the P5/S2 suites (`packages/testing/test/durable-tools.test.ts` "resolveUnknown is idempotent across the
167
166
  * intent failpoint", `durable-runtime.test.ts` abort rows,
168
167
  * `durable-subagents.test.ts` abort propagation) and by the process-kill/eviction crash
169
168
  * matrices. Runner tests assert the observed never-fired set equals EXACTLY this list, so a
@@ -188,7 +187,7 @@ export const TIER2_UNREACHED_LOCATIONS: ReadonlyArray<DurableRuntimeFailpointLoc
188
187
  "subagent:after-child-abort-intent",
189
188
  // Background workers use retained delivery, source capacity, and child-origin paths absent
190
189
  // from these six attached/ordinary scenarios. The before/after creation and completion
191
- // boundaries are exercised by packages/thread/test/worker-host.test.ts.
190
+ // boundaries are exercised by packages/effect-agent/test/durable/worker-host.test.ts.
192
191
  "worker:before-source-append",
193
192
  "worker:after-source-append",
194
193
  "worker:before-origin-append",
@@ -204,6 +203,15 @@ export const TIER2_UNREACHED_LOCATIONS: ReadonlyArray<DurableRuntimeFailpointLoc
204
203
  "worker:after-report-append",
205
204
  "worker:before-report-delivery",
206
205
  "worker:after-report-delivery",
206
+ // None of the six shapes emits Agent updates. All four boundaries are exercised separately
207
+ // by packages/effect-agent/test/durable/worker-host.test.ts ("repairs an accepted parent update after ...").
208
+ // Node restart/lost-ack coverage is in packages/platform-node/test/worker-updates.test.ts;
209
+ // Cloudflare eviction/alarm recovery is in packages/platform-cloudflare/test/background-workers.test.ts.
210
+ // These suites are not executed by this certification runner; its update rows remain not-triggered.
211
+ "update:before-canonical-append",
212
+ "update:after-canonical-append",
213
+ "update:before-delivery-insert",
214
+ "update:after-delivery-insert",
207
215
  ];
208
216
 
209
217
  /** Locations of `tier2` rows whose armed fault never fired in ANY scenario, sorted. */
@@ -651,7 +659,7 @@ const makeCell = Effect.fn("Certification.makeCell")(function* (
651
659
  ),
652
660
  );
653
661
 
654
- const delegationLayer = SubagentRuntime.layer(researchDelegation, childBinding, {
662
+ const delegationLayer = Subagent.layer(researchDelegation, childBinding, {
655
663
  mapChildFailure,
656
664
  durable: { targetDigests: CHILD_DIGEST_STRINGS },
657
665
  }).pipe(Layer.provide(delegationSupport));
@@ -769,26 +777,29 @@ const failureTagOf = <E>(cause: Cause.Cause<E>): string => {
769
777
  return "defect";
770
778
  };
771
779
 
772
- /** One Tier-2 sweep cell: arm `location` one-shot, drive `scenario`, converge, verify. */
780
+ type SweepOutcome = Pick<
781
+ CertificationSweepResult,
782
+ "failpointFired" | "status" | "digestChainVerified" | "detail"
783
+ >;
784
+
785
+ /** Discover a clean path, or arm one location; both drives converge and verify real storage. */
773
786
  const runSweepCell = Effect.fn("Certification.runSweepCell")(function* (
774
787
  scenario: CertificationScenario,
775
- location: DurableRuntimeFailpointLocation,
788
+ location: DurableRuntimeFailpointLocation | undefined,
776
789
  batchProducers: ReadonlyMap<BatchId, ProducerId>,
777
790
  leaseAdvance: Duration.Duration,
791
+ reached: Set<DurableRuntimeFailpointLocation>,
778
792
  ) {
779
793
  const ledger = yield* SubmissionLedger;
780
794
  const control = yield* DurableRuntimeFailpointTestControl;
781
- const slug = `${scenario}-${location.replaceAll(":", "-")}`;
782
-
783
- const failed = (detail: string, fired: boolean): CertificationSweepResult =>
784
- CertificationSweepResult.make({
785
- scenario,
786
- location,
787
- failpointFired: fired,
788
- status: "failed",
789
- digestChainVerified: false,
790
- detail: detail.slice(0, 4_096),
791
- });
795
+ const slug = `${scenario}-${location?.replaceAll(":", "-") ?? "discovery"}`;
796
+
797
+ const failed = (detail: string, fired: boolean): SweepOutcome => ({
798
+ failpointFired: fired,
799
+ status: "failed",
800
+ digestChainVerified: false,
801
+ detail: detail.slice(0, 4_096),
802
+ });
792
803
 
793
804
  const cell = yield* makeCell(scenario, slug);
794
805
 
@@ -807,15 +818,19 @@ const runSweepCell = Effect.fn("Certification.runSweepCell")(function* (
807
818
  const fired = yield* Ref.make(false);
808
819
 
809
820
  yield* control.setHandler((hit) =>
810
- hit !== location
811
- ? Effect.void
812
- : Ref.getAndSet(fired, true).pipe(
813
- Effect.flatMap((already) =>
814
- already
815
- ? Effect.void
816
- : Effect.fail(DurableRuntimeFailpointError.make({ location: hit })),
817
- ),
818
- ),
821
+ Effect.suspend(() => {
822
+ reached.add(hit);
823
+
824
+ return hit !== location
825
+ ? Effect.void
826
+ : Ref.getAndSet(fired, true).pipe(
827
+ Effect.flatMap((already) =>
828
+ already
829
+ ? Effect.void
830
+ : Effect.fail(DurableRuntimeFailpointError.make({ location: hit })),
831
+ ),
832
+ );
833
+ }),
819
834
  );
820
835
 
821
836
  // Submissions are idempotent (DUR-001): one replay recovers a submit-boundary fault.
@@ -945,13 +960,11 @@ const runSweepCell = Effect.fn("Certification.runSweepCell")(function* (
945
960
  );
946
961
  }
947
962
 
948
- return CertificationSweepResult.make({
949
- scenario,
950
- location,
963
+ return {
951
964
  failpointFired: wasFired,
952
965
  status: wasFired ? "converged" : "not-triggered",
953
966
  digestChainVerified,
954
- });
967
+ } satisfies SweepOutcome;
955
968
  });
956
969
 
957
970
  // ---------------------------------------------------------------------------
@@ -1070,12 +1083,73 @@ export const certifyDurableAdapters = <LedgerE = never, StoreE = never>(
1070
1083
  const program = Effect.gen(function* () {
1071
1084
  const ledger = yield* SubmissionLedger;
1072
1085
 
1073
- // Tier 2 — coordinator failpoint convergence sweep.
1086
+ // Tier 2 — discover each deterministic shape without a fault. Unreached locations
1087
+ // would all repeat this same clean drive, including its full digest verification.
1074
1088
  const tier2: Array<CertificationSweepResult> = [];
1075
1089
 
1090
+ const discoveries: Array<{
1091
+ readonly scenario: CertificationScenario;
1092
+ readonly outcome: SweepOutcome;
1093
+ readonly reached: Set<DurableRuntimeFailpointLocation>;
1094
+ }> = [];
1095
+
1076
1096
  for (const scenario of CERTIFICATION_SCENARIOS) {
1097
+ const reached = new Set<DurableRuntimeFailpointLocation>();
1098
+
1099
+ const outcome = yield* runSweepCell(
1100
+ scenario,
1101
+ undefined,
1102
+ batchProducers,
1103
+ leaseAdvance,
1104
+ reached,
1105
+ );
1106
+
1107
+ discoveries.push({ scenario, outcome, reached });
1108
+ }
1109
+ const observed = new Set(discoveries.flatMap(({ reached }) => [...reached]));
1110
+
1111
+ // Never silently omit a new location: if neither discovery nor the documented
1112
+ // never-fired set accounts for it, arm it in EVERY shape. Tests pin the fired paths
1113
+ // per shape and the never-fired set, so new or lost routes require explicit review.
1114
+ const unaccounted = new Set(
1115
+ DurableRuntimeFailpointLocation.literals.filter(
1116
+ (location) => !observed.has(location) && !TIER2_UNREACHED_LOCATIONS.includes(location),
1117
+ ),
1118
+ );
1119
+
1120
+ for (const discovery of discoveries) {
1121
+ const { scenario, reached } = discovery;
1122
+ const outcomes = new Map<DurableRuntimeFailpointLocation, SweepOutcome>();
1123
+
1124
+ if (discovery.outcome.status !== "failed") {
1125
+ while (true) {
1126
+ // Recovery may expose another route. Discover those too, without re-running a
1127
+ // cell already checked. Schema order bounds this to one drive per location.
1128
+ const location = DurableRuntimeFailpointLocation.literals.find(
1129
+ (candidate) =>
1130
+ !outcomes.has(candidate) && (reached.has(candidate) || unaccounted.has(candidate)),
1131
+ );
1132
+
1133
+ if (location === undefined) break;
1134
+ outcomes.set(
1135
+ location,
1136
+ yield* runSweepCell(scenario, location, batchProducers, leaseAdvance, reached),
1137
+ );
1138
+ }
1139
+ }
1077
1140
  for (const location of DurableRuntimeFailpointLocation.literals) {
1078
- tier2.push(yield* runSweepCell(scenario, location, batchProducers, leaseAdvance));
1141
+ const outcome = outcomes.get(location) ?? discovery.outcome;
1142
+
1143
+ tier2.push(
1144
+ CertificationSweepResult.make({
1145
+ scenario,
1146
+ location,
1147
+ ...outcome,
1148
+ ...(outcomes.has(location) || outcome.status === "failed"
1149
+ ? {}
1150
+ : { detail: "verified clean scenario did not reach this location" }),
1151
+ }),
1152
+ );
1079
1153
  }
1080
1154
  }
1081
1155
 
@@ -1088,13 +1162,7 @@ export const certifyDurableAdapters = <LedgerE = never, StoreE = never>(
1088
1162
 
1089
1163
  const generatedAt = yield* nowUtc;
1090
1164
 
1091
- const ok =
1092
- tier1.every((result) => result.status === "passed") &&
1093
- tier2.every((result) => result.status !== "failed") &&
1094
- tier3.cases.every((result) => result.status === "passed");
1095
-
1096
- return CertificationReport.make({
1097
- format: "effect-agent/certification@2",
1165
+ return makeCertificationReport({
1098
1166
  adapter: CertifiedAdapterIdentity.make({
1099
1167
  name: options.adapter.name,
1100
1168
  ...(options.adapter.version === undefined ? {} : { version: options.adapter.version }),
@@ -1104,13 +1172,6 @@ export const certifyDurableAdapters = <LedgerE = never, StoreE = never>(
1104
1172
  tier1,
1105
1173
  tier2,
1106
1174
  tier3,
1107
- ok,
1108
- fullyCertified:
1109
- ok &&
1110
- capabilities.durability !== "non-durable" &&
1111
- tier3.status === "exercised" &&
1112
- tier3.cases.length > 0 &&
1113
- tier3.cases.every((result) => result.suite === "real-loss"),
1114
1175
  });
1115
1176
  });
1116
1177
 
package/src/Chaos.ts CHANGED
@@ -1,47 +1,38 @@
1
- import * as Subagent from "@effect-agent/capabilities/Subagent";
2
- import { SubagentPolicy, SubagentRuntime } from "@effect-agent/capabilities/Subagent";
3
- import { SubagentReservationsMemoryLive } from "@effect-agent/capabilities/SubagentReservations";
4
- import * as Agent from "@effect-agent/core/Agent";
5
- import { AgentPolicy } from "@effect-agent/core/AgentPolicy";
6
- import {
7
- ThreadId,
8
- RunId,
9
- ToolCallId,
10
- TurnId,
11
- type SubmissionId,
12
- } from "@effect-agent/core/Identifiers";
13
- import { IdGenerator } from "@effect-agent/core/IdGenerator";
14
- import {
15
- DurableStep,
16
- DurableStepError,
17
- ToolExecutionClass,
18
- } from "@effect-agent/engine/DurableStep";
19
- import { RunToolAuthorization } from "@effect-agent/engine/RunOptions";
20
- import { ObligationThresholds } from "@effect-agent/thread/Admin";
1
+ import { Cause, Effect, Exit, Layer, Option, Ref, Schema, Stream } from "effect";
2
+ import { ObligationThresholds } from "effect-agent/admin";
3
+ import * as Agent from "effect-agent/agent";
4
+ import { AgentPolicy } from "effect-agent/agent-policy";
21
5
  import {
22
6
  DurableWorkerBinding,
23
7
  type DurableBindingFailure,
24
8
  type ResolvedBinding,
25
- } from "@effect-agent/thread/AgentRegistration";
9
+ } from "effect-agent/agent-registration";
26
10
  import {
27
11
  DurableAgentRuntime,
28
12
  DurableRuntimeConfig,
29
13
  type DurableSubmitFailure,
30
14
  type DurableWorkerFailure,
31
15
  type Receipt,
32
- } from "@effect-agent/thread/DurableAgentRuntime";
16
+ } from "effect-agent/durable-agent-runtime";
33
17
  import {
34
18
  DurableRuntimeFailpointError,
35
19
  DurableRuntimeFailpointLocation,
36
- } from "@effect-agent/thread/DurableFailpoint";
20
+ } from "effect-agent/durable-failpoint";
21
+ import { DurableStep, DurableStepError, ToolExecutionClass } from "effect-agent/durable-step";
22
+ import { IdGenerator } from "effect-agent/id-generator";
23
+ import { ThreadId, RunId, ToolCallId, TurnId, type SubmissionId } from "effect-agent/identifiers";
37
24
  import {
38
25
  DefinitionDigests,
39
26
  Digest,
40
27
  type CanonicalRecordEnvelope,
41
28
  type BatchId,
42
29
  type ProducerId,
43
- } from "@effect-agent/thread/Records";
44
- import { childThreadIdFor } from "@effect-agent/thread/RunJournal";
30
+ } from "effect-agent/records";
31
+ import { childThreadIdFor } from "effect-agent/run-journal";
32
+ import { RunToolAuthorization } from "effect-agent/run-options";
33
+ import * as Subagent from "effect-agent/subagent";
34
+ import { SubagentPolicy } from "effect-agent/subagent";
35
+ import { SubagentReservationsMemoryLive } from "effect-agent/subagent-reservations";
45
36
  import {
46
37
  AbortCommand,
47
38
  ApprovalDecisionCommand,
@@ -56,11 +47,10 @@ import {
56
47
  type Settlement,
57
48
  type SubmissionSnapshot,
58
49
  type UnknownResolution,
59
- } from "@effect-agent/thread/SubmissionLedger";
60
- import { DurableRuntimeFailpointTestControl } from "@effect-agent/thread/testing/DurableFailpointTestControl";
61
- import { verifyThreadInvariants } from "@effect-agent/thread/ThreadInvariants";
62
- import { ThreadExportRequest, ThreadStore } from "@effect-agent/thread/ThreadStore";
63
- import { Cause, Effect, Exit, Layer, Option, Ref, Schema, Stream } from "effect";
50
+ } from "effect-agent/submission-ledger";
51
+ import { DurableRuntimeFailpointTestControl } from "effect-agent/testing/durable-failpoint-test-control";
52
+ import { verifyThreadInvariants } from "effect-agent/thread-invariants";
53
+ import { ThreadExportRequest, ThreadStore } from "effect-agent/thread-store";
64
54
  import { FastCheck } from "effect/testing";
65
55
  import {
66
56
  LanguageModel,
@@ -769,7 +759,7 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
769
759
 
770
760
  const childBinding = Agent.withModel(childDefinition, childModel);
771
761
 
772
- const delegationLayer = SubagentRuntime.layer(chaosDelegation, childBinding, {
762
+ const delegationLayer = Subagent.layer(chaosDelegation, childBinding, {
773
763
  mapChildFailure: (failure) => ChaosDelegationFailed.make({ childErrorTag: failure._tag }),
774
764
  durable: { targetDigests: childDigestStrings(laneIndex) },
775
765
  }).pipe(Layer.provide(delegationSupport));
@@ -1,3 +1,4 @@
1
+ import { Deferred, Duration, Effect, Fiber, Schema } from "effect";
1
2
  import {
2
3
  CodeExecutionHost,
3
4
  CodeExecutionLimits,
@@ -10,13 +11,12 @@ import {
10
11
  type CodeExecutionResult,
11
12
  type CodeHostCall,
12
13
  type CodeHostCallResult,
13
- } from "@effect-agent/sandbox/CodeExecutor";
14
+ } from "effect-agent/code-executor";
14
15
  import {
15
16
  NetworkAllowlist,
16
17
  NetworkDisabled,
17
18
  type SandboxImplementation,
18
- } from "@effect-agent/sandbox/Sandbox";
19
- import { Deferred, Duration, Effect, Fiber, Schema } from "effect";
19
+ } from "effect-agent/sandbox";
20
20
 
21
21
  /**
22
22
  * Shared `CodeExecutor` conformance (TEST-015). Every adapter — the
@@ -1,3 +1,4 @@
1
+ import { Clock, Duration, Effect, Fiber, Layer, Option, Queue, Schema } from "effect";
1
2
  import {
2
3
  CodeExecutionHost,
3
4
  CodeExecutionProtocolError,
@@ -16,9 +17,8 @@ import {
16
17
  type CodeExecutionLimits,
17
18
  type CodeExecutionNamespace,
18
19
  type CodeExecutionRequest,
19
- } from "@effect-agent/sandbox/CodeExecutor";
20
- import { SandboxImplementation } from "@effect-agent/sandbox/Sandbox";
21
- import { Clock, Duration, Effect, Fiber, Layer, Option, Queue, Schema } from "effect";
20
+ } from "effect-agent/code-executor";
21
+ import { SandboxImplementation } from "effect-agent/sandbox";
22
22
 
23
23
  /**
24
24
  * The deterministic in-process executor substitute (C1 of ADR-0017). It runs