# PRR Documentation Index Welcome to the PRR documentation! This directory contains comprehensive guides and flowcharts explaining how the PR Resolver system works. We document **why** design choices were made (not just what) so you can revisit decisions and avoid regressions β€” see also the main [README](../README.md) philosophy. --- ## πŸ“š Documentation Structure ### 🎯 [Quick Reference Guide](../tools/prr/QUICK_REFERENCE.md) **Best for**: Getting started quickly or looking up common patterns **Contains**: - One-page workflow overview - Visual system diagram - Common use cases - Configuration tips - Troubleshooting guide - Success metrics explained **Read this if**: You want to understand PRR at a glance or need quick answers. --- ### πŸ”„ [Flowchart Documentation](../tools/prr/flowchart.md) **Best for**: Understanding the detailed workflow and control flow **Contains**: - Main system flow (entry to exit) - Orchestrator outer loop (push iterations) - Push iteration inner loop (fix cycles) - Fix iteration details (single attempt) - Escalation strategy (when fixes fail) - State management visualization - LLM usage points - Error recovery flows - Tool integration architecture - Performance optimizations explained **Read this if**: You want to understand the step-by-step execution flow and decision points. --- ### πŸ’¬ [Thread replies (GitHub feedback)](THREAD-REPLIES.md) **Best for**: Enabling and understanding PRR’s replies on GitHub review threads **Contains**: - What thread replies do (fixed vs dismissed, reply-eligible categories) and why they are opt-in - Why one reply per thread, why fixed vs dismissed timing, why only some dismissal categories get a reply - In-run and cross-run idempotency, batch idempotency check, use of databaseId and skip of ic-* threads - Configuration: `--reply-to-threads`, `--resolve-threads`, `PRR_BOT_LOGIN` **Read this if**: You use or maintain `--reply-to-threads` or need the WHYs for design/audit. --- ### πŸ’Š Pill (Program Improvement Log Looker) **Best for**: Auditing a project from its output.log and prompts.log, integrated with prr/story **Contains**: - What pill does (analysis-only, no fix/verify/commit) and why - How prr/story run pill on close (`enablePill`, orig console refs, double-init guard) - Log file names and prefix (prr vs story vs pill), CLI options, output files - Architecture (cli, config, context, orchestrator, prompts) **Read this if**: You run pill standalone or use pill integration from prr/story. Full doc: **[tools/pill/README.md](../tools/pill/README.md)**. Context assembly (large logs, 504 avoidance, PILL_OUTPUT_LOG_MAX_CHARS) and shared story-read: **[shared/README.md](../shared/README.md)**. --- ### πŸ“‰ Audit Improvements Token-saving, exit-logic, and fix-loop improvements are documented in the [CHANGELOG](../CHANGELOG.md) under "Audit improvements" and "Output.log audit" headings. **Conservative verification for lifecycle/cache/leak issues (2026-03)**: - Lifecycle comments now receive broader symbol-lifecycle verification context rather than a tiny line-anchored snippet, and they are verified with the stronger lane when available. - The risky "pattern absent after N rejections" auto-pass is disabled for these issues. - **WHY**: Cleanup and leak bugs often live in distant creation/replacement/cleanup paths. A local snippet can look correct while the real leak still exists elsewhere in the file. PRR now prefers leaving those issues open over claiming a premature fix. **Output.log audit follow-up (2026-02)** β€” rebase detection, push retry, non-interactive rebase: - **Rebase detection**: `completeMerge` and the pull conflict loop use `--show-toplevel` to get the repo root so `.git/rebase-merge` is checked with an absolute path. **WHY**: Relative `.git` was resolved against process cwd, not the PRR workdir, so we often ran `commit` during a rebase and left `.git/rebase-merge` behind. - **Push retry cleanup**: On failed fetch+rebase after push rejection, we try `rebase --abort` first, then `cleanupGitState` only if abort fails. **WHY**: Abort keeps commits; full cleanup is for stale state so the next run doesn’t hit "rebase-merge directory already exists". - **Non-interactive rebase continue**: All `rebase --continue` calls go through `continueRebase(git)` in `git-merge.ts`, which sets `GIT_EDITOR=true` before running rebase. **WHY**: In headless/workdir there’s no TTY; the configured editor fails ("Standard input is not a terminal" / "problem with the editor 'editor'"). One helper keeps behavior consistent. - **Dead code**: Removed unused `src/git/clone.ts`; clone/merge logic lives in `git-clone-core`, `git-merge`, and `git-lock-files` (see CHANGELOG "Fixed β€” Rebase detection, push retry cleanup"). **Output.log audit (2026-02)** β€” model and prompt behavior: - **Model rotation & skip list**: Default llm-api/elizacloud lists ordered by fix success; models that 500/timeout or have 0% fix rate are in `ELIZACLOUD_SKIP_MODELS` and never selected. **WHY**: Reduces wasted rotation slots and improves throughput. - **File injection**: Inject files by issue count (most first) and tie injection budget to model context cap. **WHY**: Better S/R success when cap is tight; avoids overshooting small-context or underusing large-context models. - **Rewrite escalation**: Escalate to full-file rewrite for files not injected (LLM never saw content) or with repeated S/R failures. **WHY**: Avoids S/R matching failures when the model has no file content to copy from. - **Duplicate prompt hash**: Use issue IDs + lesson count instead of full prompt so same-issues-same-context skips to rotation. **WHY**: Full-prompt hash rarely matched; avoids redundant LLM calls. - **Proportional batch reduce**: Reduce batch by `cap/promptLength` instead of halving. **WHY**: Converges in 1–2 iterations instead of many. - **504 retries**: Two retries with 10s/20s backoff. **WHY**: Transient gateways get a chance to recover. - **AAR exhausted list**: List `path:line` for all exhausted issues in the After-Action Report. **WHY**: Makes human follow-up actionable. **Prompts.log audit (2026-02)** β€” conflict prompt size and large-file embedding: - **Skip file injection for conflict prompts**: In `injectFileContents` (llm-api), prompts starting with `MERGE CONFLICT RESOLUTION` are returned unchanged (no file injection). **WHY**: The conflict prompt builder already embeds each file; re-injecting would duplicate content (e.g. CHANGELOG twice), causing 140k+ char prompts and 504s. - **Chunked embed for large conflicted files**: For files over 30k chars with conflict markers, only conflict sections (with 7 lines context) are embedded; section headers show the actual line range; instructions tell the LLM to use the plain file path in ``. **WHY**: Full-file embed doubled prompt size and caused 504s; sections are enough for correct search/replace blocks. - **Conflict model fallback and context cap**: When `getCurrentModel()` is undefined (e.g. setup phase), Attempt 2 falls back to `DEFAULT_ELIZACLOUD_MODEL` for ElizaCloud; "file too large" uses the effective model’s context limit. **WHY**: Avoids weak default (qwen-3-14b) that may 504; correct limit prevents wrongly skipping files that fit the actual model’s window. **Prompts.log audit follow-up (2026-02)** β€” relax file constraint, dismissal skip, judge rule, model recommendation: - **Relax file constraint**: When the fixer returns CANNOT_FIX/WRONG_LOCATION and mentions another file, we persist that path in `wrongFileAllowedPathsByCommentId` and merge it into `allowedPaths` on the next attempt so the fixer can edit the correct file. **WHY**: Audit showed 7 identical 33k-char prompts for one cross-file issue; persisting the other file avoids burning all models and can resolve the issue on retry. - **Skip dismissal LLM for already-fixed**: We no longer call the LLM to generate a Note for `already-fixed` issues; code/diff is self-documenting. **WHY**: 62% of dismissal LLM responses were EXISTING; skipping saves tokens. - **Judge rule**: Verification prompt now says "If the Current Code already implements what the review asks for, respond NO and cite the specific code." **WHY**: Reduces unnecessary ALREADY_FIXED fix attempts when the judge would otherwise say YES. - **Model recommendation wording**: Prompt asks "explain why these models in this order" instead of "brief reasoning". **WHY**: Models echoed "brief reasoning" literally; the new wording yields actionable explanation. **Prompts.log audit (2026-03) β€” grouping validation and predict-bots guard:** - **Dedup GROUP validation**: `issue-analysis.ts` now rejects an entire `GROUP:` line when any referenced comment index is outside `1..N` or when the canonical index is not listed in that group. **WHY**: One dedup response returned `GROUP: 2,5,7` for only three comments; partially applying malformed groups risks merging the wrong issues. - **Dedup prompt tightening**: The dedup prompt now explicitly says valid indices are only `1..N` for the current file and that the canonical index must be one of the listed indices. **WHY**: Tightening the prompt reduces malformed grouping responses before they hit the parser. - **Predict-bots changed-files guard**: `bot-prediction-llm.ts` skips the display-only predictor for tiny meta-only diffs and filters predictions to files that are actually in `changedFiles`. **WHY**: The predictor hallucinated `scripts/build-skills-docs.js` from a `.gitignore`-only diff; changed-file filtering keeps the UX output grounded in the commit being pushed. **Prompts.log audit (2026-02) β€” verifier before snippet, model rec skip, no-op skip verify, escalation delay, predict-bots skip:** - **Verifier "Code before fix"**: Batch verification prompt now includes a "Code before fix" section (removed lines from the diff) alongside "Current Code (AFTER)" so the verifier can compare before vs after. **WHY**: Verifier was only seeing post-fix code; with before snippet it can determine whether the issue was actually fixed and reduce false rejections (audit: one correct fix took 17 iterations due to verifier rejections). - **Skip model recommendation for fewer than 3 issues**: The separate model-recommendation LLM call runs only when there are 3+ unresolved issues; otherwise we use default rotation. **WHY**: Saves ~29s and tokens on simple runs. - **All-no-op = no changes**: When every fixer change block was a no-op (search === replace), we treat the iteration as "no changes" and skip verification (runner returns `noMeaningfulChanges`; workflow skips `handleNoChangesWithVerification` and goes to rotation). **WHY**: Avoids running the verifier on unchanged code and keeps "file modified" accurate. - **Delay full-file escalation for simple issues**: For files where all targeting issues have importance ≀ 3 and ease ≀ 2, we only escalate to full-file rewrite when the file was not injected (not when over S/R failure threshold). **WHY**: Full-file rewrites are expensive and time out more; for simple issues we rely on S/R first. - **Skip predict-bots when --no-wait-bot**: The LLM "likely new bot feedback" prediction is skipped when `--no-wait-bot` is set. **WHY**: Prediction is display-only and runs after commit; skipping saves ~26s when the user isn't waiting for bot reviews. **Fetch timeout and token auth (2026-03)** β€” conflict check and pull no longer hang: - **Fetch via spawn with 60s timeout**: Conflict check and remote-ahead check run `git fetch` via spawn; on timeout the error includes git stdout/stderr (e.g. password prompt). **WHY**: simple-git fetch could hang indefinitely; timeout + output make credential/network issues obvious. - **GitHub token for fetch/pull**: When `origin` is HTTPS with no credentials, we use a one-shot auth URL (same as push) so fetch and pull never prompt for password. **WHY**: Headless runs have no TTY; token from config unblocks setup and fix-loop sync. See [CHANGELOG](../CHANGELOG.md) "Added (2026-03) β€” Git fetch: timeout, stdout on timeout, GitHub token auth". **CLAUDE.md / sync target fix (2026-03)** β€” do not delete repo-owned files: - **Sync target state in setWorkdir**: `setWorkdir` in `tools/prr/state/lessons-context.ts` now uses `Detect.autoDetectSyncTargets(ctx)` so both `syncTargets` and `originalSyncTargetState` are set. **WHY**: A local helper previously only set `syncTargets`; cleanup uses `didSyncTargetExist(ctx, 'claude-md')` to decide whether to remove CLAUDE.md β€” with an empty `originalSyncTargetState` we always assumed we had created it and deleted it at end of run, nuking the repo's CLAUDE.md when the user never ran `--clean-claude-md`. - **Re-detect after clone**: In `tools/prr/workflow/run-setup-phase.ts`, after `cloneOrUpdateRepository()` we call `LessonsAPI.Detect.autoDetectSyncTargets(lessonsContext)` again. **WHY**: On first run the workdir is empty when we set workdir and detect; clone runs later and may check out CLAUDE.md. Without re-detection we would still record "didn't exist" and delete it at final cleanup. Re-running after clone ensures we only remove sync targets we actually created this run. **Output.log audit follow-up (2026-03)** β€” allowed paths, CodeRabbit meta, (PR comment): - **Runner allowed paths**: In `tools/prr/workflow/execute-fix-iteration.ts`, `allowedPathsForBatch` is built by expanding each issue with `getMigrationJournalPath`, `getConsolidateDuplicateTargetPath`, and `getImplPathForTestFileIssue` (same as prompt-builder). **WHY**: The prompt asked the fixer to edit e.g. `db/migrations/meta/_journal.json` for Drizzle migration issues, but the runner's allow-list used only `issue.allowedPaths`/`comment.path`, so journal edits were rejected as "disallowed file" and fixes never applied. - **CodeRabbit meta comments**: `isCodeRabbitMetaComment` in `tools/prr/github/api.ts` now matches `