feat(worker): week report prompt builder (day-major pivot)
This commit is contained in:
71
src/ClaudeDo.Worker/Report/WeekReportPromptBuilder.cs
Normal file
71
src/ClaudeDo.Worker/Report/WeekReportPromptBuilder.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace ClaudeDo.Worker.Report;
|
||||
|
||||
public static class WeekReportPromptBuilder
|
||||
{
|
||||
private const string Instructions = """
|
||||
You are generating a concise weekly standup report for a software developer.
|
||||
Summarize what they accomplished between {0} and {1}.
|
||||
|
||||
Rules:
|
||||
- Write the ENTIRE report in German.
|
||||
- Group by day. One "## {{Wochentag}}, {{dd.MM.yyyy}}" section per day that has
|
||||
activity (German weekday names). Omit days with no activity entirely.
|
||||
- Within each day: 3-5 first-person, past-tense bullets ("- Habe X umgesetzt",
|
||||
"- Y behoben"). Merge related small work into one bullet.
|
||||
- Drop trivia: typo fixes, pure exploration, false starts, tooling/log noise.
|
||||
- Blend the developer's own notes and the derived activity into ONE deduplicated
|
||||
bullet list per day. The developer's notes are authoritative - never omit or
|
||||
contradict their substance.
|
||||
- Name the project/repo when it adds clarity.
|
||||
- Output ONLY the dated sections. No preamble, no intro, no closing remarks.
|
||||
""";
|
||||
|
||||
public static string Build(
|
||||
DateOnly start, DateOnly end,
|
||||
IReadOnlyList<RepoActivity> activity,
|
||||
IReadOnlyDictionary<DateOnly, List<string>> notesByDay)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(string.Format(CultureInfo.InvariantCulture, Instructions,
|
||||
start.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture),
|
||||
end.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture)));
|
||||
sb.AppendLine();
|
||||
|
||||
var days = new SortedDictionary<DateOnly, List<(string Repo, DayActivity Day)>>();
|
||||
foreach (var repo in activity)
|
||||
foreach (var day in repo.Days)
|
||||
{
|
||||
if (!days.TryGetValue(day.Date, out var list))
|
||||
days[day.Date] = list = new();
|
||||
list.Add((repo.RepoPath, day));
|
||||
}
|
||||
foreach (var d in notesByDay.Keys)
|
||||
if (!days.ContainsKey(d)) days[d] = new();
|
||||
|
||||
sb.AppendLine("== Activity (from session history) ==");
|
||||
foreach (var (date, repos) in days)
|
||||
{
|
||||
sb.AppendLine($"### {date:yyyy-MM-dd}");
|
||||
foreach (var (repoPath, day) in repos)
|
||||
{
|
||||
sb.AppendLine($"Repo: {repoPath}");
|
||||
foreach (var p in day.Prompts) sb.AppendLine($" Prompt: {p}");
|
||||
foreach (var s in day.Summaries) sb.AppendLine($" Summary: {s}");
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
sb.AppendLine("== Developer notes ==");
|
||||
foreach (var (date, _) in days)
|
||||
{
|
||||
if (!notesByDay.TryGetValue(date, out var notes) || notes.Count == 0) continue;
|
||||
sb.AppendLine($"### {date:yyyy-MM-dd}");
|
||||
foreach (var n in notes) sb.AppendLine($" - {n}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using ClaudeDo.Worker.Report;
|
||||
|
||||
namespace ClaudeDo.Worker.Tests.Report;
|
||||
|
||||
public class WeekReportPromptBuilderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Build_IsDayMajor_AndIncludesNotesAndInstructions()
|
||||
{
|
||||
var repoA = new RepoActivity { RepoPath = @"C:\Dev\App" };
|
||||
var d1 = new DayActivity { Date = new DateOnly(2026, 6, 1) };
|
||||
d1.Prompts.Add("Add login");
|
||||
d1.Summaries.Add("Implemented login");
|
||||
repoA.Days.Add(d1);
|
||||
var d2 = new DayActivity { Date = new DateOnly(2026, 6, 2) };
|
||||
d2.Prompts.Add("Fix bug");
|
||||
repoA.Days.Add(d2);
|
||||
|
||||
var notes = new Dictionary<DateOnly, List<string>>
|
||||
{
|
||||
[new DateOnly(2026, 6, 1)] = new() { "Standup um 9" },
|
||||
};
|
||||
|
||||
var prompt = WeekReportPromptBuilder.Build(
|
||||
new DateOnly(2026, 5, 28), new DateOnly(2026, 6, 3),
|
||||
new[] { repoA }, notes);
|
||||
|
||||
Assert.Contains("Write the ENTIRE report in German", prompt);
|
||||
var idxJun1 = prompt.IndexOf("2026-06-01", StringComparison.Ordinal);
|
||||
var idxJun2 = prompt.IndexOf("2026-06-02", StringComparison.Ordinal);
|
||||
Assert.True(idxJun1 >= 0 && idxJun2 > idxJun1);
|
||||
Assert.Contains("Add login", prompt);
|
||||
Assert.Contains("Implemented login", prompt);
|
||||
Assert.Contains("Standup um 9", prompt);
|
||||
Assert.Contains(@"C:\Dev\App", prompt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user