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 summarizes scanner evidence for kenn-io/msgvault, a Go project with 2,173 GitHub stars. SynthScan examined 1,492,907 lines of code across 4124 source files, recording 1715 pattern matches distributed across 13 syntactic categories. The legacy adjusted pattern signal is 1.3 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 910 finding(s).
Are imports declared and package/API names verified? 801 finding(s).
Are wrappers, guards, and repeated structures necessary? 57 finding(s).
Which changes need focused human review? 1715 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 1715 distinct pattern matches across 13 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. 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 configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | cmd/msgvault/cmd/deletions_test.go | 767 | account := "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/muesli_remote_test.go | 43 | source := meetingimport.Source{Identifier: "recorder", AccountEmail: "user@example.com"} | CODE |
| LOW | cmd/msgvault/cmd/muesli_remote_test.go | 140 | source := meetingimport.Source{Identifier: "recorder", AccountEmail: "user@example.com"} | CODE |
| LOW | cmd/msgvault/cmd/serve_account_catalog_test.go | 58 | require.NoError(st.AddAccountIdentity(src.ID, "work@example.org", "manual")) | CODE |
| LOW | cmd/msgvault/cmd/serve_account_catalog_test.go | 59 | assert.Equal(t, []string{"work@example.org"}, addresses()) | CODE |
| LOW | cmd/msgvault/cmd/store_adapter_test.go | 468 | "account_email": "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/meeting_import_e2e_test.go | 27 | "account_email": "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/serve_api_wiring_test.go | 38 | source, err := st.GetOrCreateSource("gmail", "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/serve_archive_sql_test.go | 20 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/root_test.go | 442 | Expected: "user@example.com", | CODE |
| LOW | cmd/msgvault/cmd/root_test.go | 454 | _, err := getTokenSourceWithReauth(context.Background(), mock, "user@example.com", true, gmailReauthHint) | CODE |
| LOW | cmd/msgvault/cmd/muesli_watch_test.go | 62 | cfg.Muesli = []config.MuesliSource{{DBPath: filepath.Join(t.TempDir(), "muesli.db"), Contacts: &off, Identifier: "recor | CODE |
| LOW | cmd/msgvault/cmd/muesli_watch_test.go | 153 | cfg.Muesli = []config.MuesliSource{{Identifier: "recorder", AccountEmail: "user@example.com", DBPath: path, Contacts: & | CODE |
| LOW | cmd/msgvault/cmd/muesli_watch_test.go | 173 | cfg.Muesli = []config.MuesliSource{{Identifier: "recorder", AccountEmail: "user@example.com", DBPath: filepath.Join(t.T | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 46 | require.NoError(st.AddAccountIdentity(src.ID, "work@example.org", "manual")) | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 47 | require.NoError(st.AddAccountIdentity(src.ID, "mask@example.org", "manual")) | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 50 | for _, header := range []string{"X-Delivered-To: work@example.org", "X-Delivered-To: mask@example.org", "X-Delivered- | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 59 | require.NoError(st.UpdateSourceSyncConfig(calendar.ID, `{"account_email":"work@example.org","calendar_id":"primary"}` | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 60 | require.NoError(st.AddAccountIdentity(calendar.ID, "work@example.org", "manual")) | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 75 | "account:work@example.org": 2, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 76 | "received:work@example.org": 1, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 77 | "account:mask@example.org": 1, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 78 | "received:work@example.org received:mask@example.org": 2, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 79 | "account:work@example.org received:work@example.org": 1, | CODE |
| LOW | cmd/msgvault/cmd/account_attribution_test.go | 112 | for _, address := range []string{"work@example.org", "mask@example.org"} { | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 154 | require.NoError(st.AddAccountIdentity(src.ID, "work@example.org", "manual")) | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 155 | require.NoError(st.AddAccountIdentity(src.ID, "mask@example.org", "manual")) | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 158 | for _, header := range []string{"X-Delivered-To: work@example.org", "X-Delivered-To: mask@example.org", "X-Original-To: | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 175 | "identity": {{SourceID: &source, Addresses: []string{"work@example.org"}}}, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 177 | "inbound": {{Addresses: []string{"work@example.org", "mask@example.org"}, Inbound: true}}, | CODE |
| LOW⚡ | cmd/msgvault/cmd/account_attribution_test.go | 178 | "intersect": {{Addresses: []string{"work@example.org", "mask@example.org"}}, {Addresses: []string{"mask@example.org | CODE |
| LOW | cmd/msgvault/cmd/imap_folder_state_sync_test.go | 75 | IMAPSkipFolders: map[string][]string{src.Identifier: {"Trash", "Junk"}, "user@example.com": {"Trash"}}, | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 861 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 903 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1001 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1046 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1174 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1192 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1424 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 1515 | INSERT INTO sources (id, source_type, identifier) VALUES (1, 'gmail', 'user@example.com'); | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2313 | Args: []string{"add-account", "user@example.com", "--readonly"}, | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2334 | "add-account", "user@example.com", "--readonly", "--grant-decided=true", | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2336 | assert.Equal(t, []string{"add-account", "user@example.com", "--readonly"}, req.Args, | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2933 | imapEmail = "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2982 | imapEmail = "user@example.com" | CODE |
| LOW | cmd/msgvault/cmd/serve_test.go | 2988 | `{"host":"127.0.0.1","port":1,"username":"user@example.com","tls":true}`, | CODE |
| LOW⚡ | cmd/msgvault/cmd/serve_test.go | 3167 | "user@example.com": {Media: &enabled, MaxMediaMB: 7}, | CODE |
| LOW⚡ | cmd/msgvault/cmd/serve_test.go | 3174 | opts := scheduledTeamsImportOptions("user@example.com", cfg) | CODE |
| LOW⚡ | cmd/msgvault/cmd/serve_test.go | 3175 | assert.Equal(t, cfg.Teams.MediaPolicy("user@example.com"), opts.MediaPolicy) | CODE |
| LOW | cmd/msgvault/cmd/muesli_client_test.go | 53 | clientCfg.Muesli = []config.MuesliSource{{Identifier: "recorder", AccountEmail: "user@example.com", DBPath: path, Conta | CODE |
| LOW | cmd/msgvault/cmd/muesli_client_test.go | 162 | clientCfg.Muesli = append(clientCfg.Muesli, config.MuesliSource{Identifier: configured.identifier, AccountEmail: "us | CODE |
| LOW | cmd/msgvault/cmd/muesli_client_test.go | 241 | _, err := muesli.NewImporter(st).ImportRemote(t.Context(), muesli.RemoteRequest{Action: "register", Source: meetingim | CODE |
| LOW | cmd/msgvault/cmd/muesli_client_test.go | 288 | clientCfg.Muesli = []config.MuesliSource{{Identifier: "recorder", AccountEmail: "user@example.com", DBPath: path, Con | CODE |
| LOW | cmd/msgvault/cmd/addaccount_identity_test.go | 38 | for _, email := range []string{"user@example.com", "User.Name+archive@gmail.com", "user@googlemail.com"} { | CODE |
| LOW | cmd/msgvault/cmd/addaccount_identity_test.go | 88 | for _, profile := range []string{"user@example.com", "other@example.com", "unavailable"} { | CODE |
| LOW | cmd/msgvault/cmd/addaccount_identity_test.go | 107 | tokenPath := oauth.TokenFilePath(cfg.TokensDir(), "user@example.com") | CODE |
| LOW | cmd/msgvault/cmd/addaccount_identity_test.go | 111 | source, err := s.GetOrCreateSource("gmail", "user@example.com") | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_identity_test.go | 125 | cmd.SetArgs([]string{"user@example.com", "--display-name", "Updated", "--no-default-identity"}) | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_identity_test.go | 127 | if profile == "user@example.com" { | CODE |
| LOW⚡ | cmd/msgvault/cmd/addaccount_identity_test.go | 129 | source, err := findGmailSource(s, "user@example.com") | CODE |
| 728 more matches not shown… | ||||
| 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/eval_fts_production_test.go | 21 | ) | COMMENT |
| LOW | cmd/msgvault/cmd/eval_fts_production_test.go | 101 | // | COMMENT |
| LOW | cmd/msgvault/cmd/serve_vector.go | 461 | return fmt.Errorf("invalid multimodal cron expression %q: %w", cronExpr, err) | COMMENT |
| LOW | cmd/msgvault/cmd/serve_vector.go | 481 | // store.OpenReadOnly. On PostgreSQL it sets BOTH pgvector.Options.SkipMigrate | COMMENT |
| LOW | cmd/msgvault/cmd/store_resolver.go | 61 | if res.Notice != "" { | COMMENT |
| LOW | cmd/msgvault/cmd/store_resolver.go | 341 | COMMENT | |
| LOW | cmd/msgvault/cmd/serve.go | 4141 | func (a *schedulerAdapter) TriggerJob(name string) error { | COMMENT |
| LOW | cmd/msgvault/cmd/eval_topics_test.go | 41 | text := done() | COMMENT |
| LOW | cmd/msgvault/cmd/imap_folder_state_sync_test.go | 661 | } | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 101 | // maintenance (lockCacheAndInvalidateSyncState) for its whole operation. | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 601 | MaxMessageID int64 | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 961 | // conversation-type, participant-identifier, participant or person display-name drift | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 1101 | // Read the identity revision and computed participant clusters through | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache.go | 2361 | COMMENT | |
| LOW | cmd/msgvault/cmd/repair_encoding.go | 141 | // s.ResetEmbedGen clears embed_gen. Opening a writable backend runs the | COMMENT |
| LOW | cmd/msgvault/cmd/embed_scope.go | 81 | } | COMMENT |
| LOW | cmd/msgvault/cmd/eval_qrels_test.go | 41 | evalQrels = writeEvalFile(t, dir, "qrels.txt", qrels) | COMMENT |
| LOW | cmd/msgvault/cmd/account_identity.go | 81 | // opt-out, so scheduled sync and later add-command reruns cannot restore the | COMMENT |
| LOW | cmd/msgvault/cmd/deduplicate.go | 1061 | // backupDatabase writes a point-in-time consistent copy of the SQLite | COMMENT |
| LOW | cmd/msgvault/cmd/deletions.go | 881 | }, nil | COMMENT |
| LOW | cmd/msgvault/cmd/deletions.go | 1741 | } | COMMENT |
| LOW | cmd/msgvault/cmd/daemon_runtime.go | 541 | // createTimeComparison distinguishes exact process identity from tolerated | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector.go | 21 | // Opening a writable backend runs the one-time upgrade backfill | COMMENT |
| LOW | cmd/msgvault/cmd/repair_encoding_vector.go | 81 | // row below the watermark would otherwise wait for a full-scan backstop (which | COMMENT |
| LOW | cmd/msgvault/cmd/calendar.go | 141 | // A token that exists, carries the calendar scope, and matches the | COMMENT |
| LOW | cmd/msgvault/cmd/cache_staleness.go | 41 | // HasConversationParticipantDrift signals conversation membership changed | COMMENT |
| LOW | cmd/msgvault/cmd/cache_staleness.go | 61 | // escalates to a full rebuild when new messages coincide: incremental | COMMENT |
| LOW | cmd/msgvault/cmd/cache_staleness.go | 121 | // cacheNeedsBuild checks if the analytics cache needs to be built or | COMMENT |
| LOW | cmd/msgvault/cmd/cache_staleness.go | 501 | reasons = append(reasons, "derived message data changed") | COMMENT |
| LOW | cmd/msgvault/cmd/import_mbox.go | 321 | // whenever the legacy [identity] block had populated rows. | COMMENT |
| LOW | cmd/msgvault/cmd/vector_features.go | 21 | Worker *visual.Worker | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 181 | } | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 241 | // readonlyGrantWarning checks what actually came back after a --readonly | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 721 | } | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 761 | // Err refuses the run outright. | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 801 | if readonly { | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 841 | "Re-run with --readonly to keep the narrower grant.", | COMMENT |
| LOW | cmd/msgvault/cmd/addaccount.go | 921 | } | 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 | …t/cmd/serve_vector_precheck_mainpath_sqlitevec_test.go | 1 | //go:build sqlite_vec | COMMENT |
| LOW | cmd/msgvault/cmd/build_cache_test.go | 1001 | COMMENT | |
| LOW | cmd/msgvault/cmd/build_cache_test.go | 4041 | COMMENT | |
| LOW | cmd/msgvault/cmd/person_provider.go | 581 | } | COMMENT |
| LOW | cmd/msgvault/cmd/cache_text.go | 101 | // cacheTextSQL returns valid VARCHAR while keeping NULL. DuckDB's native | COMMENT |
| LOW | cmd/msgvault/cmd/embed_vector_test.go | 1081 | // event is different from the cumulative rate the old printer | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 201 | column string | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 221 | // keys — see eval.OverFetchPlan and evaluator.rankedKeys. | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 281 | UnhydratedHits int `json:"unhydrated_hits,omitempty"` | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 301 | COMMENT | |
| LOW | cmd/msgvault/cmd/eval.go | 401 | // ftsSearcher is the production relevance-ranked full-text path. | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 441 | // keys are the doc keys in the engine's rank order, before collapsing; | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 481 | filled := len(deduped) >= e.limit | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 641 | // reasonable default for an interactive search box, where the user sees the | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 941 | // parseEvalModes splits and validates the --modes flag, keeping each mode once | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 981 | return modes, needVec, nil | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 1001 | // second, narrower fallback inside Store itself, forcing the same LIKE | COMMENT |
| LOW | cmd/msgvault/cmd/eval.go | 1041 | // clearly rather than pointing a sqlite-vec backend at a PG handle. | COMMENT |
| 709 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | cmd/msgvault/cmd/setup.go | 69 | // Step 1: Find or prompt for OAuth credentials | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 75 | // Step 2: Choose the timezone used for activity day boundaries. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 86 | // Step 3: Optionally configure remote NAS | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 92 | // Step 3: Persist choices made in the wizard, including values that match | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1909 | // Step 1: Initial full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1914 | // Step 2: Add new messages to SQLite, then incremental export. Publication | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1936 | // Step 3: Remove conversations dir (simulate legacy cache missing a table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1940 | // Step 4: Backfill — no new messages, but conversations is missing. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1946 | // Step 5: Verify exact counts — no duplicates from stale incremental shards. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1983 | // Step 1: Full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1987 | // Step 2: Delete message_recipients dir (simulate missing table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1991 | // Step 3: Add new messages to SQLite (so maxID > lastMessageID). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2004 | // Step 4: Build — missing table + new messages should force full rebuild. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2009 | // Step 5: Verify ALL recipients present (12 original + 2 new = 14). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2038 | // Step 1: Full export to create all tables. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2043 | // Step 2: Remove the messages directory (simulate corruption/partial failure). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2052 | // Step 3: Build again — messages are missing but other tables exist. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3406 | // Step 1: Full rebuild creates metadata plus a schema-compatible empty | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3412 | // Step 2: Verify non-message parquet was created. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3417 | // Step 3: Run non-full build — should skip, NOT trigger another full rebuild. | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 631 | // Step 1: Drill into alice (top-level, creates drillFilter with TimeMonth default) | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 640 | // Step 2: Tab to sub-aggregate view | COMMENT |
| LOW | internal/tui/nav_view_test.go | 655 | // Step 3: Enter on "2024" — this was the bug | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 285 | // Step 1: Drill down to message list (sets contextStats from alice's row) | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 296 | // Step 2: Press Tab to go to sub-aggregate view (contextStats saved in breadcrumb) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 308 | // Step 3: Drill down from sub-aggregate to message list (contextStats overwritten) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 315 | // Step 4: Go back to sub-aggregate (contextStats should be restored to alice's stats) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 470 | // Step 1: Drill down from top-level to message list (Enter on alice) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 475 | // Step 2: Go to sub-aggregate view (Tab) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 484 | // Step 3: Select an aggregate in sub-aggregate view, then drill down with Enter | COMMENT |
| LOW | internal/api/agent_tokens_test.go | 697 | // Step 1: issue a grant via HTTP. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 717 | // Step 2: prove the token authenticates. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 724 | // Step 3: revoke via HTTP. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 731 | // Step 4: prove the token no longer authenticates. | COMMENT |
| LOW | internal/vector/embed/worker.go | 540 | // Step 1: upsert embeddings (VectorsDB side). | COMMENT |
| LOW | internal/vector/embed/worker.go | 565 | // Step 2: atomically skip-mark empty/missing rows and remove their stale | COMMENT |
| LOW | docs/guides/oauth-setup.md | 40 | ### Step 1: Create a Google Cloud Project | COMMENT |
| LOW | docs/guides/oauth-setup.md | 55 | ### Step 2: Enable Google APIs | COMMENT |
| LOW | docs/guides/oauth-setup.md | 71 | ### Step 3: Configure OAuth Consent Screen | COMMENT |
| LOW | docs/guides/oauth-setup.md | 149 | ### Step 4: Create OAuth Client Credentials | COMMENT |
| LOW | docs/guides/oauth-setup.md | 186 | ### Step 5: Configure msgvault | COMMENT |
| LOW | docs/guides/oauth-setup.md | 234 | ### Step 6: Add Your Account | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | cmd/msgvault/cmd/setup.go | 69 | // Step 1: Find or prompt for OAuth credentials | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 75 | // Step 2: Choose the timezone used for activity day boundaries. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 86 | // Step 3: Optionally configure remote NAS | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/setup.go | 92 | // Step 3: Persist choices made in the wizard, including values that match | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1909 | // Step 1: Initial full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1914 | // Step 2: Add new messages to SQLite, then incremental export. Publication | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1936 | // Step 3: Remove conversations dir (simulate legacy cache missing a table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1940 | // Step 4: Backfill — no new messages, but conversations is missing. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1946 | // Step 5: Verify exact counts — no duplicates from stale incremental shards. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1983 | // Step 1: Full export (5 messages, 12 recipients). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1987 | // Step 2: Delete message_recipients dir (simulate missing table). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 1991 | // Step 3: Add new messages to SQLite (so maxID > lastMessageID). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2004 | // Step 4: Build — missing table + new messages should force full rebuild. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2009 | // Step 5: Verify ALL recipients present (12 original + 2 new = 14). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2038 | // Step 1: Full export to create all tables. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2043 | // Step 2: Remove the messages directory (simulate corruption/partial failure). | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 2052 | // Step 3: Build again — messages are missing but other tables exist. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3406 | // Step 1: Full rebuild creates metadata plus a schema-compatible empty | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3412 | // Step 2: Verify non-message parquet was created. | COMMENT |
| LOW⚡ | cmd/msgvault/cmd/build_cache_test.go | 3417 | // Step 3: Run non-full build — should skip, NOT trigger another full rebuild. | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 631 | // Step 1: Drill into alice (top-level, creates drillFilter with TimeMonth default) | COMMENT |
| LOW⚡ | internal/tui/nav_view_test.go | 640 | // Step 2: Tab to sub-aggregate view | COMMENT |
| LOW | internal/tui/nav_view_test.go | 655 | // Step 3: Enter on "2024" — this was the bug | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 285 | // Step 1: Drill down to message list (sets contextStats from alice's row) | COMMENT |
| LOW | internal/tui/nav_drill_test.go | 296 | // Step 2: Press Tab to go to sub-aggregate view (contextStats saved in breadcrumb) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 308 | // Step 3: Drill down from sub-aggregate to message list (contextStats overwritten) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 315 | // Step 4: Go back to sub-aggregate (contextStats should be restored to alice's stats) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 470 | // Step 1: Drill down from top-level to message list (Enter on alice) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 475 | // Step 2: Go to sub-aggregate view (Tab) | COMMENT |
| LOW⚡ | internal/tui/nav_drill_test.go | 484 | // Step 3: Select an aggregate in sub-aggregate view, then drill down with Enter | COMMENT |
| LOW | internal/api/agent_tokens_test.go | 697 | // Step 1: issue a grant via HTTP. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 717 | // Step 2: prove the token authenticates. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 724 | // Step 3: revoke via HTTP. | COMMENT |
| LOW⚡ | internal/api/agent_tokens_test.go | 731 | // Step 4: prove the token no longer authenticates. | COMMENT |
| LOW | internal/vector/embed/worker.go | 540 | // Step 1: upsert embeddings (VectorsDB side). | COMMENT |
| LOW | internal/vector/embed/worker.go | 565 | // Step 2: atomically skip-mark empty/missing rows and remove their stale | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | web/src/lib/settings/google-authorization.ts | 56 | export function receiveGoogleContactsCallback(): boolean { | CODE |
| LOW | web/src/lib/carddav/navigation.ts | 16 | export function normalizeSettingsNavigationAuthority(value: unknown): SettingsNavigationAuthority | '' { | CODE |
| LOW | web/src/lib/archive/thread-window.ts | 8 | export function selectInclusiveThreadWindow( | CODE |
| LOW | web/src/lib/archive/url-state.ts | 26 | function freshDefaultArchiveURLState(): ArchiveURLState { | CODE |
| LOW | web/src/lib/saved-views/canonical.ts | 75 | export function exploreStateFromSavedView(saved: CanonicalState, schemaVersion = CURRENT_SCHEMA_VERSION): Partial<Explor | CODE |
| LOW | web/src/lib/content/sanitize.ts | 59 | function keepPresentationalAttributes(element: HTMLElement): void { | CODE |
| LOW | web/src/lib/content/sanitize.ts | 162 | function classifyRemoteImageSource(value: string): RemoteImageSource { | CODE |
| LOW | web/src/lib/operations/focus.ts | 43 | export function resolveOperationFocusAnchor( | CODE |
| LOW | web/src/lib/directory/person-merge.ts | 26 | export function isMatchingPersonRevisionETag( | CODE |
| LOW | web/src/lib/directory/person-merge.ts | 34 | export function validatePersonMergeRequired(value: unknown): ValidatedPersonMergeRequired | null { | CODE |
| LOW | web/src/lib/directory/person-merge.ts | 58 | export function isPersonMergeRevisionConflict(value: unknown): boolean { | CODE |
| LOW | web/src/lib/directory/profile-controller.svelte.ts | 728 | function hasUsableDefinitionIdentity(definition: Record<string, unknown>): definition is Record<string, unknown> & { | CODE |
| LOW | web/src/lib/directory/fact-ledger-controller.svelte.ts | 121 | export function evidenceStatusReasonLabel(reason: string): string { | CODE |
| LOW | web/src/lib/explore/selection.ts | 48 | export function createAllMatchingSelection( | CODE |
| LOW | web/src/lib/explore/group-context.ts | 55 | function appendGroupMembershipFilter( | CODE |
| LOW | web/src/lib/search/modes.ts | 49 | export function availableSearchModeStorage(): SearchModeStorage | null { | CODE |
| LOW | web/src/lib/search/modes.ts | 85 | export function explicitSearchModeFromURL(search: string, parameter = 'explore'): ExploreSearchMode | undefined { | CODE |
| LOW | web/src/lib/components/reader/inline-images.ts | 160 | export async function resolveArchivedInlineImages(options: { | CODE |
| LOW | web/src/lib/components/reader/remote-images.ts | 78 | export async function resolveArchivedRemoteImages(options: { | CODE |
| LOW | …c/lib/components/reader/ContentFrame.browser.svelte.ts | 22 | export function createArchivedContentMessageHandler( | CODE |
| LOW | web/src/lib/components/reader/inline-images.test.ts | 41 | async function resolveWithPublicationByteLimit( | CODE |
| LOW | …lib/components/settings/CardDAVAccountSettings.test.ts | 328 | function expectAccountControlsLocked(activeLabel: 'Testing…' | 'Saving…'): void { | CODE |
| LOW | …/src/lib/components/settings/SettingsWorkspace.test.ts | 1613 | function cardDAVOperationsResponse(request: Request): Response | undefined { | CODE |
| LOW | …/lib/components/settings/CardDAVAccountSettings.svelte | 113 | function canReusePersistedPassword(): boolean { | CODE |
| LOW | …/lib/components/settings/CardDAVAccountSettings.svelte | 118 | function canDisableWithoutPassword(): boolean { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.svelte | 253 | function replaceCommittedNavigation(patch: Partial<ExploreURLState>): void { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.svelte | 263 | function commitRestorableNavigation(patch: Partial<ExploreURLState>): void { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.svelte | 267 | function replaceCommittedRestorableNavigation(patch: Partial<ExploreURLState>): void { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.svelte | 276 | function openDirectoryFromRelationship(participantID: number): void { | CODE |
| LOW | web/src/lib/components/shell/AppShell.svelte | 347 | function openVisualAttachmentSettings(): void { | CODE |
| LOW | web/src/lib/components/shell/AppShell.svelte | 358 | function consumeCardDAVSettingsRequest(key: number): void { | CODE |
| LOW | web/src/lib/components/shell/AppShell.svelte | 786 | function syncEditableShortcutScope(target: EventTarget | null): void { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.test.ts | 47 | function documentIndexStatusResponse() { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.test.ts | 57 | function documentVectorStatusResponse() { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.test.ts | 61 | function visualAttachmentStatusResponse() { | CODE |
| LOW⚡ | web/src/lib/components/shell/AppShell.test.ts | 68 | function operationAuthorityResponse(path: string): Response | undefined { | CODE |
| LOW | …lib/components/directory/RelationshipTypeEditor.svelte | 110 | async function refreshAfterUncertainOutcome(): Promise<void> { | CODE |
| LOW | …/components/directory/OrganizationEmploymentTab.svelte | 63 | async function openRequestedOrganization(id: number): Promise<void> { | CODE |
| LOW | …/lib/components/directory/DirectoryReviewCentre.svelte | 92 | async function focusCurrentReviewSurface(): Promise<void> { | CODE |
| LOW | …b/components/directory/PersonRelationshipEditor.svelte | 199 | async function refreshAfterUncertainOutcome(): Promise<void> { | CODE |
| LOW | …ib/components/relationships/RelationshipHeader.test.ts | 71 | function clusteredPersonWithBareMember(): PersonSummary { | CODE |
| LOW | web/src/lib/theme/preferences.svelte.ts | 145 | export function createAppearancePreferences(defaults: AppearanceDefaults): AppearancePreferences { | CODE |
| LOW | web/src/lib/api/client.ts | 41 | export function createSessionAwareAPIClient( | CODE |
| LOW | web/src/lib/meetings/archive-selection.ts | 16 | export function parseArchiveMeetingSelection(value: string | null): number | undefined { | CODE |
| LOW | web/src/lib/meetings/archive-selection.ts | 21 | export function parseArchiveMeetingHistory(value: unknown, selectedRow: string | null): ArchiveMeetingHistory | undefine | CODE |
| LOW | web/src/lib/relationships/controller.svelte.ts | 920 | function relationshipCalendarCacheKey( | CODE |
| 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/internal/web-ui-overhaul-pr2-plan.md | 788 | export function exploreStateFromSavedView(saved: CanonicalState): Partial<ExploreURLState>; | CODE |
| LOW | docs/internal/web-ui-overhaul-pr4-plan.md | 1099 | function openVisualAttachmentSettings(): void { | CODE |
| LOW | docs/scripts/check_built_site.py | 395 | def check_expected_asset_files() -> None: | CODE |
| LOW | docs/scripts/check_built_site.py | 413 | def check_fragment_nav_labels(current: pathlib.Path, parser: LinkParser) -> None: | CODE |
| LOW | docs/scripts/check_built_site.py | 423 | def check_public_site_file_inventory(site: pathlib.Path = SITE) -> None: | CODE |
| LOW | docs/scripts/check_vercel_redirects.py | 50 | def validate_finite_json_numbers(path: str, value: object) -> None: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | cmd/msgvault/cmd/quickstart.md | 314 | api_key = "your-api-key" | CODE |
| HIGH | docs/guides/remote-deployment.md | 157 | --to http://nas-ip:8080 --api-key YOUR_API_KEY --allow-insecure | CODE |
| HIGH | docs/guides/remote-deployment.md | 176 | export MSGVAULT_REMOTE_API_KEY=YOUR_API_KEY | CODE |
| HIGH | docs/guides/remote-deployment.md | 202 | 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 | 205 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/scheduler/status | CODE |
| HIGH | docs/guides/remote-deployment.md | 225 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/scheduler/status | CODE |
| HIGH | docs/guides/remote-deployment.md | 266 | api_key = "YOUR_API_KEY" | CODE |
| HIGH | docs/guides/remote-deployment.md | 482 | curl -H "X-API-Key: YOUR_API_KEY" http://remote-host:8080/api/v1/accounts | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | internal/vector/pgvector/backend.go | 963 | // is robust under a busy pool. SET LOCAL is tx-scoped so the disabled timeout | COMMENT |
| MEDIUM | internal/store/migrate_recipient_envelope.go | 185 | // the current shape and there is nothing to rebuild — robust against | COMMENT |
| MEDIUM | internal/store/sqlite_errors_cgo.go | 14 | // This is more robust than strings.Contains on err.Error() because it first | COMMENT |
| MEDIUM | internal/store/sqlite_errors_cgo.go | 47 | // the result code is more robust than substring matching: BUSY surfaces as | COMMENT |
| MEDIUM | internal/store/api.go | 172 | // Use scanMessageRows for robust date parsing | COMMENT |
| MEDIUM | internal/store/dialect_pg.go | 441 | // robust against multibyte input that the SQL char cap cannot bound) and | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | docs/screenshots/generate-screenshots.sh | 50 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 52 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 277 | # ===================== | COMMENT |
| MEDIUM | docs/screenshots/generate-screenshots.sh | 279 | # ===================== | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | internal/api/media_search_test.go | 144 | f.docbank.server.Config.Handler.ServeHTTP(w, r) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | internal/api/handlers_test.go | 8384 | // can't fetch raw MIME (Postgres scaffold, remote engine) surface a stable | COMMENT |
| MEDIUM | docs/usage/vector-search.md | 302 | ### Matching `max_input_chars` to your embedder's context window | COMMENT |
| 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 | |
| LOW | docs/scripts/selftest_check_built_site.py | 8 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/testify-coverage-diff.sh | 3 | # Usage: | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/scripts/check_built_site.py | 436 | CODE |