import { describe, expect, it } from "bun:test"; import { type InstanceFeedbackInput, instanceFeedbackCaptureTransportSchema, instanceFeedbackInputSchema, } from "./instance-feedback-input"; type CategorizedFeedbackInput = Extract< InstanceFeedbackInput, { category: string } >; type FeedbackReasons = NonNullable; describe("instanceFeedbackCaptureTransportSchema", () => { it("carries bounded declared identity context outside the feedback fact", () => { expect( instanceFeedbackCaptureTransportSchema.safeParse({ context: { identities: [ { type: "anonymousId", value: "anon_1" }, { type: "externalId.users.none.crm-contact", value: "contact_1", }, ], }, feedback: { category: "helpfulness", value: true }, }).success, ).toBe(true); expect( instanceFeedbackCaptureTransportSchema.safeParse({ context: { identities: [{ type: "admin", value: "user_1" }] }, feedback: { category: "helpfulness", value: true }, }).success, ).toBe(false); }); }); describe("instanceFeedbackInputSchema", () => { it("enforces the aggregate serialized transport limit", () => { expect( instanceFeedbackInputSchema.safeParse({ comment: "x".repeat(64 * 1024) }) .success, ).toBe(false); expect( instanceFeedbackInputSchema.safeParse({ comment: "x".repeat(60 * 1024) }) .success, ).toBe(true); }); it("accepts app-level comment feedback without a target", () => { expect( instanceFeedbackInputSchema.safeParse({ comment: "Please support SSO.", }).success, ).toBe(true); }); it("accepts category-only marker feedback", () => { expect( instanceFeedbackInputSchema.safeParse({ category: "bug_report", }).success, ).toBe(true); }); it("accepts a typed value with target, graph, and external references", () => { const result = instanceFeedbackInputSchema.safeParse({ category: "helpfulness", comment: "The installation command is outdated.", properties: { placement: "message-actions" }, reasons: ["outdated"], related: [ { role: "conversation", subject: { collection: "conversation", id: "conversation-123", }, }, ], target: { collection: "docs-page", id: "https://docs.example.com/getting-started", properties: { framework: "react", version: 2 }, references: { "langfuse-primary": { observationId: "observation-123", traceId: "trace-123", }, }, }, value: false, }); expect(result.success).toBe(true); }); it.each([ true, 5, "very_helpful", ])("accepts supported scalar value %p", (value) => { expect( instanceFeedbackInputSchema.safeParse({ category: "quality", value, }).success, ).toBe(true); }); it("preserves accepted comments and string values verbatim", () => { const input = { category: "quality", comment: " Preserve this formatting. ", value: " customer-defined value ", }; const result = instanceFeedbackInputSchema.parse(input); expect(result).toEqual(input); }); it("exposes reasons as a non-empty tuple", () => { const reasons: FeedbackReasons = ["outdated"]; // @ts-expect-error Empty reasons must not satisfy the inferred contract. const emptyReasons: FeedbackReasons = []; expect(reasons).toEqual(["outdated"]); void emptyReasons; }); it.each([ {}, { properties: { placement: "footer" } }, { value: true }, { reasons: ["outdated"] }, { comment: "", value: false }, { comment: "Old payload must not degrade to comment-only feedback.", scoreValue: 1, valence: "positive", }, ])("rejects payloads without feedback semantics: %o", (input) => { expect(instanceFeedbackInputSchema.safeParse(input).success).toBe(false); }); it.each([ { category: "", value: true }, { category: " helpful ", value: true }, { category: "helpfulness", value: Number.POSITIVE_INFINITY }, { category: "helpfulness", value: null }, { category: "helpfulness", value: "" }, { category: "helpfulness", reasons: [] }, { category: "helpfulness", reasons: [" outdated "] }, ])("rejects invalid category content: %o", (input) => { expect(instanceFeedbackInputSchema.safeParse(input).success).toBe(false); }); it.each([ { category: "helpfulness", target: { collection: "Docs Page", id: "page-1" }, }, { category: "helpfulness", target: { collection: "docs-page", id: " page-1 " }, }, { category: "helpfulness", related: [ { role: "Viewed As", subject: { collection: "account", id: "account-1" }, }, ], }, ])("rejects invalid graph references: %o", (input) => { expect(instanceFeedbackInputSchema.safeParse(input).success).toBe(false); }); it("rejects reference keys that could collide after trimming", () => { expect( instanceFeedbackInputSchema.safeParse({ category: "helpfulness", target: { collection: "ai-response", id: "response-1", references: { " langfuse": { traceId: "trace-2" }, langfuse: { traceId: "trace-1" }, }, }, }).success, ).toBe(false); }); it("rejects prototype keys in the outer references map", () => { const references = JSON.parse( '{"__proto__": {"traceId": "trace-evil"}}', ) as Record; expect( instanceFeedbackInputSchema.safeParse({ category: "helpfulness", target: { collection: "ai-response", id: "response-1", references, }, }).success, ).toBe(false); }); it("rejects prototype keys before they can bypass nested JSON bounds", () => { const properties = JSON.parse('{"__proto__": {}}') as Record< string, unknown >; Object.defineProperty(properties, "__proto__", { configurable: true, enumerable: true, value: { text: "x".repeat(16 * 1024 + 1) }, writable: true, }); expect( instanceFeedbackInputSchema.safeParse({ category: "helpfulness", properties: { nested: properties }, }).success, ).toBe(false); }); it("returns a validation failure for oversized arrays", () => { const result = instanceFeedbackInputSchema.safeParse({ category: "helpfulness", properties: { values: Array.from({ length: 1_000_000 }, () => true), }, }); expect(result.success).toBe(false); }); it("bounds comments, reasons, references, and nested JSON", () => { const tooDeep: Record = {}; let cursor = tooDeep; for (let depth = 0; depth < 10; depth += 1) { const next: Record = {}; cursor.next = next; cursor = next; } const tooManyNodes = Object.fromEntries( Array.from({ length: 10 }, (_, groupIndex) => [ `group-${groupIndex}`, Object.fromEntries( Array.from({ length: 100 }, (_, valueIndex) => [ `value-${valueIndex}`, valueIndex, ]), ), ]), ); const invalidInputs = [ { comment: "x".repeat(64 * 1024 + 1) }, { category: "helpfulness", reasons: Array.from({ length: 21 }, (_, index) => `reason-${index}`), }, { category: "helpfulness", properties: { text: "x".repeat(16 * 1024 + 1) }, }, { category: "helpfulness", properties: { ["k".repeat(256)]: true }, }, { category: "helpfulness", properties: { values: Array.from({ length: 101 }, () => true) }, }, { category: "helpfulness", properties: tooDeep }, { category: "helpfulness", properties: tooManyNodes }, { category: "helpfulness", target: { collection: "ai-response", id: "response-1", references: Object.fromEntries( Array.from({ length: 21 }, (_, index) => [ `destination-${index}`, { id: index }, ]), ), }, }, ]; for (const input of invalidInputs) { expect(instanceFeedbackInputSchema.safeParse(input).success).toBe(false); } }); });