From 8f06e3c78d0a651f3d369440bc262a4a0589e486 Mon Sep 17 00:00:00 2001 From: isink17 <39876158+isink17@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:08:43 +0200 Subject: [PATCH 1/4] cli/index: stabilize --jsonl scan event envelopes with repo/scan correlation fields --- internal/cli/app.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/internal/cli/app.go b/internal/cli/app.go index 6e78e38..3f83693 100644 --- a/internal/cli/app.go +++ b/internal/cli/app.go @@ -629,6 +629,9 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName scanKind := map[bool]string{true: "update", false: "index"}[update] if err := writeJSONL(stdout, map[string]any{ "type": "scan_summary", + "repo_root": repo.RootPath, + "repo_id": summary.RepoID, + "scan_id": summary.ScanID, "command": scanKind, "scan_kind": scanKind, "data": summary, @@ -636,7 +639,10 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName return err } _ = writeJSONL(stdout, map[string]any{ - "type": "scan_phases", + "type": "scan_phases", + "repo_root": repo.RootPath, + "repo_id": summary.RepoID, + "scan_id": summary.ScanID, "data": map[string]any{ "existing_load_ms": summary.ExistingLoadMS, "walk_ms": summary.WalkMS, @@ -656,8 +662,11 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName }, }) return writeJSONL(stdout, map[string]any{ - "type": "scan_stats", - "data": stats, + "type": "scan_stats", + "repo_root": repo.RootPath, + "repo_id": summary.RepoID, + "scan_id": summary.ScanID, + "data": stats, }) } return writeJSON(stdout, map[string]any{"summary": summary, "stats": stats}) From db46b13445ef62e31d1895c179d52c0f35494e48 Mon Sep 17 00:00:00 2001 From: isink17 <39876158+isink17@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:14:40 +0200 Subject: [PATCH 2/4] cli/index: dedupe JSONL scan event envelopes and handle scan_phases write errors --- internal/cli/app.go | 76 ++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/internal/cli/app.go b/internal/cli/app.go index 3f83693..c0f4b1f 100644 --- a/internal/cli/app.go +++ b/internal/cli/app.go @@ -627,47 +627,45 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName } if jsonl { scanKind := map[bool]string{true: "update", false: "index"}[update] - if err := writeJSONL(stdout, map[string]any{ - "type": "scan_summary", - "repo_root": repo.RootPath, - "repo_id": summary.RepoID, - "scan_id": summary.ScanID, - "command": scanKind, - "scan_kind": scanKind, - "data": summary, - }); err != nil { + envelope := func(eventType string) map[string]any { + return map[string]any{ + "type": eventType, + "repo_root": repo.RootPath, + "repo_id": summary.RepoID, + "scan_id": summary.ScanID, + } + } + ev := envelope("scan_summary") + ev["command"] = scanKind + ev["scan_kind"] = scanKind + ev["data"] = summary + if err := writeJSONL(stdout, ev); err != nil { return err } - _ = writeJSONL(stdout, map[string]any{ - "type": "scan_phases", - "repo_root": repo.RootPath, - "repo_id": summary.RepoID, - "scan_id": summary.ScanID, - "data": map[string]any{ - "existing_load_ms": summary.ExistingLoadMS, - "walk_ms": summary.WalkMS, - "process_wall_ms": summary.ProcessWallMS, - "task_ms": summary.TaskMS, - "task_other_ms": summary.TaskOtherMS, - "parse_ms": summary.ParseMS, - "read_ms": summary.ReadMS, - "hash_ms": summary.HashMS, - "write_ms": summary.WriteMS, - "write_metadata_ms": summary.WriteMetadataMS, - "write_replace_ms": summary.WriteReplaceMS, - "embed_ms": summary.EmbedMS, - "mark_missing_ms": summary.MarkMissingMS, - "resolve_ms": summary.ResolveMS, - "duration_ms": summary.DurationMS, - }, - }) - return writeJSONL(stdout, map[string]any{ - "type": "scan_stats", - "repo_root": repo.RootPath, - "repo_id": summary.RepoID, - "scan_id": summary.ScanID, - "data": stats, - }) + ev = envelope("scan_phases") + ev["data"] = map[string]any{ + "existing_load_ms": summary.ExistingLoadMS, + "walk_ms": summary.WalkMS, + "process_wall_ms": summary.ProcessWallMS, + "task_ms": summary.TaskMS, + "task_other_ms": summary.TaskOtherMS, + "parse_ms": summary.ParseMS, + "read_ms": summary.ReadMS, + "hash_ms": summary.HashMS, + "write_ms": summary.WriteMS, + "write_metadata_ms": summary.WriteMetadataMS, + "write_replace_ms": summary.WriteReplaceMS, + "embed_ms": summary.EmbedMS, + "mark_missing_ms": summary.MarkMissingMS, + "resolve_ms": summary.ResolveMS, + "duration_ms": summary.DurationMS, + } + if err := writeJSONL(stdout, ev); err != nil { + return err + } + ev = envelope("scan_stats") + ev["data"] = stats + return writeJSONL(stdout, ev) } return writeJSON(stdout, map[string]any{"summary": summary, "stats": stats}) } From 4d188a060cfcbac56ac5a4a8102d75a015bf7902 Mon Sep 17 00:00:00 2001 From: isink17 <39876158+isink17@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:31:10 +0200 Subject: [PATCH 3/4] doctor: always emit applied_fixes and recommendations arrays in JSON output --- internal/doctor/doctor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/doctor/doctor.go b/internal/doctor/doctor.go index 9155f94..bcc0507 100644 --- a/internal/doctor/doctor.go +++ b/internal/doctor/doctor.go @@ -29,8 +29,8 @@ type Report struct { SQLiteDriver string `json:"sqlite_driver"` DB *DBInfo `json:"db,omitempty"` Deep *DeepInfo `json:"deep,omitempty"` - AppliedFixes []string `json:"applied_fixes,omitempty"` - Recommendations []string `json:"recommendations,omitempty"` + AppliedFixes []string `json:"applied_fixes"` + Recommendations []string `json:"recommendations"` } type DBInfo struct { From 9fb72536a74a2ff20bdc5b5c220105ec0f1bd914 Mon Sep 17 00:00:00 2001 From: isink17 <39876158+isink17@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:42:20 +0200 Subject: [PATCH 4/4] cli/index: dedupe JSONL scan event data fields (use envelope for repo/scan correlation) --- internal/cli/app.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/internal/cli/app.go b/internal/cli/app.go index c0f4b1f..adaf3b7 100644 --- a/internal/cli/app.go +++ b/internal/cli/app.go @@ -635,10 +635,28 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName "scan_id": summary.ScanID, } } + stripEnvelopeKeys := func(v any, keys ...string) (map[string]any, error) { + b, err := json.Marshal(v) + if err != nil { + return nil, err + } + var out map[string]any + if err := json.Unmarshal(b, &out); err != nil { + return nil, err + } + for _, k := range keys { + delete(out, k) + } + return out, nil + } ev := envelope("scan_summary") ev["command"] = scanKind ev["scan_kind"] = scanKind - ev["data"] = summary + summaryData, err := stripEnvelopeKeys(summary, "repo_id", "scan_id") + if err != nil { + return err + } + ev["data"] = summaryData if err := writeJSONL(stdout, ev); err != nil { return err } @@ -664,7 +682,11 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName return err } ev = envelope("scan_stats") - ev["data"] = stats + statsData, err := stripEnvelopeKeys(stats, "repo_root", "repo_id") + if err != nil { + return err + } + ev["data"] = statsData return writeJSONL(stdout, ev) } return writeJSON(stdout, map[string]any{"summary": summary, "stats": stats})