The bounded-cost NFR asks for explicit ceilings on BOTH axes - max
conversation turns and max discovered dimensions. The turn axis got
MAX_CONV_TURNS, a ledger-backed reader and a PreToolUse enforcer. The
discovery axis got one sentence in Phase 4.5 prose ("append candidates only
while the whole list stays at or below maxDimensions: 8") with no constant
of its own, no reader, and no test that a run exceeding it is caught. That
is the brief_reviewer_iter_cap shape the operator decision warned about: a
cap nothing reads.
checkDimensionCeiling() is the reader, exposed on the CLI as
--check-dimensions N (exit 0 within, exit 1 rejected), and Phase 4.5 step 3
now calls it once the final list is settled instead of merely describing the
bound.
Three deliberate choices:
- The ceiling IS MAX_TOTAL_DIMENSIONS, the constant that sizes the turn
budget. Both axes read one settings.json:16 value, so they cannot end up
enforcing different numbers - a second constant is how that drift starts.
- An unreadable count is REJECTED ('abc', null, undefined, {}, -1, NaN,
non-integers). A cost ceiling that waves through what it cannot measure is
not a ceiling.
- --check-dimensions requires no run id, effort or VOYAGE_STORM_ENABLED.
Phase 4.5 never calls the budget gate - that is why its skip-guard reads
the flag directly - so the ceiling check must not inherit the gate's
preconditions.
The mitigation the review already verified still holds and is unchanged:
MAX_TOTAL_DIMENSIONS bounds actual retrieval cost regardless of how many
dimensions discovery appends. What was missing was anything that FAILS on a
list over the bound, and now a run over it is rejected by exit code.
Review finding 96a3ee51152dfe72aca703f771843f2f3639e7b6 (MINOR).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuGhWAbWyRFBFeemfhxoVv