Problem
Among the history read ops, only history.list is gated. The cooldown check tests the list type alone (apps/hocuspocus.server/src/hocuspocus.server.ts:297), through listCoolingDown (apps/hocuspocus.server/src/hocuspocus.server.ts:116). history.revert carries its own separate cooldown (apps/hocuspocus.server/src/hocuspocus.server.ts:151).
history.watch has no cap at all. Each call reads one row and base64-encodes the whole document (apps/hocuspocus.server/src/lib/history-stateless.ts:147-155, encoder at apps/hocuspocus.server/src/lib/history-stateless.ts:90).
That encode is synchronous work on the shared process event loop. The Throttle extension only covers onConnect, so no per-frame cap stands behind it (apps/hocuspocus.server/src/hocuspocus.server.ts:91). A client that loops over versions therefore pays no cost cap.
What to do
Add a cost cap to the watch arm. Shape it as a bytes-per-connection budget, not as a cooldown.
Keep the recorded decision at apps/hocuspocus.server/src/hocuspocus.server.ts:293-296. A cooldown on watch would walk the client through its own list, because the client answers a refusal by asking for the next version. Do not re-propose one.
Acceptance
Notes
The cost of one watch encode is not measured. Size the budget against a real document before you pick a number.
Problem
Among the history read ops, only
history.listis gated. The cooldown check tests the list type alone (apps/hocuspocus.server/src/hocuspocus.server.ts:297), throughlistCoolingDown(apps/hocuspocus.server/src/hocuspocus.server.ts:116).history.revertcarries its own separate cooldown (apps/hocuspocus.server/src/hocuspocus.server.ts:151).history.watchhas no cap at all. Each call reads one row and base64-encodes the whole document (apps/hocuspocus.server/src/lib/history-stateless.ts:147-155, encoder atapps/hocuspocus.server/src/lib/history-stateless.ts:90).That encode is synchronous work on the shared process event loop. The
Throttleextension only coversonConnect, so no per-frame cap stands behind it (apps/hocuspocus.server/src/hocuspocus.server.ts:91). A client that loops over versions therefore pays no cost cap.What to do
Add a cost cap to the watch arm. Shape it as a bytes-per-connection budget, not as a cooldown.
Keep the recorded decision at
apps/hocuspocus.server/src/hocuspocus.server.ts:293-296. A cooldown on watch would walk the client through its own list, because the client answers a refusal by asking for the next version. Do not re-propose one.Acceptance
Notes
The cost of one watch encode is not measured. Size the budget against a real document before you pick a number.