Merge claudedo/05827da5ecde413e9a2fe8edd45c24a8

This commit is contained in:
mika kuns
2026-08-05 11:03:56 +02:00
4 changed files with 122 additions and 4 deletions
@@ -87,6 +87,15 @@ public class PromptFilesTests
Assert.DoesNotContain("whenever you are unsure", d);
}
[Fact]
public void DefaultFor_merge_helper_phase0_treats_brief_as_primary_source()
{
var d = PromptFiles.DefaultFor(PromptKind.MergeHelper);
Assert.Contains("primary source", d, StringComparison.OrdinalIgnoreCase);
Assert.Contains("batch_get_tasks", d);
Assert.Contains("Do not act on any single task before you have read", d);
}
[Fact]
public void DefaultFor_merge_helper_initial_has_repo_token()
{
@@ -88,13 +88,13 @@ public sealed class InteractiveLaunchSpecServiceTests : IDisposable
return listId;
}
private async Task SeedTaskAsync(string taskId, string listId, TaskStatus status, string? sessionSkillsJson = null, string title = "T")
private async Task SeedTaskAsync(string taskId, string listId, TaskStatus status, string? sessionSkillsJson = null, string title = "T", string? description = null)
{
using var ctx = _db.CreateContext();
await new TaskRepository(ctx).AddAsync(new TaskEntity
{
Id = taskId, ListId = listId, Title = title, Status = status,
CreatedAt = DateTime.UtcNow, SessionSkills = sessionSkillsJson,
CreatedAt = DateTime.UtcNow, SessionSkills = sessionSkillsJson, Description = description,
});
_seededTaskIds.Add(taskId); // a fresh-task ConPTY spec may write a real brief.md under
// ~/.todo-app/task-sessions/<taskId> -- clean it up on dispose
@@ -562,6 +562,82 @@ public sealed class InteractiveLaunchSpecServiceTests : IDisposable
Assert.Contains(t2, brief);
}
[Fact]
public async Task BuildForMergeHelperAsync_BriefIncludesTaskDescription()
{
var repo = Path.Combine(_tempDir, "repoDesc");
Directory.CreateDirectory(repo);
var listId = await SeedListAsync(workingDir: repo, name: "Alpha");
var t1 = Guid.NewGuid().ToString();
await SeedTaskAsync(t1, listId, TaskStatus.Idle, title: "First task",
description: "Do the thing carefully and report back.");
var svc = BuildService();
var spec = await svc.BuildForMergeHelperAsync(new[] { t1 }, listId, CancellationToken.None);
var sessionDir = TrackSessionDir(spec);
var brief = File.ReadAllText(Path.Combine(sessionDir, "brief.md"));
Assert.Contains("Do the thing carefully and report back.", brief);
}
[Fact]
public async Task BuildForMergeHelperAsync_TaskWithoutDescription_RendersCleanly()
{
var repo = Path.Combine(_tempDir, "repoNoDesc");
Directory.CreateDirectory(repo);
var listId = await SeedListAsync(workingDir: repo, name: "Alpha");
var t1 = Guid.NewGuid().ToString();
await SeedTaskAsync(t1, listId, TaskStatus.Idle, title: "No description task", description: null);
var svc = BuildService();
var spec = await svc.BuildForMergeHelperAsync(new[] { t1 }, listId, CancellationToken.None);
var sessionDir = TrackSessionDir(spec);
var brief = File.ReadAllText(Path.Combine(sessionDir, "brief.md"));
var line = brief.Split('\n').Single(l => l.Contains("No description task"));
Assert.Equal($"- [Idle] No description task (id: {t1})", line.TrimEnd('\r'));
}
[Fact]
public async Task BuildForMergeHelperAsync_BriefDescriptionWithCodeFenceAndHeadingsKeepsTaskListRecognizable()
{
var repo = Path.Combine(_tempDir, "repoMd");
Directory.CreateDirectory(repo);
var listId = await SeedListAsync(workingDir: repo, name: "Alpha");
var t1 = Guid.NewGuid().ToString();
var t2 = Guid.NewGuid().ToString();
var trickyDescription = """
# Heading inside description
- a nested list item
- another one
```csharp
var x = "fenced code block";
```
""";
await SeedTaskAsync(t1, listId, TaskStatus.Idle, title: "First task", description: trickyDescription);
await SeedTaskAsync(t2, listId, TaskStatus.WaitingForReview, title: "Second task", description: "plain description");
var svc = BuildService();
var spec = await svc.BuildForMergeHelperAsync(new[] { t1, t2 }, listId, CancellationToken.None);
var sessionDir = TrackSessionDir(spec);
var brief = File.ReadAllText(Path.Combine(sessionDir, "brief.md"));
var lines = brief.Replace("\r\n", "\n").Split('\n');
// The two task bullets must still be recognizable top-level list items, unbroken
// by the embedded heading/list/code-fence in the first task's description.
Assert.Contains(lines, l => l == $"- [Idle] First task (id: {t1})");
Assert.Contains(lines, l => l == $"- [WaitingForReview] Second task (id: {t2})");
Assert.Contains("Heading inside description", brief);
Assert.Contains("fenced code block", brief);
Assert.Contains("var x = \"fenced code block\";", brief);
}
// ── CreateMergeHelperTaskAsync ──
[Fact]