| ... | ... | @@ -29,6 +29,7 @@ import * as Deferred from "effect/Deferred"; |
| 29 | 29 | import * as Fiber from "effect/Fiber"; |
| 30 | 30 | import * as Effect from "effect/Effect"; |
| 31 | 31 | import * as Layer from "effect/Layer"; |
| 32 | import * as SqlClient from "effect/sql/SqlClient"; |
| 32 | 33 | import * as Stream from "effect/Stream"; |
| 33 | 34 | import * as TestClock from "effect/testing/TestClock"; |
| 34 | 35 | |
| ... | ... | @@ -58,6 +59,7 @@ const layerTestEventSink = EventSink.layer.pipe( |
| 58 | 59 | ); |
| 59 | 60 | |
| 60 | 61 | const layerTest = Layer.mergeAll( |
| 62 | layerTestDatabase, |
| 61 | 63 | layerTestStores, |
| 62 | 64 | layerTestEventSink, |
| 63 | 65 | IdAllocator.layer, |
| ... | ... | @@ -1514,6 +1516,84 @@ layer("ProviderEventIngestorV2", (it) => { |
| 1514 | 1516 | }), |
| 1515 | 1517 | ); |
| 1516 | 1518 | |
| 1519 | it.effect("stores a bounded copy of a large file-change diff in both SQLite tables", () => |
| 1520 | Effect.gen(function* () { |
| 1521 | const now = yield* DateTime.now; |
| 1522 | const eventSink = yield* EventSink.EventSinkV2; |
| 1523 | const projectionStore = yield* ProjectionStore.ProjectionStoreV2; |
| 1524 | const ingestor = yield* ProviderEventIngestor.ProviderEventIngestorV2; |
| 1525 | const idAllocator = yield* IdAllocator.IdAllocatorV2; |
| 1526 | const threadEvent = yield* threadCreatedEvent(now); |
| 1527 | const providerSessionId = yield* idAllocator.allocate.providerSession({ |
| 1528 | providerInstanceId: modelSelection.instanceId, |
| 1529 | threadId: threadEvent.threadId, |
| 1530 | }); |
| 1531 | const largeDiff = `@@ -0,0 +1 @@\n${"+generated line\n".repeat(150_000)}`; |
| 1532 | const fileChange = ( |
| 1533 | id: string, |
| 1534 | ordinal: number, |
| 1535 | diffStr: string, |
| 1536 | ): OrchestrationV2TurnItem => ({ |
| 1537 | id: TurnItemId.make(id), |
| 1538 | threadId: threadEvent.threadId, |
| 1539 | runId: null, |
| 1540 | nodeId: null, |
| 1541 | providerThreadId: null, |
| 1542 | providerTurnId: null, |
| 1543 | nativeItemRef: null, |
| 1544 | parentItemId: null, |
| 1545 | ordinal, |
| 1546 | status: "completed", |
| 1547 | title: null, |
| 1548 | startedAt: now, |
| 1549 | completedAt: now, |
| 1550 | updatedAt: now, |
| 1551 | type: "file_change", |
| 1552 | fileName: "src/generated.ts", |
| 1553 | diffStr, |
| 1554 | }); |
| 1555 | const large = fileChange("turn-item:large-diff", 1, largeDiff); |
| 1556 | const small = fileChange("turn-item:small-diff", 2, "@@ -1 +1 @@\n-old\n+new\n"); |
| 1557 | |
| 1558 | yield* eventSink.write({ events: [threadEvent] }); |
| 1559 | for (const turnItem of [large, small]) { |
| 1560 | yield* ingestor.ingestNormalized({ |
| 1561 | providerSessionId, |
| 1562 | providerInstanceId: modelSelection.instanceId, |
| 1563 | threadId: threadEvent.threadId, |
| 1564 | event: { type: "turn_item.updated", driver: CODEX_DRIVER, turnItem }, |
| 1565 | }); |
| 1566 | } |
| 1567 | |
| 1568 | const sql = yield* SqlClient.SqlClient; |
| 1569 | const storedBytes = yield* sql<{ readonly events: number; readonly projection: number }>` |
| 1570 | SELECT |
| 1571 | (SELECT SUM(LENGTH(payload_json)) FROM orchestration_events |
| 1572 | WHERE stream_id = ${threadEvent.threadId} AND event_type = 'turn-item.updated') AS events, |
| 1573 | (SELECT SUM(LENGTH(payload_json)) FROM orchestration_v2_projection_turn_items |
| 1574 | WHERE thread_id = ${threadEvent.threadId}) AS projection |
| 1575 | `; |
| 1576 | const projectedLarge = yield* projectionStore.getTurnItem({ |
| 1577 | threadId: threadEvent.threadId, |
| 1578 | itemId: large.id, |
| 1579 | }); |
| 1580 | const projectedSmall = yield* projectionStore.getTurnItem({ |
| 1581 | threadId: threadEvent.threadId, |
| 1582 | itemId: small.id, |
| 1583 | }); |
| 1584 | |
| 1585 | assert.isAbove(largeDiff.length, 2_000_000); |
| 1586 | assert.isBelow(storedBytes[0]!.events, 100_000); |
| 1587 | assert.isBelow(storedBytes[0]!.projection, 100_000); |
| 1588 | assert.isTrue(projectedLarge?.type === "file_change"); |
| 1589 | if (projectedLarge?.type !== "file_change") return; |
| 1590 | assert.equal(projectedLarge.fileName, "src/generated.ts"); |
| 1591 | assert.isBelow(projectedLarge.diffStr?.length ?? 0, 40_000); |
| 1592 | assert.isTrue(largeDiff.startsWith(projectedLarge.diffStr?.split("\n…")[0] ?? "-")); |
| 1593 | assert.deepEqual(projectedSmall, small); |
| 1594 | }), |
| 1595 | ); |
| 1596 | |
| 1517 | 1597 | it.effect("routes provider-owned child artifacts to their child app thread", () => |
| 1518 | 1598 | Effect.gen(function* () { |
| 1519 | 1599 | const now = yield* DateTime.now; |