[WRONG BRANCH] fix(routing): bound reasoning effort hydration - #34
Conversation
⏳ DRAFT
What to do
Its title has been prefixed with |
|
✅ Deterministic PR hygiene checks passed. |
📝 WalkthroughWalkthrough
ChangesReasoning Effort Normalization
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/routing/trace.ts`:
- Around line 468-475: Update the reasoningEfforts normalization in the trace
parsing flow to reject sparse arrays within the retained first eight entries,
rather than relying on every() and map() which skip and preserve holes. Use an
indexed validation loop or densify the slice before the existing string checks,
and add a regression test covering a sparse reasoningEfforts array.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: edb71c19-c108-455c-9cb6-c96c5f7fbfd2
📒 Files selected for processing (2)
src/routing/trace.tstests/route-decision-trace.test.ts
| const reasoningEfforts = Array.isArray(raw.reasoningEfforts) | ||
| ? raw.reasoningEfforts.slice(0, 8) | ||
| : undefined; | ||
| if (reasoningEfforts | ||
| && reasoningEfforts.every((value): value is string => typeof value === "string")) { | ||
| if (reasoningEfforts.some((value: unknown) => typeof value === "string" | ||
| && value.length > MAX_TRACE_STRING)) caps.strings = true; | ||
| out.reasoningEfforts = raw.reasoningEfforts | ||
| .slice(0, 8) | ||
| .map(value => value.slice(0, MAX_TRACE_STRING)); | ||
| out.reasoningEfforts = reasoningEfforts.map(value => value.slice(0, MAX_TRACE_STRING)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
bun -e '
const sparse = new Array(8);
const mapped = sparse.map(value => value);
if (!sparse.every(value => typeof value === "string")) {
throw new Error("every() did not skip sparse holes");
}
if (0 in mapped) {
throw new Error("map() did not preserve sparse holes");
}
'Repository: luvs01/opencodex
Length of output: 195
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- target file ---'
sed -n '430,500p' src/routing/trace.ts
printf '%s\n' '--- declarations and consumers ---'
rg -n -C 3 'reasoningEfforts|MAX_TRACE_STRING' src test tests 2>/dev/null || true
printf '%s\n' '--- runtime sparse-array semantics ---'
node - <<'JS'
const sparse = new Array(8);
const sliced = sparse.slice(0, 8);
const mapped = sliced.map(value => value);
const densified = Array.from(sliced);
console.log(JSON.stringify({
every: sliced.every(value => typeof value === "string"),
mappedHasIndex0: 0 in mapped,
densifiedHasIndex0: 0 in densified,
densifiedEvery: densified.every(value => typeof value === "string"),
}));
JSRepository: luvs01/opencodex
Length of output: 50372
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- exact parser context ---'
sed -n '1,80p' src/routing/trace.ts
sed -n '455,485p' src/routing/trace.ts
printf '%s\n' '--- trace-related tests and parser callers ---'
rg -n -C 4 'parseCapability|reasoningEfforts|trace' tests src/routing/trace.ts \
-g '*trace*' -g '*routing*' -g '*.test.ts' | head -n 240
printf '%s\n' '--- standalone sparse-array probe ---'
node - <<'JS'
const sparse = new Array(8);
const sliced = sparse.slice(0, 8);
const mapped = sliced.map(value => value);
const densified = Array.from(sliced);
console.log({
everyAcceptsSparse: sliced.every(value => typeof value === "string"),
mappedHasIndex0: 0 in mapped,
densifiedHasIndex0: 0 in densified,
densifiedEveryAccepts: densified.every(value => typeof value === "string"),
});
JSRepository: luvs01/opencodex
Length of output: 21731
Reject sparse retained arrays before normalization.
At src/routing/trace.ts:468-475, every() skips holes and map() preserves them. A sparse array in the retained first eight entries therefore passes validation and remains a sparse string[]. Reject the holes with an indexed loop or densify the slice before validation. Add a sparse-array regression test.
Proposed localized fix
const reasoningEfforts = Array.isArray(raw.reasoningEfforts)
- ? raw.reasoningEfforts.slice(0, 8)
+ ? Array.from(raw.reasoningEfforts.slice(0, 8))
: undefined;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const reasoningEfforts = Array.isArray(raw.reasoningEfforts) | |
| ? raw.reasoningEfforts.slice(0, 8) | |
| : undefined; | |
| if (reasoningEfforts | |
| && reasoningEfforts.every((value): value is string => typeof value === "string")) { | |
| if (reasoningEfforts.some((value: unknown) => typeof value === "string" | |
| && value.length > MAX_TRACE_STRING)) caps.strings = true; | |
| out.reasoningEfforts = raw.reasoningEfforts | |
| .slice(0, 8) | |
| .map(value => value.slice(0, MAX_TRACE_STRING)); | |
| out.reasoningEfforts = reasoningEfforts.map(value => value.slice(0, MAX_TRACE_STRING)); | |
| const reasoningEfforts = Array.isArray(raw.reasoningEfforts) | |
| ? Array.from(raw.reasoningEfforts.slice(0, 8)) | |
| : undefined; | |
| if (reasoningEfforts | |
| && reasoningEfforts.every((value): value is string => typeof value === "string")) { | |
| if (reasoningEfforts.some((value: unknown) => typeof value === "string" | |
| && value.length > MAX_TRACE_STRING)) caps.strings = true; | |
| out.reasoningEfforts = reasoningEfforts.map(value => value.slice(0, MAX_TRACE_STRING)); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/routing/trace.ts` around lines 468 - 475, Update the reasoningEfforts
normalization in the trace parsing flow to reject sparse arrays within the
retained first eight entries, rather than relying on every() and map() which
skip and preserve holes. Use an indexed validation loop or densify the slice
before the existing string checks, and add a regression test covering a sparse
reasoningEfforts array.
Motivation
parseCapabilityvalidated onlyraw.reasoningEfforts.slice(0, 8)but then ransome()and slicing on the originalraw.reasoningEfforts, allowing a malicious/Corrupt persisted row to force an unbounded scan and CPU exhaustion.Description
src/routing/trace.tsparseCapabilitynow readsraw.reasoningEffortsonce into a localreasoningEffortsslice (.slice(0, 8)) and performs validation, length checks, and normalization only on that slice.reasoningEffortsnow run against the retained slice socaps.stringsis set correctly without scanning the original array.tests/route-decision-trace.test.tsthat constructs a very largereasoningEffortsarray with a throwing accessor outside the retained range to assert that normalization does not inspect discarded entries.Testing
bun run typecheckand it completed successfully.bun run privacy:scanand it completed successfully.git diff --check) and the diff is clean.bun scripts/test.ts tests/route-decision-trace.test.ts), but execution failed in this environment due to a runtime mismatch (node:zlibexportzstdDecompressSyncnot available in the installed Bun version); the new regression test is included in the tree and is expected to run in CI (which uses the pinned Bun runtime).Summary by CodeRabbit
Bug Fixes
Tests