6247585b66
PR-1 'core' of #370: introduces page_history.kind ('manual'|'agent'|'idle'| 'boundary'; legacy null = autosave) and rebuilds the snapshot triggers around a three-tier intentionality model. Draft durability (pages/ydoc hocuspocus autosave) is unchanged; only the frequency and labelling of history points change. - Migration 20260705T120000: page_history.kind nullable varchar(20), no default. - Manual Save: one stateless 'save-version' path for human AND agent; kind is derived SERVER-SIDE from the signed context.actor (never the payload), readOnly connections rejected, the fresh ydoc runs through the existing store path (no REST race), then broadcasts version.saved. - Idle-flush: trailing debounce (one BullMQ job per page, remove-then-readd) with IDLE_INTERVAL_USER=60m / AGENT=15m AND a max-wait ceiling (IDLE_MAX_WAIT_USER=10m / AGENT=5m) so a continuous editing session can't starve the autosnapshot (review round-1 WARNING). - Boundary: generalized from the user→agent special-case to ANY lastUpdatedSource transition (user↔agent↔git), same isDeepStrictEqual gate — covers git-sync free. - Removed the agent delay=0 fast path and the old HISTORY_FAST_* constants; the agent joins the common idle pipeline. - Promote-not-dup: a manual save on unchanged content promotes the latest autosave's kind in place (or no-ops if already manual) instead of duplicating a heavy content row. - Client: mod+S hotkey + menu button (hidden when readOnly), history-panel kind badges, dimmed autosaves, a 'versions only' filter (indices map to the full list so diff/restore still target the true previous snapshot), live refresh on version.saved. Internal review: APPROVE-with-suggestions; the round-1 WARNING (idle starvation) is fixed here via the max-wait ceiling, and the generalized-boundary + ceiling behaviours are pinned with new tests (115 collab/repo specs green, server tsc 0). Deferred to later PRs: shares.published_mode (PR-2), the save_page_version MCP tool + role prompts (PR-3), actor='git' wiring into #359 (PR-4). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
37 lines
1.9 KiB
TypeScript
37 lines
1.9 KiB
TypeScript
// #348 — debounce window for the per-page RAG re-embed job. Repeated saves
|
|
// within this window collapse to a single delayed job (coalesced by a stable
|
|
// jobId), so active editing does not pile up expensive re-embeds (external API
|
|
// + page_embeddings rewrite, concurrency 1). The worker reads the CURRENT page
|
|
// state at run time, so the last content within the window wins.
|
|
export const EMBED_DEBOUNCE_MS = 30 * 1000;
|
|
|
|
/**
|
|
* #370 — page-history intentionality tiers. Domain of `page_history.kind`.
|
|
* - 'manual' / 'agent' → Tier 1 versions (intentional points)
|
|
* - 'idle' / 'boundary' → Tier 0 autosnapshots (safety net)
|
|
* A legacy `null` kind is treated as an autosave.
|
|
*/
|
|
export type PageHistoryKind = 'manual' | 'agent' | 'idle' | 'boundary';
|
|
|
|
/**
|
|
* #370 — trailing idle-flush windows. A page's pending idle snapshot is
|
|
* re-armed on every store and fires this long after edits go quiet, so a burst
|
|
* of edits collapses into a single autosnapshot instead of one-per-store. Human
|
|
* sessions are noisier and less risky, so they flush less often than the agent.
|
|
*/
|
|
export const IDLE_INTERVAL_USER = 60 * 60 * 1000; // 60m
|
|
export const IDLE_INTERVAL_AGENT = 15 * 60 * 1000; // 15m
|
|
|
|
/**
|
|
* #370 — max-wait ceiling for the idle flush. Pure trailing debounce starves the
|
|
* safety net: hocuspocus stores at least every ~45s, so a CONTINUOUS editing
|
|
* session would re-arm the trailing timer forever and never take an idle
|
|
* snapshot until edits finally go quiet (up to IDLE_INTERVAL_USER = 60m). This
|
|
* ceiling bounds the actual wait from the FIRST edit of a burst, so an idle
|
|
* snapshot fires at least this often during a long unbroken session — restoring
|
|
* a recovery point cadence closer to the old heuristic without one-per-store
|
|
* noise. Mirrors hocuspocus's own maxDebounce idea.
|
|
*/
|
|
export const IDLE_MAX_WAIT_USER = 10 * 60 * 1000; // 10m
|
|
export const IDLE_MAX_WAIT_AGENT = 5 * 60 * 1000; // 5m
|