Skip to content

bug: regenerateArtifacts silently skips summary.md when summary.json is missing #534

@galexy

Description

@galexy

Symptom

ox session regenerate <name> (default mode) regenerates markdown artifacts from a session's raw.jsonl. session.md gets regenerated unconditionally, but summary.md is only written if summary.json already exists in the session directory. If summary.json is missing, summary.md is silently skipped — no warning, no fallback template.

Evidence

Reproduced during #519 investigation. Recreated a session in cache with only raw.jsonl, ran ox session regenerate <name>. Output claimed success:

✓ Regenerated artifacts for 2026-04-19T05-59-galexy-OxBkup

But on disk:

-rw-r--r--  raw.jsonl         250496 bytes
-rw-r--r--  session.md        100428 bytes   ← regenerated
                                            ← no summary.md

No warning that summary.md wasn't written. Only session.md was produced.

Root cause

cmd/ox/session_regenerate.go:691-706:

// summary.md — regenerate from summary.json if available
summaryJSONPath := filepath.Join(sessionPath, "summary.json")
if data, err := os.ReadFile(summaryJSONPath); err == nil {
    var summaryResp session.SummarizeResponse
    if json.Unmarshal(data, &summaryResp) == nil {
        summaryView := session.SummarizeResponseToSummaryView(&summaryResp)
        summaryMdGen := session.NewSummaryMarkdownGenerator()
        summaryMdBytes, err := summaryMdGen.Generate(rawSession.Meta, summaryView, rawSession.Entries)
        if err == nil {
            summaryMdPath := filepath.Join(sessionPath, ledgerFileSummaryMD)
            if writeErr := os.WriteFile(summaryMdPath, summaryMdBytes, 0644); writeErr != nil {
                errs = append(errs, ...)
            }
        }
    }
}

Three silent-skip points:

  1. summary.json doesn't exist → outer if skips. No fallback.
  2. summary.json fails to unmarshal → inner if skips. Error not collected.
  3. summaryMdGen.Generate fails → skip. Error not collected.

Only write errors get added to errs and surfaced to the user.

Impact

  • Users rebuilding a session from raw.jsonl (e.g., recovering from data loss, importing prior history) get session.md but no summary.md. They don't know this unless they check.
  • To get summary.md, users must either have an existing summary.json or run ox session regenerate --summary — which invokes claude as a subprocess (requires the CLI, uses LLM tokens, may take minutes).
  • There's no template-based fallback for summary.md even though session.md has a perfectly good template-based generation path (NewMarkdownGenerator).
  • Contrast with ox agent session import (cmd/ox/agent_session_plan_history.go:148-157) which DOES generate a template-based summary.md without an LLM:
summaryMDGen := session.NewSummaryMarkdownGenerator()
summaryBytes, summaryErr := summaryMDGen.Generate(stored.Meta, nil, stored.Entries)
//                                                             ^^^ nil SummaryView works

The generator accepts a nil SummaryView and produces a structural summary.md from meta + entries alone. regenerate gates on a non-existent summary.json for no real reason.

Fix direction

In regenerateArtifacts, always generate summary.md:

  1. If summary.json exists and parses → generate with the rich summary view.
  2. Otherwise → generate with nil SummaryView (structural fallback). Same behavior as session import.

Also surface the three silent-skip points as warnings at minimum — users should know when a file they expect didn't get written.

Acceptance

  • Running ox session regenerate <name> on a session with no summary.json produces a non-empty summary.md.
  • The output of regenerate either reports which artifacts were written or warns which were skipped — no silent partials.
  • Test fixture covers: session dir with only raw.jsonl → both session.md and summary.md produced.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions