Data Model¶
Everything the agent knows lives in Postgres, split across three schemas by what the data
is. The SQL files under server/db/migrations/ are the source of truth, applied in
order.
| Schema | Holds |
|---|---|
event_logs |
parsed VEX events, detected triggers, and identity |
chat |
messages, their feedback, and the stream change counter |
current_state |
the derived per-session state snapshot |
event_logs¶
parsed_events is the append-only record of what a student did in VEX, one row per
event. It carries the identity of the actor, the moment and kind of event, and the block
payload.
| Column | Notes |
|---|---|
session_id, student_id, class_code |
who and which session |
event_ts, event_type |
when, and what kind of event |
playground, program_type |
which task and program |
project_json, block_event_data_json, playground_data_json |
the block workspace and event payloads |
has_orphans, switch_block_count, error_message |
derived flags used by triggers |
source, source_log_id, source_received_at, source_queue |
provenance back to the Hub log |
agent_triggers records each detected behavior. A unique key on
(student_id, session_id, trigger_type, run_index) is the dedupe that makes a trigger
fire once. It also tracks acted, the response_id of the message it produced, and a
lifecycle of acknowledged, resolved_at, and last_seen_at.
switch_events logs identity switches, a casing flip or a changed class code.
student_identity maps a folded canon_id to the most recent spelling and class code
seen, so the same student is not split across near-duplicate ids.
chat¶
messages is the conversation, one row per turn. Alongside the text and role it keeps
a feedback_class, a response_id, and an origin that marks whether a message was
reactive or proactive. message_feedback records a thumbs up or down and an
optional comment on a given response.
channel_rev is a single small counter per channel. The SSE stream reads one row to
learn a student's channel changed, rather than polling the messages table. This is what
keeps the live stream cheap.
current_state¶
state_snapshots is the derived read model, one row per session and student enforced
by a unique constraint. It holds the computed picture of the session, time_on_task_s,
action_level, progress_pct, direction, cognition, and persistence, along with
the range of event ids it was computed from. Because it is a projection over
parsed_events, it can be dropped and rebuilt from the log at any time.
The Migrations¶
Applied in filename order, drift-proof with no per-file list to maintain.
| File | Builds |
|---|---|
001_create_parsed_events |
the parsed event log |
002_create_state_snapshots |
the derived per-session snapshot |
003_add_playground_data_to_parsed_events |
playground payload on events |
004_create_messages |
the chat log |
005_create_message_feedback |
thumbs and comments |
006_create_agent_triggers |
detected triggers with the dedupe key |
007_agent_triggers_lifecycle |
acknowledge, resolve, and re-alert fields |
008_student_id_case_folding |
case and space folded student ids |
009_switch_events |
identity switch log |
010_channel_rev |
the O(1) stream change counter |
011_student_identity |
the canonical identity map |
Apply them against a running database with a short loop.
export DATABASE_URL=postgresql://vexagent:$POSTGRES_PASSWORD@127.0.0.1:5433/vexagent
for f in server/db/migrations/*.sql; do psql "$DATABASE_URL" -f "$f"; done