fix: P1 correctness and operational fixes from FAR-104/FAR-105 analysis

5. Cap log stream reconnect attempts at 50 — prevents infinite
   reconnect loops during sustained API partitions.

6. Fire keepalive refresh earlier — tick 1 + every 12 ticks (~3min)
   instead of every 16 ticks (~4min), providing better safety margin
   under the 5-minute reaper window.

7. Catch rejections from onLog inside keepalive — add .catch(() => {})
   to prevent unhandledRejection on SSE backpressure.

8. Prevent sanitized-name collisions — extend slugs to 16 chars each,
   add a 6-char SHA-256 hash suffix, shorten prefix to `ac-` to stay
   well within the 63-char DNS label limit.

10. Fix config-hint parity for nodeSelector and labels — parse both
    `key=value` multiline text and JSON objects, matching what the
    textarea hint promises.

11. Large-prompt fallback via Secret — prompts >256 KiB are staged as a
    K8s Secret and mounted as a volume instead of passed via env var,
    protecting against the ~1 MiB PodSpec limit.

13. Track last-seen log timestamp on reconnect — anchor sinceSeconds at
    the last received log line instead of stream start, fixing FAR-105
    duplicative logs. Belt-and-braces: dedupe assistantTexts at the
    parser boundary in parse.ts.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Test User
2026-04-20 19:05:07 +00:00
parent d74b6d34b3
commit 1e517bb9bb
5 changed files with 331 additions and 49 deletions
+13
View File
@@ -141,6 +141,19 @@ more raw output`;
expect(result.summary).toContain("JSON output");
expect(result.summary).not.toContain("some raw output");
});
it("deduplicates identical assistant text blocks from reconnect replays", () => {
const assistantEvent = JSON.stringify({
type: "assistant",
message: { content: [{ type: "text", text: "Hello world" }] },
});
// Simulate the same assistant event appearing twice (log stream reconnect replay)
const stdout = `${assistantEvent}\n${assistantEvent}\n`;
const result = parseClaudeStreamJson(stdout);
expect(result.summary).toBe("Hello world");
// Should not be "Hello world\n\nHello world"
expect(result.summary.split("Hello world").length).toBe(2);
});
});
describe("extractClaudeLoginUrl", () => {