feat(P02): telemetry models + TraceStore SQLite + TS types (Wave 1)

Task 2-1-01: TelemetryEvent (SQLModel table, composite PK learner/task/seq) + TraceSpan
derived view; SQLAlchemy @validates enforcement (sqlmodel drops Field constraints on table
models). Task 2-1-02: TraceStore protocol (D-019-mirrored) + SQLiteTraceStore with WAL +
synchronous=NORMAL (a-3); concurrent writer/reader no database-locked; idempotent
dedup-on-retry. Task 2-1-03: TS TelemetryEvent/TraceSpan mirroring Python field-for-field
(snake_case for byte-identical JSON); full typecheck green.

195/195 + typecheck pass; ruff clean.

---ci---
phase: 2
milestone: v0.3
status: execute
requirements: {covered: [REQ-3-003], partial: []}
---/ci---
This commit is contained in:
CIAgent
2026-09-11 18:51:42 +00:00
parent f0df18576e
commit cfdceac17a
8 changed files with 679 additions and 0 deletions
+1
View File
@@ -1,4 +1,5 @@
export * from './domain';
export * from './marketplace';
export * from './telemetry';
export * from './user';
export * from './ui';
+44
View File
@@ -0,0 +1,44 @@
/**
* Nextcraft — Telemetry Types
*
* Learner process telemetry: ordered events emitted from sandbox sessions,
* aggregated into trace spans for evidence-of-process analysis.
*
* Source of truth: the Python models in `apps/ai-service/ai_service/telemetry/models.py`
* (`TelemetryEvent` / `TraceSpan`). This file mirrors those models
* field-for-field; any schema change must be made in both places.
*/
export type TelemetryKind =
| 'command'
| 'file_diff'
| 'run_result'
| 'test_result'
| 'activity'
| 'stdin'
| 'stdout';
export interface TelemetryEvent {
learner_id: string;
task_id: string;
/** Sequence number within the session (int >= 0). */
seq: number;
kind: TelemetryKind;
payload: Record<string, unknown>;
/** ISO 8601 datetime string. */
ts: string;
sandbox_id: string;
}
/**
* Derived view: the ordered event trace for one (learner_id, task_id).
* Materialized by the store from persisted TelemetryEvents — mirrors the
* Python `TraceSpan` (ai_service/telemetry/models.py), which holds an ordered
* `events` sequence. NOT a table on either side.
*/
export interface TraceSpan {
learner_id: string;
task_id: string;
/** Ordered events for the (learner, task) pair, sorted by seq. */
events: TelemetryEvent[];
}