Skip to content

fix(engine): keep renderRepoMap's output within maxOutputChars including the marker (#9617) - #9633

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
RealDiligent:fix/critical-issue-repo-map-truncation-marker-9617
Jul 29, 2026
Merged

fix(engine): keep renderRepoMap's output within maxOutputChars including the marker (#9617)#9633
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
RealDiligent:fix/critical-issue-repo-map-truncation-marker-9617

Conversation

@RealDiligent

Copy link
Copy Markdown
Contributor

Problem

Closes #9617.

renderRepoMap (packages/loopover-engine/src/miner/repo-map.ts) budgets content lines via pushLine but appended the truncation marker unbudgeted (lines.push(...)), so a truncated result overshot maxOutputChars by up to the marker's length + a newline, and a first line over budget returned only an over-budget marker. maxOutputChars is a token-budget guarantee the prompt packet relies on.

Fix

Reserve the marker from the budget (extracted to a TRUNCATION_MARKER const):

  • Not truncated → return the join unchanged (byte-for-byte identical, no reserved headroom).
  • Truncated → drop trailing content lines until the marker (plus its joining newline while content remains) fits, then append it — so result.length <= maxOutputChars always.
  • maxOutputChars < the marker length → return the empty string, never an over-budget marker.

Tests

  • test/unit/repo-map.test.ts (root vitest): tightened the truncation test to the strict <= maxOutputChars bound; added budget-spread + empty-string + marker-only cases; updated the four break-site tests to the new contract.
  • packages/loopover-engine/test/repo-map.test.ts (engine node:test): mirrors the budget contract so the engine Codecov flag credits the changed lines, complete + truncated + empty-string + marker-only + keep-fitting-symbol cases.

100% line + branch coverage on the changed source.

@RealDiligent
RealDiligent requested a review from JSONbored as a code owner July 29, 2026 02:01
@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-29 02:23:31 UTC

3 files · 1 AI reviewer · no blockers · CI green · clean

⏸️ Suggested Action - Manual Review

Review summary
This fix correctly reserves the TRUNCATION_MARKER's length (plus joining newline while content remains) from the output budget, replacing the old unbudgeted `lines.push(marker)` at repo-map.ts:384 (pre-change) that could overshoot maxOutputChars by the marker's length + newline. I traced the new pop-loop's length bookkeeping (repo-map.ts:392-396) against pushLine's original addedLength accounting and it correctly mirrors it in reverse, and the maxOutputChars < TRUNCATION_MARKER.length early return correctly avoids an over-budget marker-only string. Both the root vitest suite and the engine node:test suite exercise the empty-string, marker-only, budget-spread, and content-retention branches with real (non-fabricated) inputs.

Nits — 4 non-blocking
  • packages/loopover-engine/test/repo-map.test.ts:9 and test/unit/repo-map.test.ts:480 both hardcode a local `MARKER`/`marker` string literal instead of importing/asserting against the exported `TRUNCATION_MARKER` constant, so the two would silently diverge if the marker text ever changes.
  • The while-loop condition at repo-map.ts:393 (`length + TRUNCATION_MARKER.length + 1 > maxOutputChars`) always adds `+1` for the joining newline even on the iteration that would empty `lines`, but this is harmless since the `lines.length === 0` exit path supersedes it — worth a one-line comment noting that's intentional, since it reads like an off-by-one at first glance.
  • Export or reuse TRUNCATION_MARKER in both test files rather than duplicating the literal string, per the nit above.
  • Consider a short comment at the while-loop's `+1` check clarifying it's conservative for the content-remains case and irrelevant once lines empties, to preempt future confusion.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9617
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ❌ 5/25 Preflight is holding this PR: the review lane is unavailable, so it is not ready for automated review.
Contributor workload ✅ 10/10 Author activity: 266 registered-repo PR(s), 111 merged, 37 issue(s).
Contributor context ✅ Confirmed Gittensor contributor RealDiligent; Gittensor profile; 266 PR(s), 37 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff reserves the marker's length (plus joining newline) from the budget before appending it, returns the unchanged content when nothing was truncated, and returns "" when maxOutputChars is smaller than the marker — directly fixing the overshoot described in the issue while keeping pushLine/outer loop and line formats intact. New tests in both the engine and root suites assert length<=budget a

Review context
  • Author: RealDiligent
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is registered but has no active allocation in the current snapshot.
  • Public profile languages: Python, Ruby, TypeScript, Svelte, Cuda, JavaScript, Markdown, MDX
  • Official Gittensor activity: 266 PR(s), 37 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Await review-lane availability.
  • Then work through the remaining 1 step in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (a402b9f) to head (9a3b871).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9633      +/-   ##
==========================================
+ Coverage   90.12%   90.13%   +0.01%     
==========================================
  Files         891      891              
  Lines      112306   112323      +17     
  Branches    26629    26639      +10     
==========================================
+ Hits       101216   101246      +30     
+ Misses       9760     9743      -17     
- Partials     1330     1334       +4     
Flag Coverage Δ
backend 95.51% <100.00%> (-0.01%) ⬇️
engine 67.26% <100.00%> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-engine/src/miner/repo-map.ts 72.25% <100.00%> (+5.67%) ⬆️

... and 1 file with indirect coverage changes

…ing the marker

renderRepoMap's pushLine budgets every content line against maxOutputChars,
but the truncation marker was appended via lines.push unbudgeted — so a
truncated result overshot by up to the marker's length plus a newline, and in
the degenerate case returned a marker longer than the budget with no content.
maxOutputChars is a token-budget guarantee the prompt builder relies on.

Reserve the marker (plus its joining newline) from the budget: on truncation,
drop trailing content lines until the marker fits, and when the budget can't
hold even the marker alone, return the empty string rather than an over-budget
marker. A complete (non-truncated) render is byte-for-byte unchanged.
@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 29, 2026

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit d997bac into JSONbored:main Jul 29, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

engine(repo-map): renderRepoMap's truncation marker is appended outside its own char budget

1 participant