|
| 1 | +# Community Data Collection Schema |
| 2 | + |
| 3 | +Anonymous completion metrics collected with opt-in consent for training an |
| 4 | +improved completion gating model. **No code content, no file paths, nothing |
| 5 | +identifying.** |
| 6 | + |
| 7 | +## Schema |
| 8 | + |
| 9 | +```json |
| 10 | +{ |
| 11 | + "device_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", |
| 12 | + "outcome": "accepted", |
| 13 | + "file_ext": ".go", |
| 14 | + "language": "go", |
| 15 | + "prefix_length": 15, |
| 16 | + "trimmed_prefix_length": 13, |
| 17 | + "line_count": 210, |
| 18 | + "relative_position": 0.14, |
| 19 | + "after_cursor_ws": false, |
| 20 | + "last_char": ")", |
| 21 | + "last_nonws_char": ")", |
| 22 | + "prev_filter_shown": true, |
| 23 | + "completion_lines": 3, |
| 24 | + "completion_additions": 3, |
| 25 | + "completion_deletions": 0, |
| 26 | + "completion_source": "typing", |
| 27 | + "manually_triggered": false, |
| 28 | + "display_duration_ms": 1200, |
| 29 | + "time_since_last_decision_ms": 4500, |
| 30 | + "recent_actions": ["IC", "IC", "IC", "DC", "IC"], |
| 31 | + "has_diagnostics": false, |
| 32 | + "treesitter_scope": "function", |
| 33 | + "provider": "sweepapi", |
| 34 | + "edit_count": 18, |
| 35 | + "predicted_edit_ratio": 0.33, |
| 36 | + "time_since_last_edit_ms": 800, |
| 37 | + "typing_speed": 4.2, |
| 38 | + "completions_since_accept": 3, |
| 39 | + "indentation_level": 2, |
| 40 | + "stage_index": 0, |
| 41 | + "cursor_target_distance": 12, |
| 42 | + "is_prefetched": false, |
| 43 | + "filter_score": 0.72 |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +## Database Schema |
| 48 | + |
| 49 | +Server-side fields are added on ingestion and are not sent by the client. |
| 50 | + |
| 51 | +```sql |
| 52 | +CREATE TABLE events ( |
| 53 | + -- Server-side fields |
| 54 | + id INTEGER PRIMARY KEY AUTOINCREMENT, |
| 55 | + created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), |
| 56 | + ip_hash TEXT NOT NULL, |
| 57 | + plugin_version TEXT NOT NULL, |
| 58 | + |
| 59 | + -- Identity |
| 60 | + device_id TEXT NOT NULL, |
| 61 | + |
| 62 | + -- Outcome |
| 63 | + outcome TEXT NOT NULL, -- 'accepted', 'rejected', 'ignored' |
| 64 | + |
| 65 | + -- File context |
| 66 | + file_ext TEXT NOT NULL, |
| 67 | + language TEXT NOT NULL, |
| 68 | + |
| 69 | + -- Cursor context |
| 70 | + prefix_length INTEGER NOT NULL, |
| 71 | + trimmed_prefix_length INTEGER NOT NULL, |
| 72 | + line_count INTEGER NOT NULL, |
| 73 | + relative_position REAL NOT NULL, |
| 74 | + after_cursor_ws INTEGER NOT NULL, -- 0/1 |
| 75 | + last_char TEXT NOT NULL DEFAULT '', |
| 76 | + last_nonws_char TEXT NOT NULL DEFAULT '', |
| 77 | + indentation_level INTEGER NOT NULL, |
| 78 | + |
| 79 | + -- Filter state |
| 80 | + prev_filter_shown INTEGER NOT NULL, -- 0/1 |
| 81 | + filter_score REAL NOT NULL, |
| 82 | + |
| 83 | + -- Completion properties |
| 84 | + completion_lines INTEGER NOT NULL, |
| 85 | + completion_additions INTEGER NOT NULL, |
| 86 | + completion_deletions INTEGER NOT NULL, |
| 87 | + completion_source TEXT NOT NULL, -- 'typing', 'idle' |
| 88 | + manually_triggered INTEGER NOT NULL, -- 0/1 |
| 89 | + provider TEXT NOT NULL, |
| 90 | + |
| 91 | + -- Staging & cursor prediction |
| 92 | + stage_index INTEGER NOT NULL DEFAULT 0, |
| 93 | + cursor_target_distance INTEGER NOT NULL DEFAULT 0, |
| 94 | + is_prefetched INTEGER NOT NULL DEFAULT 0, -- 0/1 |
| 95 | + |
| 96 | + -- Timing |
| 97 | + display_duration_ms INTEGER NOT NULL, |
| 98 | + time_since_last_decision_ms INTEGER NOT NULL, |
| 99 | + time_since_last_edit_ms INTEGER NOT NULL, |
| 100 | + typing_speed REAL NOT NULL, |
| 101 | + |
| 102 | + -- Session context |
| 103 | + recent_actions TEXT NOT NULL, -- JSON array, e.g. '["IC","IC","DC"]' |
| 104 | + has_diagnostics INTEGER NOT NULL, -- 0/1 |
| 105 | + treesitter_scope TEXT NOT NULL, |
| 106 | + edit_count INTEGER NOT NULL, |
| 107 | + predicted_edit_ratio REAL NOT NULL, |
| 108 | + completions_since_accept INTEGER NOT NULL |
| 109 | +); |
| 110 | + |
| 111 | +-- Indexes for queries and anomaly detection |
| 112 | +CREATE INDEX idx_events_device_id ON events(device_id); |
| 113 | +CREATE INDEX idx_events_created_at ON events(created_at); |
| 114 | +CREATE INDEX idx_events_outcome ON events(outcome); |
| 115 | +``` |
| 116 | + |
| 117 | +## API Payload |
| 118 | + |
| 119 | +The client sends the following JSON body to `POST /events`. Server-side fields |
| 120 | +(`id`, `created_at`, `ip_hash`, `plugin_version`) are derived on ingestion — |
| 121 | +`plugin_version` is sent as a header. |
| 122 | + |
| 123 | +## Field Reference |
| 124 | + |
| 125 | +| Field | Type | Source | Description | |
| 126 | +| ----------------------------- | ---------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 127 | +| `id` | `int` | server | Auto-increment primary key | |
| 128 | +| `created_at` | `string` | server | ISO 8601 UTC timestamp when the event was received | |
| 129 | +| `ip_hash` | `string` | server | SHA-256 hash of the client IP (for rate limiting and anomaly detection, not identifying) | |
| 130 | +| `plugin_version` | `string` | header | Plugin version that sent the event (e.g. `"0.5.0"`) | |
| 131 | +| `device_id` | `string` | client | Persistent UUID4 generated once per install | |
| 132 | +| `outcome` | `string` | client | Completion result: `"accepted"`, `"rejected"`, or `"ignored"` | |
| 133 | +| `file_ext` | `string` | client | Lowercase file extension including dot (e.g. `".go"`, `".ts"`) | |
| 134 | +| `language` | `string` | client | Resolved language identifier (e.g. `"go"`, `"typescript"`, `"unknown"`) | |
| 135 | +| `prefix_length` | `int` | client | Length of the text on the current line before the cursor (byte offset within line) | |
| 136 | +| `trimmed_prefix_length` | `int` | client | Length of the prefix with trailing whitespace removed | |
| 137 | +| `line_count` | `int` | client | Total number of lines in the document | |
| 138 | +| `relative_position` | `float` | client | Normalized cursor position in the document (`0.0` = top, `1.0` = bottom) | |
| 139 | +| `after_cursor_ws` | `bool` | client | Whether all text after the cursor on the current line is whitespace (or cursor is at EOL) | |
| 140 | +| `last_char` | `string` | client | Last character of the prefix, or `""` if the prefix is empty | |
| 141 | +| `last_nonws_char` | `string` | client | Last non-whitespace character of the prefix, or `""` if none | |
| 142 | +| `indentation_level` | `int` | client | Number of leading indent units (tab stops) on the current line | |
| 143 | +| `prev_filter_shown` | `bool` | client | Whether the previous contextual filter invocation resulted in showing a completion | |
| 144 | +| `filter_score` | `float` | client | Score from the current contextual filter model (`0.0`-`1.0`) | |
| 145 | +| `completion_lines` | `int` | client | Number of lines in the completion suggestion | |
| 146 | +| `completion_additions` | `int` | client | Number of lines added by the completion | |
| 147 | +| `completion_deletions` | `int` | client | Number of lines deleted/replaced by the completion | |
| 148 | +| `completion_source` | `string` | client | What triggered the completion: `"typing"` or `"idle"` | |
| 149 | +| `manually_triggered` | `bool` | client | Whether the user explicitly triggered the completion (keybind) vs. automatic | |
| 150 | +| `provider` | `string` | client | Which provider generated the completion (e.g. `"sweepapi"`, `"copilot"`, `"mercuryapi"`) | |
| 151 | +| `stage_index` | `int` | client | Which stage of a multi-stage completion (`0` for single-stage or the first stage) | |
| 152 | +| `cursor_target_distance` | `int` | client | Lines between the cursor and the completion target (`0` when no navigation needed) | |
| 153 | +| `is_prefetched` | `bool` | client | Whether the completion was speculatively prefetched ahead of the user arriving at the target | |
| 154 | +| `display_duration_ms` | `int` | client | Milliseconds the completion was visible before the user acted (analytics only — not a gating model input) | |
| 155 | +| `time_since_last_decision_ms` | `int` | client | Milliseconds since the last accept/reject/suppress decision | |
| 156 | +| `time_since_last_edit_ms` | `int` | client | Milliseconds since the most recent edit in the current file | |
| 157 | +| `typing_speed` | `float` | client | Average typing speed (chars/sec) over the ~3 seconds preceding the completion trigger | |
| 158 | +| `recent_actions` | `string[]` | client | Last 5 user actions before the completion trigger. Values: `"IC"` (insert char), `"IS"` (insert selection), `"DC"` (delete char), `"DS"` (delete selection), `"CM"` (cursor movement) | |
| 159 | +| `has_diagnostics` | `bool` | client | Whether the file has active LSP diagnostics (errors or warnings) | |
| 160 | +| `treesitter_scope` | `string` | client | Enclosing AST scope: `"function"`, `"class"`, `"top_level"`, `"string"`, `"comment"`, or `"other"` | |
| 161 | +| `edit_count` | `int` | client | Total number of diff entries in the current file's session history | |
| 162 | +| `predicted_edit_ratio` | `float` | client | Ratio of AI-accepted edits (`predicted`) to total edits in the current file (`0.0`-`1.0`) | |
| 163 | +| `completions_since_accept` | `int` | client | Number of completions shown (and not accepted) since the last accept | |
0 commit comments