stitchkit 0.66.0 → 0.66.1

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.
@@ -1,6 +1,39 @@
1
1
  import type { AgentRuntimeStore } from '../agent-runtime/store';
2
+ /**
3
+ * What the scenario is about to touch, handed over before the first mutation.
4
+ *
5
+ * The kit used to pick its conversation identities *after* `createStore()`
6
+ * returned, which locked out exactly the adapters it exists to certify: a
7
+ * durable store whose runtime rows hang off an application-owned conversation
8
+ * row cannot serve the first admission, because nobody ever told it which
9
+ * parent to provision. Running the kit against the memory reference store
10
+ * instead proves the reducer — which is not the thing under test.
11
+ */
12
+ export interface AgentStoreConformanceContext {
13
+ /**
14
+ * Every conversation the scenario mutates, in the order it first touches
15
+ * them. Provision one parent per id before returning the store, and remove
16
+ * them again in `cleanup`.
17
+ */
18
+ readonly conversationIds: readonly string[];
19
+ }
2
20
  export interface AgentStoreConformanceConfig {
3
- createStore(): AgentRuntimeStore | Promise<AgentRuntimeStore>;
21
+ /**
22
+ * Build the store under test. The context arrives first so an adapter can
23
+ * provision fixture state; a factory that needs none may ignore it, and an
24
+ * existing zero-argument factory stays valid unchanged.
25
+ */
26
+ createStore(context: AgentStoreConformanceContext): AgentRuntimeStore | Promise<AgentRuntimeStore>;
27
+ /**
28
+ * Remove whatever `createStore` provisioned.
29
+ *
30
+ * Runs exactly once, after the scenario, whether it passed or failed — a kit
31
+ * that only cleans up on success leaks a row for every red run, which is the
32
+ * shape that makes a failing suite un-rerunnable. A failure here never
33
+ * replaces the scenario's own: the answer to "does this adapter conform" is
34
+ * not overwritten by the answer to "did the teardown work".
35
+ */
36
+ cleanup?(context: AgentStoreConformanceContext): void | Promise<void>;
4
37
  }
5
38
  /** Black-box contract shared by memory and third-party durable agent stores. */
6
39
  export declare function runAgentStoreConformance(config: AgentStoreConformanceConfig): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-store-conformance.d.ts","sourceRoot":"","sources":["../../src/testing/agent-store-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,MAAM,WAAW,2BAA2B;IAC1C,WAAW,IAAI,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/D;AAwCD,gFAAgF;AAChF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,IAAI,CAAC,CAobf"}
1
+ {"version":3,"file":"agent-store-conformance.d.ts","sourceRoot":"","sources":["../../src/testing/agent-store-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE;;;;;;;;;GASG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,WAAW,CACT,OAAO,EAAE,4BAA4B,GACpC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClD;;;;;;;;OAQG;IACH,OAAO,CAAC,CAAC,OAAO,EAAE,4BAA4B,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE;AAwCD,gFAAgF;AAChF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
package/dist/testing.d.ts CHANGED
@@ -32,7 +32,7 @@ export declare function createHandlerTestClients<T extends Record<string, Contra
32
32
  [P in keyof T]: ScopedHttpClient<T[P]['endpoints'], ScopedKeys<K>>;
33
33
  };
34
34
  export { type AgentRaceBarrier, type AgentRaceDriver, type AgentRaceTrace, type AgentRaceTraceEntry, createAgentRaceBarrier, createAgentRaceDriver, createAgentRaceTrace, } from './agent-runtime/testing';
35
- export { type AgentStoreConformanceConfig, runAgentStoreConformance, } from './testing/agent-store-conformance';
35
+ export { type AgentStoreConformanceConfig, type AgentStoreConformanceContext, runAgentStoreConformance, } from './testing/agent-store-conformance';
36
36
  export { type ManagedResourceConformanceConfig, type ManagedResourceConformanceControls, ManagedResourceConformanceError, type ManagedResourceConformanceFactoryInput, type ManagedResourceConformanceFixture, type ManagedResourceConformancePhase, ManagedResourceConformancePhaseSchema, type ManagedResourceConformanceScenario, type ManagedResourceConformanceScenarioId, ManagedResourceConformanceScenarioIdSchema, ManagedResourceConformanceScenarioSchema, type ManagedResourceConformanceTraceEntry, ManagedResourceConformanceTraceEntrySchema, type ManagedResourceConformanceTraceOutcome, ManagedResourceConformanceTraceOutcomeSchema, runManagedResourceConformance, } from './testing/managed-resource-conformance';
37
37
  export { assertSurfaceDiscovery, type ConformanceTransport, type CreateRealtimeProbeDriverConfig, createRealtimeProbeDriver, type DefineRealtimeProbeConfig, defineRealtimeProbe, type RealtimeDisconnectObservation, RealtimeDisconnectObservationSchema, type RealtimeProbeAdapter, type RealtimeProbeFixture, type RealtimeProbeScenario, type RealtimeRejectionObservation, RealtimeRejectionObservationSchema, type RunSurfaceProbesConfig, runSurfaceProbes, type SurfaceDiscoveryObservation, type SurfaceProbe, type SurfaceProbeDriver, type SurfaceRealtimeDiscoveryObservation, type SurfaceToolDiscoveryObservation, type TransportObservation, TransportObservationSchema, } from './testing/surface-conformance';
38
38
  export { assertSurfaceManifestSnapshot, buildSurfaceManifest, type IncompatibleSchemaPolicy, type McpSchemaValidationConfig, type SurfaceAgentProjection, type SurfaceManifest, type SurfaceManifestConfig, type SurfaceManifestExtension, SurfaceManifestExtensionSchema, type SurfaceManifestOperation, SurfaceManifestOperationSchema, type SurfaceManifestRealtimeEvent, SurfaceManifestRealtimeEventSchema, SurfaceManifestSchema, type SurfaceManifestTool, SurfaceManifestToolSchema, type SurfaceManifestToolSurface, SurfaceManifestToolSurfaceSchema, type SurfaceMcpPreparation, SurfaceRealtimeSchemaPairSchema, type SurfaceRuntimeToolDefinition, SurfaceSchemaDigestsSchema, type SurfaceToolDefinition, type SurfaceToolExtension, serializeSurfaceValue, } from './testing/surface-manifest';
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
package/dist/testing.js CHANGED
@@ -141,8 +141,33 @@ function requireOutcome(actual, expected) {
141
141
  }
142
142
  }
143
143
  async function runAgentStoreConformance(config) {
144
- const store = await config.createStore();
145
- const conversationId = `conformance-${crypto.randomUUID()}`;
144
+ const run = `conformance-${crypto.randomUUID()}`;
145
+ const context = {
146
+ conversationIds: [run, `${run}-recovery`, `${run}-absorb`]
147
+ };
148
+ const store = await config.createStore(context);
149
+ let failure;
150
+ try {
151
+ await conformanceScenario(store, context.conversationIds);
152
+ } catch (error) {
153
+ failure = error;
154
+ }
155
+ try {
156
+ await config.cleanup?.(context);
157
+ } catch (cleanupError) {
158
+ if (failure === undefined)
159
+ throw cleanupError;
160
+ throw new AggregateError([failure, cleanupError], `${failure instanceof Error ? failure.message : String(failure)} (cleanup also failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)})`);
161
+ }
162
+ if (failure !== undefined)
163
+ throw failure;
164
+ }
165
+ async function conformanceScenario(store, conversationIds) {
166
+ const [conversationId, recoveryConversationId, absorbConversationId] = conversationIds;
167
+ if (!conversationId || !recoveryConversationId || !absorbConversationId) {
168
+ throw new Error("Agent store conformance requires three conversation identities");
169
+ }
170
+ const absentConversationId = `${conversationId}-absent`;
146
171
  const firstInput = userMessage(conversationId, "input-1");
147
172
  const firstRun = queuedRun(conversationId, firstInput.id, "run-1");
148
173
  const accepted = await store.acceptInputAndAssignRun({
@@ -373,7 +398,7 @@ async function runAgentStoreConformance(config) {
373
398
  if (await store.loadRun({ conversationId, runId: "no-such-run" })) {
374
399
  throw new Error("loadRun must return undefined for an unknown run");
375
400
  }
376
- if (await store.loadRun({ conversationId: "no-such-conversation", runId: running.id })) {
401
+ if (await store.loadRun({ conversationId: absentConversationId, runId: running.id })) {
377
402
  throw new Error("loadRun must not cross conversation boundaries");
378
403
  }
379
404
  const activeRuns = await store.listActiveRuns(conversationId);
@@ -393,7 +418,7 @@ async function runAgentStoreConformance(config) {
393
418
  throw new Error("listActiveRuns must order by createdAt and then by id");
394
419
  }
395
420
  }
396
- if ((await store.listActiveRuns("no-such-conversation")).length !== 0) {
421
+ if ((await store.listActiveRuns(absentConversationId)).length !== 0) {
397
422
  throw new Error("listActiveRuns must be empty for an unknown conversation");
398
423
  }
399
424
  const recoverable = await store.scanRecoverable({ limit: 10 });
@@ -488,7 +513,6 @@ async function runAgentStoreConformance(config) {
488
513
  if (duplicateTerminal.run.terminalReason !== "success" || JSON.stringify(duplicateTerminal.assistant) !== JSON.stringify(terminalAssistant)) {
489
514
  throw new Error("Compaction discarded the canonical duplicate terminal result");
490
515
  }
491
- const recoveryConversationId = `${conversationId}-recovery`;
492
516
  const recoveryInput = userMessage(recoveryConversationId, "recovery-input");
493
517
  const recoveryRun = queuedRun(recoveryConversationId, recoveryInput.id, "recovery-run");
494
518
  const recoveryAccepted = await store.acceptInputAndAssignRun({
@@ -522,10 +546,9 @@ async function runAgentStoreConformance(config) {
522
546
  if (terminalRun?.state !== "abandoned" || terminalMessage?.status !== "failed") {
523
547
  throw new Error("Abandon recovery did not atomically terminalize its assistant record");
524
548
  }
525
- await assertAbsorptionIsAtomic(store);
549
+ await assertAbsorptionIsAtomic(store, absorbConversationId);
526
550
  }
527
- async function assertAbsorptionIsAtomic(store) {
528
- const conversationId = `conformance-absorb-${crypto.randomUUID()}`;
551
+ async function assertAbsorptionIsAtomic(store, conversationId) {
529
552
  const leadInput = userMessage(conversationId, "absorb-input-1");
530
553
  const leadRun = queuedRun(conversationId, leadInput.id, "absorb-run-1");
531
554
  const lead = await store.acceptInputAndAssignRun({
package/llms-full.txt CHANGED
@@ -4171,8 +4171,14 @@ outbox.
4171
4171
  `stitchkit/testing` exports `createAgentRaceBarrier`, `createAgentRaceDriver` and
4172
4172
  `createAgentRaceTrace`. Barriers have bounded teardown, traces assert exact partial order, and the
4173
4173
  helpers are exercised from packed Bun and Node consumers. `runAgentStoreConformance` runs duplicate,
4174
- coalescing, collision, stale checkpoint, replay safety, terminal race, compaction and recovery
4175
- invariants against any fresh durable adapter.
4174
+ coalescing, collision, stale checkpoint, replay safety, terminal race, absorption, bounded reads,
4175
+ compaction and recovery invariants against any fresh durable adapter.
4176
+
4177
+ It picks its conversation identities itself and passes them to `createStore(context)` **before the
4178
+ first mutation**, so an adapter whose runtime rows reference an application-owned conversation row
4179
+ can provision those parents; the optional `cleanup(context)` removes them again, and runs once
4180
+ whether the scenario passed or failed. A factory that owns no fixture state ignores the argument and
4181
+ keeps working unchanged.
4176
4182
 
4177
4183
 
4178
4184
  ==============================================================================
@@ -7856,9 +7862,28 @@ Prisma adapter, an in-memory one, anything — run the conformance kit against i
7856
7862
  ```ts
7857
7863
  import { runAgentStoreConformance } from 'stitchkit/testing'
7858
7864
 
7859
- await runAgentStoreConformance({ store: yourStore, conversationId: 'conformance' })
7865
+ await runAgentStoreConformance({ createStore: () => yourStore })
7860
7866
  ```
7861
7867
 
7868
+ The kit picks the conversation identities itself and hands them over **before**
7869
+ the first mutation, so a store whose runtime rows hang off an application-owned
7870
+ conversation row can provision the parents — and take them away again:
7871
+
7872
+ ```ts
7873
+ await runAgentStoreConformance({
7874
+ createStore: (context) => {
7875
+ for (const conversationId of context.conversationIds) createConversationRow(conversationId)
7876
+ return yourStore
7877
+ },
7878
+ cleanup: (context) => {
7879
+ for (const conversationId of context.conversationIds) deleteConversationRow(conversationId)
7880
+ },
7881
+ })
7882
+ ```
7883
+
7884
+ `cleanup` runs exactly once, after the scenario, whether it passed or failed —
7885
+ and a failure in it never replaces the scenario's own.
7886
+
7862
7887
  Green before and red after tells you the contract grew and where, in one run,
7863
7888
  instead of one failure at a time in production. Green both times means the
7864
7889
  upgrade owes you nothing on that surface — which is the usual answer if you
@@ -11126,7 +11151,8 @@ handler pipeline without opening a TCP port.
11126
11151
  | `createHandlerTestClient` | function | one contract client backed by an in-process `FetchHandler` |
11127
11152
  | `createHandlerTestClients` | function | exact contract-registry batch form |
11128
11153
  | `runAgentStoreConformance` | function | reusable black-box duplicate/coalescing/stale/recovery contract for durable agent-store adapters |
11129
- | `AgentStoreConformanceConfig` | _type_ | factory configuration for running the same contract against a fresh adapter |
11154
+ | `AgentStoreConformanceConfig` | _type_ | `{ createStore(context), cleanup?(context) }` the factory the contract runs against, plus a teardown that runs once whether the scenario passed or failed |
11155
+ | `AgentStoreConformanceContext` | _type_ | `{ conversationIds }` — every conversation the scenario will mutate, handed over **before** the first mutation so an adapter can provision application-owned parent rows; a zero-argument factory stays valid |
11130
11156
  | `runManagedResourceConformance` | function | run the canonical deterministic lifecycle matrix against a fresh consumer-owned `ManagedResource` fixture; resolves `void` or throws `ManagedResourceConformanceError` with a stable scenario ID and normalized trace |
11131
11157
  | `ManagedResourceConformanceScenarioIdSchema` / `ManagedResourceConformanceScenarioId` | schema / _type_ | stable clean, rollback, readiness/completion, activation, shutdown-race and forced-cleanup scenario vocabulary |
11132
11158
  | `ManagedResourceConformanceScenarioSchema` / `ManagedResourceConformanceScenario` | schema / _type_ | discriminated scenario record including whether the controlled resource is required |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.66.0",
3
+ "version": "0.66.1",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",