fix(DIS-105): prevent fence closure from pushing chunks beyond 2000-char hard limit
Some checks failed
CI / build-and-test (ubuntu-latest) (pull_request) Has been cancelled
CI / build-and-test (windows-latest) (pull_request) Has been cancelled
CI / lint (pull_request) Has been cancelled

The flush() helper now enforces the Discord hard limit by hard-splitting
any chunk that exceeds 2000 chars (e.g. when "\n```" was appended after
the soft-limit check). Also reserves 4 chars of overhead in the
soft-limit check when inside a fenced code block.

Adds a regression test that verifies no chunk exceeds 2000 chars even
when the fence closure is appended at the limit boundary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Tabeling 2026-04-10 10:13:58 +02:00
parent a85217f753
commit 62ea507974
2 changed files with 26 additions and 1 deletions

View file

@ -28,6 +28,12 @@ export function splitForDiscord(text: string, limit = 1900): string[] {
let fenceLang = ""; let fenceLang = "";
const flush = () => { const flush = () => {
// Hard-split if current exceeds the Discord hard limit (e.g. because
// a fence closure "\n```" was appended after the soft-limit check).
while (current.length > DISCORD_HARD_LIMIT) {
chunks.push(current.slice(0, DISCORD_HARD_LIMIT));
current = current.slice(DISCORD_HARD_LIMIT);
}
if (current.length > 0) { if (current.length > 0) {
chunks.push(current); chunks.push(current);
current = ""; current = "";
@ -43,7 +49,10 @@ export function splitForDiscord(text: string, limit = 1900): string[] {
const separator = current.length > 0 ? "\n" : ""; const separator = current.length > 0 ? "\n" : "";
const addition = separator + line; const addition = separator + line;
if (current.length + addition.length > effectiveLimit) { // Reserve space for a closing fence (``` + newline) when inside a code block
const fenceOverhead = inFence ? 4 : 0; // "\n```".length
if (current.length + addition.length + fenceOverhead > effectiveLimit) {
// Need to flush before adding this line // Need to flush before adding this line
if (inFence) { if (inFence) {
// Close the open fence before flushing // Close the open fence before flushing

View file

@ -101,4 +101,20 @@ describe("splitForDiscord", () => {
const idx = result.indexOf(closingChunk!); const idx = result.indexOf(closingChunk!);
expect(result[idx + 1]).toMatch(/^```python/); expect(result[idx + 1]).toMatch(/^```python/);
}); });
// Regression: fence closure "\n```" must not push a chunk beyond the 2000 hard limit
it("does not exceed 2000 chars even when fence closure is appended at limit boundary", () => {
const fenceOpen = "```typescript\n";
// Line long enough that current is near 2000 when fence closure is added
const longLine = "x".repeat(1984);
const nextLine = "y".repeat(10);
const fenceClose = "\n```";
const text = fenceOpen + longLine + "\n" + nextLine + fenceClose;
const result = splitForDiscord(text, 2000);
for (const chunk of result) {
expect(chunk.length).toBeLessThanOrEqual(DISCORD_HARD_LIMIT);
}
});
}); });