Merge branch 'main' into feat/poweruse-list-handler
Kollision mit #264 (Handoff-Budget im Brief sichtbar machen): beide Seiten haben HandoffRoundTracker, HandoffMcpTools und InteractiveLaunchSpecService angefasst. Der Konflikt war inhaltlich, nicht nur textuell. #264 liest den Cap an zwei Stellen aus der Konstante (GetStatus und das roundInfo-Rendering), waehrend dieser Branch ihn zum Parameter aus app_settings gemacht hat. Ein reiner Text-Merge haette kompiliert und trotzdem gelogen: Register haette den konfigurierten Cap durchgesetzt, waehrend der Brief dem Modell weiter "2 Runden uebrig" gemeldet haette, obwohl es 39 hat. Aufgeloest so, dass der Cap eine einzige Quelle hat: - GetStatus(taskId, maxHandoffs) nimmt den Cap als Parameter, mit demselben Clamp wie Register. Die Rechnerei liegt damit an einer Stelle. - GetHandoffStatus liest das Setting und gibt es weiter. - Das roundInfo-Rendering benutzt GetStatus statt eigener Arithmetik. Zwei Tests nageln genau diesen Drift fest, damit er beim naechsten Merge nicht unbemerkt zurueckkommt: einer auf GetHandoffStatus, einer auf den Brief. MaxHandoffs -> DefaultMaxHandoffs in #264s vier Test-Referenzen; die laufen alle mit Default-Settings, die Semantik bleibt.
This commit is contained in:
+27
@@ -13,6 +13,8 @@ namespace ClaudeDo.Worker.External;
|
||||
// reflects the effective (post-coercion) value in that case.
|
||||
public sealed record HandoffListHandlerResult(bool Requested, string TaskId, int Number, int SurvivingCount, string NextPhase, bool Coerced = false);
|
||||
|
||||
public sealed record HandoffStatusResult(string TaskId, int Number, int Round, int Remaining, bool Final);
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class HandoffMcpTools
|
||||
{
|
||||
@@ -78,4 +80,29 @@ public sealed class HandoffMcpTools
|
||||
await _broadcaster.HandoffRequested(taskId, survivingTaskIds, round.EffectivePhase);
|
||||
return new HandoffListHandlerResult(true, taskId, task.Number, survivingTaskIds.Count, round.EffectivePhase, round.Coerced);
|
||||
}
|
||||
|
||||
[McpServerTool, Description(
|
||||
"Read-only lookup of a handler task's handoff-round budget (round already used, rounds " +
|
||||
"remaining before handoff_list_handler starts coercing to a _final phase, and whether the " +
|
||||
"chain is already sealed by a completed merge_final round) -- for checking the budget mid-" +
|
||||
"session or from outside a handoff, instead of only seeing it once at the start of a round. " +
|
||||
"A task that never called handoff_list_handler reports round 0, its full remaining budget, " +
|
||||
"and final=false. In-memory only, same as the tracker itself: a worker restart resets it." +
|
||||
McpToolDocs.TaskNumberHint)]
|
||||
public async Task<HandoffStatusResult> GetHandoffStatus(
|
||||
[Description("The handler task's own id.")] string taskId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
taskId = await TaskIdResolver.ResolveAsync(_tasks, taskId, cancellationToken);
|
||||
var task = await _tasks.GetByIdAsync(taskId, cancellationToken)
|
||||
?? throw new InvalidOperationException($"Task {taskId} not found.");
|
||||
|
||||
// Same setting HandoffListHandler enforces against — read here too, so a raised cap shows up
|
||||
// in the reported budget instead of the tool confidently understating it.
|
||||
await using var ctx = await _dbFactory.CreateDbContextAsync(cancellationToken);
|
||||
var maxHandoffs = (await new AppSettingsRepository(ctx).GetAsync(cancellationToken)).ListHandlerMaxHandoffs;
|
||||
|
||||
var status = _rounds.GetStatus(taskId, maxHandoffs);
|
||||
return new HandoffStatusResult(taskId, task.Number, status.Round, status.Remaining, status.Final);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user