Archive a lifetime of email and chat. Offline search, analytics, and AI query over your full message history. Powered by SQLite and DuckDB
This report presents the forensic synthetic code analysis of kenn-io/msgvault, a Go project with 1,921 GitHub stars. SynthScan v2.0 examined 290,425 lines of code across 866 source files, recording 568 pattern matches distributed across 14 syntactic categories. The overall adjusted score of 2.5 places this repository in the Likely human-written band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 568 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …ault/cmd/serve_vector_precheck_mainpath_pgonly_test.go | 1 | //go:build pgvector && !sqlite_vec | COMMENT |
| LOW | cmd/msgvault/cmd/serve_vector_init.go | 141 | // Cron was validated in precheckVectorFeatures, so this is an | COMMENT |
| LOW | cmd/msgvault/cmd/serve_vector.go | 61 | // must be called on shutdown. | COMMENT |
| LOW | cmd/msgvault/cmd/store_resolver.go | 61 | } | COMMENT |
| LOW | cmd/msgvault/cmd/serve.go | 1201 | // Under scan-and-fill there is no enqueue step — newly-ingested messages | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 921 | } | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 941 | // | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding.go | 81 | } else { | COMMENT |
| LOW | cmd/msgvault/cmd/account_identity.go | 21 | // | COMMENT |
| LOW | cmd/msgvault/cmd/deduplicate.go | 1021 | COMMENT | |
| LOW | cmd/msgvault/cmd/deletions.go | 1321 | } | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector.go | 21 | // still unmarked. repair-encoding MUST open the backend BEFORE it clears | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector.go | 61 | Dimension: cfg.Vector.Embeddings.Dimension, | COMMENT |
| LOW | cmd/msgvault/cmd/import_mbox.go | 301 | COMMENT | |
| LOW | cmd/msgvault/cmd/confirm.go | 21 | ConfirmModePermanent ConfirmMode = iota | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector_test.go | 21 | // that guards the one-time upgrade backfill. Kept in sync deliberately: the | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector_test.go | 41 | // the vector backend runs BackfillEmbedGenForUpgrade, which stamps | COMMENT |
| LOW | cmd/msgvault/cmd/embed_pg_test.go | 161 | // pgvector tables into it (via pgvector.Open), and returns the pgvector | COMMENT |
| LOW | …t/cmd/serve_vector_precheck_mainpath_sqlitevec_test.go | 1 | //go:build sqlite_vec | COMMENT |
| LOW | cmd/msgvault/cmd/embed_vector_test.go | 281 | assert.NotContains(t, got, "resume` again") | COMMENT |
| LOW | cmd/msgvault/cmd/embeddings_manage.go | 41 | MessageCount int64 | COMMENT |
| LOW | cmd/msgvault/cmd/embeddings_manage.go | 541 | return fmt.Sprintf( | COMMENT |
| LOW | cmd/msgvault/cmd/embeddings_manage.go | 621 | if err != nil { | COMMENT |
| LOW | cmd/msgvault/cmd/root.go | 61 | // Errors from (2) (config load, logger setup) are runtime | COMMENT |
| LOW | cmd/msgvault/cmd/root.go | 341 | // silenceUsageOnce guards silenceUsageInRunE so each command's RunE is | COMMENT |
| LOW | cmd/msgvault/cmd/embed_vector.go | 201 | // true if the user agreed to proceed. | COMMENT |
| LOW | cmd/msgvault/cmd/embed_vector.go | 241 | return gen, true, nil | COMMENT |
| LOW | cmd/msgvault/cmd/embed_vector.go | 281 | _, _ = fmt.Fprintf(opts.Stderr, "Using active generation %d (%s).\n", active.ID, active.Fingerprint) | COMMENT |
| LOW | internal/beeper/importer.go | 21 | // O(chats) JSON, so rewriting it after every chat of a large account is | COMMENT |
| LOW | internal/beeper/types.go | 141 | COMMENT | |
| LOW | internal/beeper/participants.go | 21 | // Beeper and native SMS/WhatsApp archives. | COMMENT |
| LOW | internal/beeper/doc.go | 1 | // Package beeper archives chats from the local Beeper Desktop API into the | COMMENT |
| LOW | internal/deletion/manifest.go | 481 | default: | COMMENT |
| LOW | internal/imap/client.go | 41 | // WithListProgress sets a callback reporting mailbox-enumeration | COMMENT |
| LOW | internal/imap/folderstate.go | 21 | // WithFolderStates provides per-mailbox states saved after the last | COMMENT |
| LOW | internal/fileutil/secure_windows.go | 141 | // SecureOpenFile opens the named file with specified flag and permissions. | COMMENT |
| LOW | internal/fbmessenger/importer.go | 41 | COMMENT | |
| LOW | internal/fbmessenger/types.go | 21 | // (e.g. a DYI metadata file). Callers should silently skip — the | COMMENT |
| LOW | internal/fbmessenger/types.go | 41 | // Messages are sorted chronologically (ascending). | COMMENT |
| LOW | internal/fbmessenger/types.go | 81 | } | COMMENT |
| LOW | internal/fbmessenger/discover.go | 141 | } | COMMENT |
| LOW | internal/fbmessenger/discover.go | 181 | // e2eeShapeThread: the file is a JSON object with at least both of | COMMENT |
| LOW | internal/config/config.go | 201 | // LogConfig holds logging configuration. File logging is opt-in: | COMMENT |
| LOW | internal/config/config.go | 501 | COMMENT | |
| LOW | internal/config/config.go | 781 | if src.Enabled && src.Schedule != "" { | COMMENT |
| LOW | internal/sqldialect/sqldialect.go | 1 | // Package sqldialect carries the small SQL primitives that both the | COMMENT |
| LOW | internal/sqldialect/sqldialect.go | 41 | } | COMMENT |
| LOW | internal/tui/model.go | 101 | // Keys are scoped to the current ViewType to prevent collisions. | COMMENT |
| LOW | internal/microsoft/oauth.go | 201 | COMMENT | |
| LOW | internal/backupapp/content_source.go | 21 | // bytes from the production blob store (packs plus canonical loose files), | COMMENT |
| LOW | internal/scheduler/scheduler_test.go | 1021 | // generation that has a below-watermark straggler. With a global time.Time | COMMENT |
| LOW | internal/scheduler/embed_job.go | 41 | // Compile-time check that the production worker satisfies EmbedRunner. | COMMENT |
| LOW | internal/scheduler/embed_job.go | 61 | Backend vector.Backend | COMMENT |
| LOW | internal/scheduler/embed_job.go | 81 | // BackstopInterval controls how often Run also performs a full | COMMENT |
| LOW | internal/scheduler/embed_job.go | 101 | // backstop throttle a different generation's first backstop — which would | COMMENT |
| LOW | internal/scheduler/embed_job.go | 161 | // scans forward from the per-gen watermark, so below-watermark | COMMENT |
| LOW | internal/scheduler/embed_job.go | 261 | "succeeded", res.Succeeded, | COMMENT |
| LOW | internal/scheduler/embed_job.go | 281 | // into an index whose existing vectors used a different policy, | COMMENT |
| LOW | internal/search/parser.go | 281 | func NewParser() *Parser { | COMMENT |
| LOW | internal/textutil/encoding.go | 141 | // where the first line itself may be excessively long (e.g. enmime | COMMENT |
| 260 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | cmd/msgvault/cmd/root_test.go | 565 | Expected: "user@example.com", | CODE |
| LOW | cmd/msgvault/cmd/root_test.go | 577 | _, err := getTokenSourceWithReauth(context.Background(), mock, "user@example.com", true, gmailReauthHint) | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1048 | imapEmail = "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1096 | imapEmail = "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1102 | `{"host":"127.0.0.1","port":1,"username":"user@example.com","tls":true}`, | CODE |
| LOW | cmd/msgvault/cmd/calendar_test.go | 80 | assert.True(calendarSyncShouldRunFullForSources([]*store.Source{calendarSourceWithSyncConfig(`{"account_email":"user@ex | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 395 | got := calendarTokenExpiredOrRevoked(context.Background(), tt.prber, "user@example.com") | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 404 | calendarSyncNextCommand("user@example.com", "personal", calendarSyncNextOptions{})) | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 407 | calendarSyncNextCommand("user@example.com", "", calendarSyncNextOptions{})) | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 415 | calendarSyncNextCommand("user@example.com", "personal", calendarSyncNextOptions{AllCalendars: true})) | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 418 | calendarSyncNextCommand("user@example.com", "", calendarSyncNextOptions{MinAccessRole: "reader"})) | CODE |
| LOW⚡ | cmd/msgvault/cmd/calendar_test.go | 421 | calendarSyncNextCommand("user@example.com", "", calendarSyncNextOptions{ | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 177 | root.SetArgs([]string{"add-account", "user@example.com"}) | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 186 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 246 | root.SetArgs([]string{"add-account", "user@example.com", "--no-default-identity"}) | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 254 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 502 | "add-account", "user@example.com", "--oauth-app", "", | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 570 | "add-account", "user@example.com", "--oauth-app", "", | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_test.go | 783 | root.SetArgs([]string{"add-account", "user@example.com"}) | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_test.go | 791 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_test.go | 798 | assert.Equal("user@example.com", ids[0].Address, "address") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 854 | root.SetArgs([]string{"add-account", "user@example.com", "--no-default-identity"}) | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 862 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 935 | root.SetArgs([]string{"add-account", "user@example.com", "--no-default-identity"}) | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 952 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 1040 | root.SetArgs([]string{"add-account", "user@example.com"}) | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 1048 | src, err := findGmailSource(s, "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_test.go | 1060 | for _, want := range []string{"alias@example.com", "alt@work.com", "user@example.com"} { | CODE |
| LOW | cmd/msgvault/cmd/scope_escalation_test.go | 21 | const scopeEscalationAccount = "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/add_synctech_sms_drive_test.go | 36 | "--google-account", "user@example.com", | CODE |
| LOW | cmd/msgvault/cmd/add_synctech_sms_drive_test.go | 45 | for _, want := range []string{`[[synctech_sms.sources]]`, `name = "pixel"`, `backend = "drive"`, `folder_id = "drive-fo | CODE |
| LOW | cmd/msgvault/cmd/add_synctech_sms_drive_test.go | 377 | GoogleAccount: "user@example.com", | CODE |
| LOW | cmd/msgvault/cmd/verify_test.go | 129 | "user@example.com", | CODE |
| LOW | cmd/msgvault/cmd/verify_test.go | 140 | assert.Equal("user@example.com", got.Email) | CODE |
| LOW | cmd/msgvault/cmd/cache_staleness_test.go | 44 | `INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com')`) | CODE |
| LOW | internal/beeper/mapping_test.go | 24 | {"location with text keeps text", Message{Type: "LOCATION", Text: "123 Main St"}, "123 Main St"}, | CODE |
| LOW | internal/imap/xoauth2_test.go | 20 | username: "user@example.com", | CODE |
| LOW | internal/imap/xoauth2_test.go | 27 | username: "user@example.com", | CODE |
| LOW | internal/imap/xoauth2_test.go | 45 | c := NewXOAuth2Client("user@example.com", "token") | CODE |
| LOW⚡ | internal/imap/config_test.go | 18 | cfg: Config{Host: "imap.example.com", Port: 993, TLS: true, Username: "user@example.com"}, | CODE |
| LOW⚡ | internal/imap/config_test.go | 23 | cfg: Config{Host: "mail.example.com", Port: 143, STARTTLS: true, Username: "user@example.com"}, | CODE |
| LOW⚡ | internal/imap/config_test.go | 28 | cfg: Config{Host: "mail.example.com", Port: 143, Username: "user@example.com"}, | CODE |
| LOW | internal/imap/config_test.go | 89 | STARTTLS: true, Username: "user@example.com", | CODE |
| LOW | internal/imap/config_test.go | 93 | Username: "user@example.com", | CODE |
| LOW⚡ | internal/imap/config_test.go | 106 | cfg: Config{Host: "imap.example.com", Port: 993, TLS: true, Username: "user@example.com"}, | CODE |
| LOW⚡ | internal/imap/config_test.go | 110 | cfg: Config{Host: "mail.example.com", Port: 143, STARTTLS: true, Username: "user@example.com"}, | CODE |
| LOW⚡ | internal/imap/config_test.go | 114 | cfg: Config{Host: "mail.example.com", Port: 143, Username: "user@example.com"}, | CODE |
| LOW | internal/importer/pst_integration_test.go | 144 | Identifier: "user@example.com", | CODE |
| LOW | internal/importer/pst_import_test.go | 70 | Identifier: "user@example.com", | CODE |
| LOW | internal/importer/pst_import_test.go | 93 | src, err := st.GetOrCreateSource("pst", "user@example.com") | CODE |
| LOW | internal/importer/pst_import_test.go | 166 | Identifier: "user@example.com", | CODE |
| LOW | internal/oauth/oauth_test.go | 901 | {"different domains", "user@example.com", "user@gmail.com", false}, | CODE |
| LOW | internal/oauth/oauth_test.go | 931 | {"user@example.com", ""}, | CODE |
| LOW | internal/gvoice/parser_test.go | 62 | wantName: "John Doe", | CODE |
| LOW | internal/config/config_test.go | 293 | google_account = "user@example.com" | CODE |
| LOW | internal/config/config_test.go | 307 | require.Truef(src.Backend == "drive" && src.OwnerPhone == "+15550000001" && src.FolderID == "drive-folder-id" && src.Go | CODE |
| LOW | internal/sqldialect/sqldialect_test.go | 46 | {"email_address", "user@example.com", | CODE |
| LOW | internal/tui/nav_view_test.go | 655 | model.drillFilter = query.MessageFilter{SenderName: "John Doe"} | CODE |
| LOW | internal/tui/nav_view_test.go | 658 | assert.Equal(t, "John Doe", key) | CODE |
| LOW | internal/tui/nav_view_test.go | 804 | model.drillFilter = query.MessageFilter{RecipientName: "Jane Doe"} | CODE |
| 74 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | cmd/msgvault/cmd/setup.go | 49 | // Step 1: Find or prompt for OAuth credentials | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 55 | // Step 2: Optionally configure remote NAS | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 61 | // Step 3: Update config | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 472 | // Step 1: Initial full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 477 | // Step 2: Add new messages to SQLite, then incremental export. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 499 | // Step 3: Remove conversations dir (simulate legacy cache missing a table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 503 | // Step 4: Backfill — no new messages, but conversations is missing. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 509 | // Step 5: Verify exact counts — no duplicates from stale incr_*.parquet. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 546 | // Step 1: Full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 550 | // Step 2: Delete message_recipients dir (simulate missing table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 554 | // Step 3: Add new messages to SQLite (so maxID > lastMessageID). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 567 | // Step 4: Build — missing table + new messages should force full rebuild. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 572 | // Step 5: Verify ALL recipients present (12 original + 2 new = 14). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 602 | // Step 1: Full export to create all tables. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 607 | // Step 2: Remove the messages directory (simulate corruption/partial failure). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 616 | // Step 3: Build again — messages are missing but other tables exist. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1226 | // Step 1: Full rebuild to create metadata parquet (sources, labels, etc.). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1232 | // Step 2: Verify non-message parquet was created. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1237 | // Step 3: Run non-full build — should skip, NOT trigger another full rebuild. | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 565 | // Step 1: Drill into alice (top-level, creates drillFilter with TimeMonth default) | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 574 | // Step 2: Tab to sub-aggregate view | COMMENT |
| LOW | internal/tui/nav_view_test.go | 589 | // Step 3: Enter on "2024" — this was the bug | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 234 | // Step 1: Drill down to message list (sets contextStats from alice's row) | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 245 | // Step 2: Press Tab to go to sub-aggregate view (contextStats saved in breadcrumb) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 257 | // Step 3: Drill down from sub-aggregate to message list (contextStats overwritten) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 264 | // Step 4: Go back to sub-aggregate (contextStats should be restored to alice's stats) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 431 | // Step 1: Drill down from top-level to message list (Enter on alice) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 436 | // Step 2: Go to sub-aggregate view (Tab) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 445 | // Step 3: Select an aggregate in sub-aggregate view, then drill down with Enter | COMMENT |
| LOW | internal/vector/embed/worker.go | 453 | // Step 1: upsert embeddings (VectorsDB side). | COMMENT |
| LOW | internal/vector/embed/worker.go | 475 | // Step 2: atomically skip-mark empty/missing rows and remove their stale | COMMENT |
| LOW⚡ | docs/guides/oauth-setup.md | 10 | ### Step 1: Create a Google Cloud Project | COMMENT |
| LOW⚡ | docs/guides/oauth-setup.md | 16 | ### Step 2: Enable Google APIs | COMMENT |
| LOW⚡ | docs/guides/oauth-setup.md | 23 | ### Step 3: Configure OAuth Consent Screen | COMMENT |
| LOW | docs/guides/oauth-setup.md | 41 | ### Step 4: Create OAuth Client Credentials | COMMENT |
| LOW | docs/guides/oauth-setup.md | 57 | ### Step 5: Configure msgvault | COMMENT |
| LOW | docs/guides/oauth-setup.md | 78 | ### Step 6: Add Your Account | COMMENT |
| LOW | scripts/update-nix-flake.sh | 43 | # Step 1: Update version in nix/package.nix if a version tag was provided | COMMENT |
| LOW | scripts/update-nix-flake.sh | 57 | # Step 2: Compute the correct vendorHash | COMMENT |
| LOW⚡ | scripts/update-nix-flake.sh | 83 | # Step 3: Verify it actually builds | COMMENT |
| LOW⚡ | scripts/update-nix-flake.sh | 93 | # Step 4: Commit and open PR | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | cmd/msgvault/cmd/setup.go | 49 | // Step 1: Find or prompt for OAuth credentials | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 55 | // Step 2: Optionally configure remote NAS | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 61 | // Step 3: Update config | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 472 | // Step 1: Initial full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 477 | // Step 2: Add new messages to SQLite, then incremental export. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 499 | // Step 3: Remove conversations dir (simulate legacy cache missing a table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 503 | // Step 4: Backfill — no new messages, but conversations is missing. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 509 | // Step 5: Verify exact counts — no duplicates from stale incr_*.parquet. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 546 | // Step 1: Full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 550 | // Step 2: Delete message_recipients dir (simulate missing table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 554 | // Step 3: Add new messages to SQLite (so maxID > lastMessageID). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 567 | // Step 4: Build — missing table + new messages should force full rebuild. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 572 | // Step 5: Verify ALL recipients present (12 original + 2 new = 14). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 602 | // Step 1: Full export to create all tables. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 607 | // Step 2: Remove the messages directory (simulate corruption/partial failure). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 616 | // Step 3: Build again — messages are missing but other tables exist. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1226 | // Step 1: Full rebuild to create metadata parquet (sources, labels, etc.). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1232 | // Step 2: Verify non-message parquet was created. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1237 | // Step 3: Run non-full build — should skip, NOT trigger another full rebuild. | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 565 | // Step 1: Drill into alice (top-level, creates drillFilter with TimeMonth default) | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 574 | // Step 2: Tab to sub-aggregate view | COMMENT |
| LOW | internal/tui/nav_view_test.go | 589 | // Step 3: Enter on "2024" — this was the bug | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 234 | // Step 1: Drill down to message list (sets contextStats from alice's row) | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 245 | // Step 2: Press Tab to go to sub-aggregate view (contextStats saved in breadcrumb) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 257 | // Step 3: Drill down from sub-aggregate to message list (contextStats overwritten) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 264 | // Step 4: Go back to sub-aggregate (contextStats should be restored to alice's stats) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 431 | // Step 1: Drill down from top-level to message list (Enter on alice) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 436 | // Step 2: Go to sub-aggregate view (Tab) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 445 | // Step 3: Select an aggregate in sub-aggregate view, then drill down with Enter | COMMENT |
| LOW | internal/vector/embed/worker.go | 453 | // Step 1: upsert embeddings (VectorsDB side). | COMMENT |
| LOW | internal/vector/embed/worker.go | 475 | // Step 2: atomically skip-mark empty/missing rows and remove their stale | COMMENT |
| LOW | scripts/update-nix-flake.sh | 43 | # Step 1: Update version in nix/package.nix if a version tag was provided | COMMENT |
| LOW | scripts/update-nix-flake.sh | 57 | # Step 2: Compute the correct vendorHash | COMMENT |
| LOW⚡ | scripts/update-nix-flake.sh | 83 | # Step 3: Verify it actually builds | COMMENT |
| LOW⚡ | scripts/update-nix-flake.sh | 93 | # Step 4: Commit and open PR | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | cmd/msgvault/cmd/quickstart.md | 286 | api_key = "your-api-key" | CODE |
| HIGH | docs/guides/remote-deployment.md | 153 | --to http://nas-ip:8080 --api-key YOUR_API_KEY --allow-insecure | CODE |
| HIGH | docs/guides/remote-deployment.md | 170 | export MSGVAULT_REMOTE_API_KEY=YOUR_API_KEY | CODE |
| HIGH | docs/guides/remote-deployment.md | 196 | curl -X POST -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/sync/you@gmail.com | CODE |
| HIGH | docs/guides/remote-deployment.md | 199 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/scheduler/status | CODE |
| HIGH | docs/guides/remote-deployment.md | 219 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/scheduler/status | CODE |
| HIGH | docs/guides/remote-deployment.md | 250 | api_key = "YOUR_API_KEY" | CODE |
| HIGH | docs/guides/remote-deployment.md | 399 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/accounts | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | CLAUDE.md | 34 | │ ├── sync/ # Sync orchestration | CODE |
| MEDIUM | internal/api/handlers_test.go | 6109 | // can't fetch raw MIME (Postgres scaffold, remote engine) surface a stable | COMMENT |
| MEDIUM | docs/usage/vector-search.md | 173 | ### Matching `max_input_chars` to your embedder's context window | COMMENT |
| MEDIUM⚡ | docs/architecture/overview.md | 24 | │ ├── calsync/ # Google Calendar sync orchestration | CODE |
| MEDIUM⚡ | docs/architecture/overview.md | 25 | │ ├── sync/ # Sync orchestration | CODE |
| MEDIUM⚡ | docs/architecture/overview.md | 27 | │ ├── importer/ # Local email import orchestration | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | internal/vector/pgvector/backend.go | 804 | // is robust under a busy pool. SET LOCAL is tx-scoped so the disabled timeout | COMMENT |
| MEDIUM | internal/store/store.go | 62 | // This is more robust than strings.Contains on err.Error() because it first | COMMENT |
| MEDIUM | internal/store/api.go | 141 | // Use scanMessageRows for robust date parsing | COMMENT |
| MEDIUM | internal/store/dialect_pg.go | 155 | // robust against multibyte input that the SQL char cap cannot bound) and | COMMENT |
| MEDIUM | internal/store/dialect_sqlite.go | 392 | // the result code is more robust than substring matching: BUSY surfaces as | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | docs/screenshots/generate-screenshots.sh | 49 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 51 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 271 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 273 | # ===================== | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | scripts/release.sh | 43 | # Create a temp file for the changelog | COMMENT |
| MEDIUM | scripts/release.sh | 68 | # Create the tag with changelog as message | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/screenshots/generate_demo_data.py | 331 | def get_or_create_participant(conn: sqlite3.Connection, email: str, name: str | None = None) -> int: | STRING |
| LOW | docs/scripts/check_built_site.py | 341 | def check_expected_asset_files() -> None: | CODE |
| LOW | docs/scripts/check_built_site.py | 359 | def check_fragment_nav_labels(current: pathlib.Path, parser: LinkParser) -> None: | CODE |
| LOW | docs/scripts/check_built_site.py | 369 | def check_public_site_file_inventory() -> None: | CODE |
| LOW | docs/scripts/check_vercel_redirects.py | 28 | def validate_finite_json_numbers(path: str, value: object) -> None: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/scripts/check_built_site.py | 2 | CODE | |
| LOW | docs/scripts/check_markdown_sources.py | 2 | CODE | |
| LOW | docs/scripts/check_vercel_redirects.py | 2 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/update-nix-flake.sh | 5 | # Usage: | COMMENT |
| LOW | scripts/testify-coverage-diff.sh | 3 | # Usage: | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/release.sh | 25 | # Check if tag already exists | COMMENT |
| LOW | scripts/release.sh | 37 | # Check if gh CLI is available | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/scripts/check_built_site.py | 382 | CODE |