fix(memory-b): keep non-enumerable recall diagnostics through budget slicing

This commit is contained in:
exec
2026-11-03 21:35:59 +08:00
parent 2069cd5f25
commit ca0b5ff813

View File

@ -811,6 +811,20 @@ export function segmentRecallBudget(hits, options = {}) {
const average = costs.reduce((sum, cost) => sum + cost, 0) / costs.length
const count = Math.max(1, Math.min(topK, Math.floor(budget / Math.max(1, average))))
const retained = rows.slice(0, count)
// ★ `slice` copies indexed elements only. `degraded` / `degradedError` /
// `skipped` are NON-enumerable by design (so the phase-A golden fixture and
// every serialised log keep their shape), which means a plain slice silently
// drops them — and the degradation notice would then never reach the model.
// Re-attach every out-of-band channel the recall path is known to carry.
for (const key of ['degraded', 'degradedError', 'skipped', 'skippedDim']) {
if (Object.prototype.hasOwnProperty.call(rows, key)) {
Object.defineProperty(retained, key, {
value: rows[key],
enumerable: false,
configurable: true,
})
}
}
const singleHitOverBudget = costs[0] > budget
Object.defineProperty(retained, "budgetNotice", { value: singleHitOverBudget ? `[Memory] Top note estimate ${costs[0]} tokens exceeds memory budget ${budget}; retained without truncation.` : count < rows.length ? `[Memory] Recall limited to ${count} note(s) by memory budget ${budget}.` : "", enumerable: false })
return { hits: retained, budgetTokens: budget, source, singleHitOverBudget }