Files
ClawdDotNet/src/ClawdDotNet.Core/Tasks/ITaskRepository.cs
T
RichardandClaude Opus 5.5 67649559f5 Grossaufgaben und Sonderbudget (#717, Stufe 2+3)
Eine Aufgabe, deren eigene Schaetzung (gemessen, Geschwister oder Autor)
ueber der Haelfte der Tageskostengrenze liegt, bekommt zuerst einen
Planungslauf: teilen (Teile unter der Elternaufgabe) oder Sonderbudget
beantragen. Danach wartet sie auf ihre Teile bzw. die Freigabe und laeuft
einmal zum Zusammenfuehren.

Sonderbudget ueber Escalation.request_budget, ausnahmslos freigabepflichtig
(auch gegen Werkzeugkonfiguration und Dauerfreigabe). Laeufe im Baum ziehen
den Topf statt der Tagesgrenzen, tragen BudgetPot in Verbrauch und Beleg und
sind in der Kostenanalyse (nach Budget) und auf der Aufgabenkarte gesondert
sichtbar. Aufgebraucht zaehlen sie wieder gegen den Tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:47:41 +02:00

125 lines
6.2 KiB
C#

namespace ClawdDotNet.Core.Tasks;
/// <summary>
/// Der Ausführungszustand des Taskboards. Die Definition der Aufgaben lebt in
/// Markdown-Dateien; dieses Repository ist die DB-Seite, die das Claiming atomar macht
/// (was ein Dateisystem nicht verlässlich kann) und dem Scanner erlaubt, ohne
/// Dateizugriff zu entscheiden.
/// </summary>
public interface ITaskRepository
{
/// <summary>
/// Legt eine Aufgabe an oder aktualisiert ihre Definition (Importer). Idempotent über
/// die <see cref="TaskItem.Id"/> — ein zweiter Import erzeugt keine Dublette. Der
/// Ausführungszustand (Marker, Claim) bleibt dabei unangetastet.
/// </summary>
Task<TaskItem> UpsertAsync(TaskItem task, CancellationToken ct);
Task<TaskItem?> GetAsync(string id, CancellationToken ct);
Task<IReadOnlyList<TaskItem>> ListAsync(TaskQuery query, CancellationToken ct);
/// <summary>
/// #682: Every task in status <c>todo</c> — the scanner's candidates, without a cap.
///
/// <para><see cref="ListAsync"/> clamps to 500 because it serves views and tools. The
/// scanner used it too, so beyond 500 tasks schedules silently fell out of the tick.
/// Only <c>todo</c> can be claimed, so this list is bounded by the work that is
/// actually waiting, not by the size of the board.</para>
/// </summary>
Task<IReadOnlyList<TaskItem>> ListRunnableAsync(CancellationToken ct);
/// <summary>
/// Every task, without a cap — for the few callers that must see the whole board: the
/// cost forecast, duplicate detection, the import's orphan sweep. Before #716 they used
/// <see cref="ListAsync"/> with its limit of 500 and silently saw only part of it.
/// </summary>
Task<IReadOnlyList<TaskItem>> ListAllAsync(bool includeArchived, CancellationToken ct);
/// <summary>
/// Beansprucht einen fälligen Termin atomar. Genau ein gleichzeitiger Aufruf gewinnt;
/// jeder weitere erhält <c>false</c>. Setzt den Marker (<paramref name="occurrenceKey"/>)
/// sofort — ein Termin ist damit auch dann verbraucht, wenn der Lauf später scheitert
/// oder der Prozess abstürzt (at-most-once, kein Retry-Sturm).
/// </summary>
/// <param name="occurrenceKey">Sortierbarer ISO-UTC-Zeitstempel des Termins.</param>
/// <param name="leaseCutoff">
/// Claims, die älter sind, gelten als verwaist (abgestürzter Lauf) und dürfen
/// überschrieben werden.
/// </param>
Task<bool> TryClaimAsync(
string id, string occurrenceKey, string claimToken,
DateTime now, DateTime leaseCutoff, CancellationToken ct);
/// <summary>
/// Schließt einen beanspruchten Lauf ab und setzt den Endstatus. Nur wirksam, solange
/// der Aufrufer den Claim noch hält (<paramref name="claimToken"/> passt) — ein Lauf,
/// der seine Lease verloren hat, überschreibt nichts mehr. Gibt zurück, ob der Claim
/// noch gehörte.
/// </summary>
Task<bool> CompleteClaimAsync(
string id, string claimToken, TaskItemStatus finalStatus,
DateTime now, CancellationToken ct);
/// <summary>
/// Gibt einen Claim zurück, als hätte es ihn nicht gegeben: Status <c>todo</c> und der
/// Marker auf <paramref name="previousOccurrence"/> (#643). Für Läufe, die gar nicht
/// stattfanden. Nur wirksam, solange der Aufrufer den Claim hält.
/// </summary>
Task<bool> ReleaseClaimAsync(
string id, string claimToken, string? previousOccurrence, DateTime now, CancellationToken ct);
/// <summary>Ändert den Status direkt (Tool-Aktionen, Auto-Dispatch, Eskalation).</summary>
Task<bool> SetStatusAsync(string id, TaskItemStatus status, DateTime now, CancellationToken ct);
/// <summary>
/// #716: The budget refused a run of a one-time task. Releases the claim, restores the
/// occurrence (the task is still due) and defers it to <paramref name="deferredUntil"/>.
/// </summary>
Task<bool> CarryOverAsync(
string id, string claimToken, string? previousOccurrence, DateTime deferredUntil,
DateTime now, CancellationToken ct);
/// <summary>
/// #716: The budget refused a run of a recurring task. Releases the claim back to
/// <c>todo</c>; the occurrence stays consumed. With <paramref name="catchUpUntil"/> a
/// single catch-up run is scheduled for then — an already pending one is kept.
/// </summary>
Task<bool> RecordBudgetMissAsync(
string id, string claimToken, DateTime? catchUpUntil, DateTime now, CancellationToken ct);
/// <summary>
/// #716: A run took place — clears the miss counter, a pending catch-up and the
/// deferral. <see cref="TaskItem.LastBudgetMissAt"/> stays as history.
/// </summary>
Task<bool> ClearBudgetMissAsync(string id, DateTime now, CancellationToken ct);
/// <summary>
/// #717: Records that a human was asked about fill work that found no room before its
/// deadline. Returns <c>false</c> if that had already happened — asked once.
/// </summary>
Task<bool> MarkFillAlertedAsync(string id, DateTime now, CancellationToken ct);
/// <summary>#717: Records that a large task had its planning run.</summary>
Task<bool> MarkLargePlannedAsync(string id, DateTime now, CancellationToken ct);
/// <summary>
/// Reconciliation beim Start: verwaiste Claims (älter als <paramref name="leaseCutoff"/>)
/// lösen und die betroffenen Aufgaben von <see cref="TaskItemStatus.InProgress"/> zurück
/// auf <see cref="TaskItemStatus.Todo"/> stellen. Gibt die Zahl der zurückgesetzten
/// Aufgaben zurück.
/// </summary>
Task<int> ReleaseStaleClaimsAsync(DateTime leaseCutoff, DateTime now, CancellationToken ct);
/// <summary>
/// Aufgaben, die auf <paramref name="blockerId"/> warten — Grundlage für den
/// Auto-Dispatch, wenn der letzte Blocker fertig wird.
/// </summary>
Task<IReadOnlyList<TaskItem>> ListBlockedByAsync(string blockerId, CancellationToken ct);
/// <summary>#717: The tasks directly below a task in the goal chain (#714), archived ones included.</summary>
Task<IReadOnlyList<TaskItem>> ListChildrenAsync(string parentId, CancellationToken ct);
Task<int> CountAsync(CancellationToken ct);
}