fix(runner): align editable draft bounds with Unicode schema lengths

Count initialText Unicode code points consistently in TypeScript, Zod, JSON Schema and Rust. Keep submitted-answer UTF-16 limits unchanged, with mixed BMP and astral boundary tests inside the wire byte cap.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-29 12:39:25 -05:00
1 parent c2b0c804cb
commit 4f9506072c
13 files changed
+68 -15

No files matched your search

+8 -1
View File
@@ -643,8 +643,15 @@ describe("persisted canonical question initial text", () => {
expect(paperclipQuestionSetPayloadSchema.parse(input({ initialText }))).toEqual(input({ initialText }));
}
});
it("counts mixed BMP and astral draft text like JSON Schema", () => {
for (const codePoints of [100_000, 100_001]) {
const initialText = "a".repeat(codePoints - 1) + "😀";
expect(Buffer.byteLength(JSON.stringify(input({ initialText })))).toBeLessThan(196 * 1024);
expect(paperclipQuestionSetPayloadSchema.safeParse(input({ initialText })).success).toBe(codePoints === 100_000);
}
});
it("rejects non-text modes and unbounded or nonstring defaults", () => {
for (const initialText of [null, 1, "x".repeat(100_001), "😀".repeat(50_001)]) {
for (const initialText of [null, 1, "x".repeat(100_001), "a".repeat(100_000) + "😀"]) {
expect(paperclipQuestionSetPayloadSchema.safeParse(input({ initialText })).success).toBe(false);
}
expect(paperclipQuestionSetPayloadSchema.safeParse(input({ answerMode: "single_select", options: [{ id: "a", label: "A" }], initialText: "a" })).success).toBe(false);
+1 -1
View File
@@ -1251,7 +1251,7 @@ const paperclipQuestionSchema = z
helpText: z.string().max(4000).optional(),
required: z.boolean(),
answerMode: z.enum(["single_select", "multi_select", "text"]),
initialText: z.string().max(100000).optional(),
initialText: z.string().refine(value => value.length <= 200000 && Array.from(value).length <= 100000, "initial text exceeds 100000 Unicode code points").optional(),
options: z.array(paperclipQuestionOptionSchema).max(128).optional(),
customAnswer: z
.object({