## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - The issue detail page displays comment threads with rich timeline
rendering
> - Long threads (100+ items) cause severe typing lag in the comment
composer because every keystroke re-renders the entire timeline
> - CDP tracing confirmed 110ms avg key→paint latency and 60 long tasks
blocking the main thread for 3.7s total
> - This pull request memoizes the timeline, stabilizes callback props,
debounces editor observers, and reduces idle polling frequency
> - The benefit is responsive typing (21ms avg, 5.3× faster) even on
threads with 100+ timeline items
## What Changed
- **CommentThread.tsx**: Memoize `TimelineList` with `useMemo` so typing
state changes don't re-render 143 timeline items; extract
`handleFeedbackVote` to `useCallback`; added missing deps
(`pendingApprovalAction`, `onApproveApproval`, `onRejectApproval`) to
useMemo array
- **IssueDetail.tsx**: Extract inline callbacks (`handleCommentAdd`,
`handleCommentVote`, `handleCommentImageUpload`,
`handleCommentAttachImage`, `handleInterruptQueued`) to `useCallback`
with `.mutateAsync` deps (not full mutation objects) for stable
references; add conditional polling intervals (3s active / 30s idle) for
`liveRuns`, `activeRun`, `linkedRuns`, and timeline queries
- **MarkdownEditor.tsx**: Debounce `MutationObserver` and
`selectionchange` handlers via `requestAnimationFrame` coalescing
- **LiveRunWidget.tsx**: Accept optional `liveRunsData` and
`activeRunData` props to reuse parent-fetched data instead of duplicate
polling
## Verification
- Navigated to [IP address]:3105/PAPA/issues/PAPA-32 (thread with 100+
items)
- Typed in comment composer — lag eliminated, characters appear
instantly
- CDP trace test script (`test-typing-lag.mjs`) confirmed: avg 21ms
key→paint (was 110ms), 5 long tasks (was 60), 0.5s blocking (was 3.7s)
- Ran `pnpm test:run` locally — all tests pass
## Risks
- Low risk. All changes are additive memoization and callback
stabilization — no behavioral changes. Polling intervals are only
reduced for idle state; active runs still poll at 3–5s.
## Model Used
- Claude Opus 4.6 (`claude-opus-4-6`) via Claude Code CLI, with tool use
and extended context
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
- backup-lib: delete uncompressed .sql file in catch block when gzip
compression fails, preventing silent disk usage accumulation
- server: replace stale retentionDays scalar with retentionSource in
startup log since retention is now read from DB on each backup tick
Replace single retentionDays with a three-tier BackupRetentionPolicy:
- Daily: keep all backups (presets: 3, 7, 14 days; default 7)
- Weekly: keep one per calendar week (presets: 1, 2, 4 weeks; default 4)
- Monthly: keep one per calendar month (presets: 1, 3, 6 months; default 1)
Pruning sorts backups newest-first and applies each tier's cutoff,
keeping only the newest entry per ISO week/month bucket. The Instance
Settings General page now shows three preset selectors (no icon, matches
existing page design). Remove Database icon import.
Compress database backups with gzip (.sql.gz), reducing file size ~83%.
Add backup retention configuration to Instance Settings UI with preset
options (7 days, 2 weeks, 1 month). The backup scheduler now reads
retention from the database on each tick so changes take effect without
restart. Default retention changed from 30 to 7 days.
On resumed sessions, skipping --append-system-prompt-file (the original
fix) left two secondary issues:
- commandNotes still claimed the flag was injected, producing misleading
onMeta logs on every resumed heartbeat
- The instructions file was still read from disk and a combined temp file
written on every resume, even though effectiveInstructionsFilePath was
never consumed
Hoist canResumeSession before the I/O block and gate both the disk
operations and commandNotes construction on !canResumeSession / !sessionId.
Adds three regression tests: commandNotes is populated on fresh sessions,
empty on resume; and no agent-instructions.md is written on resume.
On resumed sessions the agent instructions are already present in the
session cache. Unconditionally passing --append-system-prompt-file
re-injects 5-10K redundant tokens per heartbeat and may be rejected by
the Claude CLI when combined with --resume.
Guard the flag behind `!resumeSessionId` so it is only appended on
fresh session starts.
Fixes: #2848
Previously, --model was completely skipped for Bedrock users, so the
model dropdown selection was silently ignored and the CLI always used
its default model. Selecting Haiku would still run Opus.
- Add listClaudeModels() that returns Bedrock-native model IDs
(us.anthropic.*) when Bedrock env is detected
- Register listModels on claude_local adapter so the UI dropdown
shows Bedrock models instead of Anthropic API names
- Allow --model to pass through when the ID is a Bedrock-native
identifier (us.anthropic.* or ARN)
- Add isBedrockModelId() helper shared by execute.ts and test.ts
Follows up on #2793 which added basic Bedrock auth detection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Set server.keepAliveTimeout to 185s to safely outlive default Traefik/AWS ALB idle timeouts (typically 60-180s)
- Resolves random "Failed to fetch" edge cases caused by Node.js's notoriously short 5s default timeout
Closes#3008