email-activity agent: propose -> review -> approve grid notes (v0.1.0:64)
When a sent/received email is matched to an investor, a local-model agent drafts a
one-line dated note and queues it as a PENDING proposal (it never writes the grid
itself). On the Email Capture page a partner sees "Proposed grid notes", can edit the
text, and Approve (appends to that investor's grid notes cell, newest at bottom,
stamped with the approver) or Dismiss. Going-forward only: a cutoff (app_settings
email_activity_since, set on first run) means email dated before the feature was
enabled is never summarized, so the historical backfill makes no noise. Sovereign:
summaries run entirely on the local model (no redaction needed). Gmail sync interval
tightened 180 -> 15 min so outgoing email surfaces quickly.
Backend: migration 0002 (email_activity_proposals); propose_email_activity_notes()
runs via a new scheduler post_sync hook; list/decide functions + routes
GET /api/activity/proposals, POST .../{id}/approve|dismiss. Grid append stamps the
approving user (fundraising_state.updated_by has a FK to users). Test
test_email_activity.py (propose cutoff/idempotency, approve appends + edited note,
dismiss, already-decided guard) under FK enforcement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
-- ============================================================================
|
||||
-- email_activity_proposals — the email-activity agent's PROPOSED grid notes,
|
||||
-- queued for human review. The agent (local model, sovereign) drafts one note per
|
||||
-- newly-matched email; a partner approves (optionally after editing) or dismisses
|
||||
-- it in the web UI. Only on approval does the text get appended to the grid.
|
||||
-- One proposal per email (email_id UNIQUE) — never re-proposed.
|
||||
-- ============================================================================
|
||||
CREATE TABLE IF NOT EXISTS email_activity_proposals (
|
||||
id TEXT PRIMARY KEY,
|
||||
email_id TEXT NOT NULL UNIQUE,
|
||||
investor_id TEXT, -- fundraising_investors.id / grid row id (best-effort)
|
||||
investor_name TEXT,
|
||||
direction TEXT, -- sent | received
|
||||
summary TEXT, -- the one-line gist from the local model
|
||||
proposed_note TEXT, -- the full note as drafted (editable before approve)
|
||||
email_subject TEXT, -- context shown to the reviewer
|
||||
email_date TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending', -- pending | approved | dismissed
|
||||
decided_by TEXT, -- users.id who approved/dismissed
|
||||
decided_at TEXT,
|
||||
final_note TEXT, -- the text actually appended on approval (may be edited)
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
FOREIGN KEY(email_id) REFERENCES emails(id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_email_proposals_status ON email_activity_proposals(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_email_proposals_investor ON email_activity_proposals(investor_id);
|
||||
Reference in New Issue
Block a user