Summary
formatValue (packages/harness/web/src/lib/extract-step-context.ts) is documented as producing output "capped at VALUE_CAP characters," but it sliced content to exactly VALUE_CAP and then appended a truncation marker AFTER the slice — so the total could exceed VALUE_CAP by the marker's length.
This is the fourth instance of the same bug class found in a repo-wide sweep; the other three (truncateForPayload/clip/clamp in packages/harness/src/core/) are fixed in #656. This one lives in a different subsystem (the web frontend's run-inspector Debug/Explain macro context builder), so it's a separate issue/PR.
Reproduction
// text.length = 5000, VALUE_CAP = 2000
formatValue(hugeValue).length // > 2000
Impact
Low: this feeds a debug-macro prompt context block (an LLM context budget with far more headroom than a couple dozen extra characters), not a storage or transport limit. But it contradicts the function's own documented cap.
Note: unlike the three instances in #656, this marker (\n… (truncated, N chars total)) reports the value's original total length rather than a dropped-char count, so its length doesn't depend on where the slice lands — the fix here is a single subtraction, not a converging loop.
Suggested fix
Reserve the marker's (fixed) length within VALUE_CAP before slicing. I have a fix ready with an updated test. Happy to open a PR.
Summary
formatValue(packages/harness/web/src/lib/extract-step-context.ts) is documented as producing output "capped at VALUE_CAP characters," but it sliced content to exactlyVALUE_CAPand then appended a truncation marker AFTER the slice — so the total could exceedVALUE_CAPby the marker's length.This is the fourth instance of the same bug class found in a repo-wide sweep; the other three (
truncateForPayload/clip/clampinpackages/harness/src/core/) are fixed in #656. This one lives in a different subsystem (the web frontend's run-inspector Debug/Explain macro context builder), so it's a separate issue/PR.Reproduction
Impact
Low: this feeds a debug-macro prompt context block (an LLM context budget with far more headroom than a couple dozen extra characters), not a storage or transport limit. But it contradicts the function's own documented cap.
Note: unlike the three instances in #656, this marker (
\n… (truncated, N chars total)) reports the value's original total length rather than a dropped-char count, so its length doesn't depend on where the slice lands — the fix here is a single subtraction, not a converging loop.Suggested fix
Reserve the marker's (fixed) length within
VALUE_CAPbefore slicing. I have a fix ready with an updated test. Happy to open a PR.