Events Catalog
Complete taxonomy of thefund_events signal stream — 4 groups, closed enum, structured payloads.
Every mutation in Hugo emits structured events to the fund_events table. The event type is a closed enum — no free-form strings. Each type has a defined payload schema enforced at the emit helper. Events are grouped into four categories by source and nature.
fund_events are never updated or deleted. History is immutable for audit and replay integrity.
Group 1 — User-initiated mutations
Direct results of user actions, emitted via the withImpact helper. Each event captures the actor, the entity affected, and a structured payload with before/after state where applicable.
| Event type | Payload fields | Trigger source |
|---|---|---|
commitment_created |
commitment_id, fund_id, lp_id, amount, closing_id |
Create commitment form |
commitment_updated |
commitment_id, changed_fields, old_values, new_values |
Edit commitment |
commitment_deleted |
commitment_id, fund_id, lp_id |
Delete commitment action |
clause_created |
clause_id, fund_id, clause_name_id, category |
Add clause to library |
clause_updated |
clause_id, changed_fields, old_values, new_values |
Edit clause text or metadata |
clause_forked |
clause_id, parent_id, fund_id |
Fork clause from genealogy parent |
clause_assignment_created |
assignment_id, clause_id, commitment_id |
Assign clause to LP |
clause_assignment_removed |
assignment_id, clause_id, commitment_id |
Remove clause from LP |
mfn_basic_rule_created |
rule_id, fund_id, dimensions, logic_op |
Create basic MFN rule |
mfn_basic_rule_updated |
rule_id, changed_fields |
Edit basic MFN rule |
mfn_basic_rule_deleted |
rule_id, fund_id |
Delete basic MFN rule |
mfn_general_rule_created |
rule_id, fund_id, category, action |
Create general MFN rule |
mfn_general_rule_updated |
rule_id, changed_fields |
Edit general MFN rule |
mfn_general_rule_deleted |
rule_id, fund_id |
Delete general MFN rule |
mfn_individual_rule_created |
rule_id, commitment_id, action, rationale |
Create individual MFN rule |
mfn_individual_rule_deleted |
rule_id, commitment_id |
Delete individual MFN rule |
mfn_election_recorded |
election_id, commitment_id, clause_id, decision |
LP records election (elected/excluded/pending) |
fund_closing_scheduled |
closing_id, fund_id, closing_date, sequence |
Schedule a closing |
fund_closing_executed |
closing_id, fund_id, committed_amount |
Execute a closing |
document_uploaded |
document_id, fund_id, lp_id, r2_key, filename |
Upload side letter .docx |
side_letter_parsed |
document_id, clauses_extracted, confidence_avg |
Parse queue consumer completes |
investor_bulk_imported |
count, fund_id, filename, job_id |
Spreadsheet import completes (sync <= 20 rows or async) |
lp_task_created / lp_task_updated / lp_task_completed / lp_task_overdue |
task_id, commitment_id, fund_id, priority, status |
LP task lifecycle (create / edit / complete / SLA miss) |
side_letter_status_changed / commitment_lifecycle_changed / kyc_status_changed |
commitment_id, old_status, new_status |
Commitment-level lifecycle transitions |
Group 2 — Derived effects
Automatically computed by the withImpact helper after a root mutation. These events always have a caused_by FK pointing to the root event that triggered them, with depth ≥ 1.
| Event type | Payload fields | Trigger source |
|---|---|---|
mfn_eligibility_changed |
commitment_id, clause_id, old_eligible, new_eligible, rule_layer |
MFN diff after any rule/assignment/commitment mutation |
mfn_cascade_detected |
fund_id, affected_count, root_event_type |
Multiple eligibility changes from a single mutation |
close_readiness_flipped |
commitment_id, old_ready, new_ready, blocking_fields |
Commitment readiness status change after field updates |
template_divergence_increased |
clause_id, parent_id, divergence_score |
Clause edit increases drift from fork parent |
Group 3 — Absence and timing
Events that matter because something did not happen. These cannot be mutation-triggered — they are detected by scheduled cron sweeps running every 10–15 minutes. Each sweep is independent and try/catch-wrapped.
| Event type | Payload fields | Trigger source |
|---|---|---|
election_window_opening_soon |
fund_id, window_opens_at, days_until |
sweepElectionWindows — window opening within N days |
election_window_closing_soon |
fund_id, window_closes_at, days_remaining, pending_count |
sweepElectionWindows — window closing within N days |
lp_silent |
commitment_id, lp_id, days_silent, last_activity_at |
sweepSilentLps — anchor LPs past silence threshold |
draft_clause_stale |
clause_id, fund_id, days_in_draft, last_edited_at |
sweepStaleDrafts — draft clauses past age threshold |
low_confidence_clause_unreviewed |
clause_id, document_id, confidence, days_since_parse |
sweepLowConfidenceUnreviewed — low-confidence parses not human-reviewed |
Group 4 — System observability
Emitted by Hugo's own pipelines for debugging and reliability monitoring. These events are free to add and useful for diagnosing issues in the parse pipeline, MFN engine, and classifier.
| Event type | Payload fields | Trigger source |
|---|---|---|
parse_classified_low_confidence |
document_id, clause_index, confidence, predicted_category |
Clause classifier returns confidence below threshold |
parse_job_failed |
document_id, error_message, attempt, queue_id |
Parse queue consumer fails after retries |
mfn_recompute_slow |
fund_id, duration_ms, commitment_count, clause_count |
MFN engine run exceeds 150ms threshold |
Event discipline
Closed enum
The event type set is a committed enum in a shared types file (src/lib/types.ts), not free-form strings. Free-form types drift (mfn_cascade vs mfnCascade vs MFN_CASCADE_DETECTED) and make synthesis prompts brittle. One enum, one payload schema per type, enforced at the emit helper.
Provenance
- Root events (Groups 1, 3, 4) have
caused_by = NULLanddepth = 0 - Derived events (Group 2) point at the root that caused them via
caused_byFK withdepth ≥ 1 - Enables provenance walks: trace any derived effect back to its originating user action or sweep
Synthesis integration
Every write to fund_events also enqueues a message to hugo-sitrep-queue via waitUntil, triggering event-driven synthesis with 30-second debounce. See SITREP signals for the full synthesis pipeline.